From 039b0a256a764118b40b895a3fb317a884323fe5 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 21 Jun 2016 15:31:46 +0800 Subject: [PATCH 01/94] Update config.guess/.sub to support Android standalone toolchains. --- config.guess | 577 ++++++++++++++++++++++++++------------------------- config.sub | 391 +++++++++++++++++++++++----------- 2 files changed, 569 insertions(+), 399 deletions(-) diff --git a/config.guess b/config.guess index 34093cc6bb..b79252d6b1 100644 --- a/config.guess +++ b/config.guess @@ -1,14 +1,12 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# Copyright 1992-2013 Free Software Foundation, Inc. -timestamp='2007-07-22' +timestamp='2013-06-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -17,26 +15,22 @@ timestamp='2007-07-22' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner . -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner. # -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + me=`echo "$0" | sed -e 's,.*/,,'` @@ -56,8 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -139,29 +132,33 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -if [ "${UNAME_SYSTEM}" = "Linux" ] ; then +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + eval $set_cc_for_build - cat << EOF > $dummy.c + cat <<-EOF > $dummy.c #include - #ifdef __UCLIBC__ - # ifdef __UCLIBC_CONFIG_VERSION__ - LIBC=uclibc __UCLIBC_CONFIG_VERSION__ - # else + #if defined(__UCLIBC__) LIBC=uclibc - # endif + #elif defined(__dietlibc__) + LIBC=dietlibc #else LIBC=gnu #endif -EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep LIBC= | sed -e 's: ::g'` -fi + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + ;; +esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward @@ -187,7 +184,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep __ELF__ >/dev/null + | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? @@ -197,7 +194,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release @@ -218,6 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} @@ -240,7 +241,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on @@ -286,7 +287,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead @@ -312,12 +316,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo s390-ibm-zvmoe exit ;; *:OS400:*:*) - echo powerpc-ibm-os400 + echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) + arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) @@ -341,14 +345,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize @@ -392,23 +415,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; @@ -478,8 +501,8 @@ EOF echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ @@ -492,7 +515,7 @@ EOF else echo i586-dg-dgux${UNAME_RELEASE} fi - exit ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; @@ -549,7 +572,7 @@ EOF echo rs6000-ibm-aix3.2 fi exit ;; - *:AIX:*:[45]) + *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 @@ -592,52 +615,52 @@ EOF 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + sed 's/^ //' << EOF >$dummy.c - #define _HPUX_SOURCE - #include - #include + #define _HPUX_SOURCE + #include + #include - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa @@ -657,7 +680,7 @@ EOF # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null + grep -q __LP64__ then HP_ARCH="hppa2.0w" else @@ -728,22 +751,22 @@ EOF exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; @@ -767,14 +790,14 @@ EOF exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} @@ -786,40 +809,51 @@ EOF echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; - *:Interix*:[3456]*) - case ${UNAME_MACHINE} in + *:Interix*:*) + case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; - EM64T | authenticamd) + authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we @@ -840,29 +874,72 @@ EOF exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; - arm*:Linux:*:*) + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) - echo cris-axis-linux-${LIBC} + echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) - echo crisv32-axis-linux-${LIBC} + echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) - echo frv-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -873,74 +950,36 @@ EOF m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - mips:Linux:*:*) + mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU - #undef mips - #undef mipsel + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel + CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips + CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; - mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips64 - #undef mips64el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mips64el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips64 - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } - ;; - or32:Linux:*:*) - echo or32-unknown-linux-${LIBC} + or1k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level @@ -950,14 +989,23 @@ EOF *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -965,80 +1013,18 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - xtensa:Linux:*:*) - echo xtensa-unknown-linux-${LIBC} + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-${LIBC}" - ;; - a.out-i386-linux) - echo "${UNAME_MACHINE}-pc-linux-${LIBC}aout" - exit ;; - coff-i386) - echo "${UNAME_MACHINE}-pc-linux-${LIBC}coff" - exit ;; - "") - # Either a pre-BFD a.out linker (linux-gnuoldld) or - # one that does not give us useful --help. - echo "${UNAME_MACHINE}-pc-linux-${LIBC}oldld" - exit ;; - esac - # This should get integrated into the C code below, but now we hack - if [ "$LIBC" != "gnu" ] ; then echo "$TENTATIVE" && exit 0 ; fi - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 - LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } - ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both @@ -1046,11 +1032,11 @@ EOF echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) @@ -1067,7 +1053,7 @@ EOF i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) @@ -1082,7 +1068,7 @@ EOF fi exit ;; i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; @@ -1110,10 +1096,13 @@ EOF exit ;; pc:*:*:*) # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit ;; + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; @@ -1148,8 +1137,18 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; @@ -1162,7 +1161,7 @@ EOF rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) @@ -1182,10 +1181,10 @@ EOF echo ns32k-sni-sysv fi exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm @@ -1211,11 +1210,11 @@ EOF exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; @@ -1225,6 +1224,12 @@ EOF BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; @@ -1251,9 +1256,21 @@ EOF exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) @@ -1267,7 +1284,10 @@ EOF *:QNX:*:4*) echo i386-pc-qnx exit ;; - NSE-?:NONSTOP_KERNEL:*:*) + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) @@ -1312,13 +1332,13 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; @@ -1333,11 +1353,14 @@ EOF i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; esac -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - eval $set_cc_for_build cat >$dummy.c < printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 - "4" + "4" #else - "" + "" #endif - ); exit (0); + ); exit (0); #endif #endif @@ -1493,9 +1516,9 @@ This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD and - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD If the version you run ($0) is already up to date, please send the following data and any information you think might be diff --git a/config.sub b/config.sub index 63cdd0a35d..9633db7046 100644 --- a/config.sub +++ b/config.sub @@ -1,44 +1,40 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# Copyright 1992-2013 Free Software Foundation, Inc. -timestamp='2007-06-28' +timestamp='2013-08-10' -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. +# Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. @@ -72,8 +68,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -120,12 +115,18 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] @@ -148,10 +149,13 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray) + -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; + -bluegene*) + os=-cnk + ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 @@ -166,10 +170,10 @@ case $os in os=-chorusos basic_machine=$1 ;; - -chorusrdb) - os=-chorusrdb + -chorusrdb) + os=-chorusrdb basic_machine=$1 - ;; + ;; -hiux*) os=-hiuxwe2 ;; @@ -214,6 +218,12 @@ case $os in -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; -lynx*) os=-lynxos ;; @@ -238,24 +248,34 @@ case $basic_machine in # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ + | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ | bfin \ - | c4x | clipper \ - | d10v | d30v | dlx | dsp16xx | dvp \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ - | mips64vr | mips64vrel \ + | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ @@ -266,31 +286,45 @@ case $basic_machine in | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ + | moxie \ | mt \ | msp430 \ - | nios | nios2 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | or32 \ + | open8 \ + | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]a*eb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ - | z8k) + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) basic_machine=$basic_machine-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; @@ -300,6 +334,21 @@ case $basic_machine in basic_machine=mt-unknown ;; + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. @@ -314,29 +363,37 @@ case $basic_machine in # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ + | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | be32-* | be64-* \ | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ - | clipper-* | craynv-* | cydra-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ - | mips64vr-* | mips64vrel-* \ + | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ @@ -347,31 +404,41 @@ case $basic_machine in | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ - | nios-* | nios2-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ - | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]a*eb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ | tron-* \ - | v850-* | v850e-* | vax-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ | ymp-* \ - | z8k-*) + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. @@ -389,7 +456,7 @@ case $basic_machine in basic_machine=a29k-amd os=-udi ;; - abacus) + abacus) basic_machine=abacus-unknown ;; adobe68k) @@ -435,6 +502,10 @@ case $basic_machine in basic_machine=m68k-apollo os=-bsd ;; + aros) + basic_machine=i386-pc + os=-aros + ;; aux) basic_machine=m68k-apple os=-aux @@ -443,10 +514,35 @@ case $basic_machine in basic_machine=ns32k-sequent os=-dynix ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; c90) basic_machine=c90-cray os=-unicos ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; convex-c1) basic_machine=c1-convex os=-bsd @@ -475,7 +571,7 @@ case $basic_machine in basic_machine=craynv-cray os=-unicosmp ;; - cr16) + cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; @@ -514,6 +610,10 @@ case $basic_machine in basic_machine=m88k-motorola os=-sysv3 ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp @@ -629,7 +729,6 @@ case $basic_machine in i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -668,6 +767,14 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; m88k-omron*) basic_machine=m88k-omron ;; @@ -679,8 +786,15 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; mingw32) - basic_machine=i386-pc + basic_machine=i686-pc os=-mingw32 ;; mingw32ce) @@ -694,24 +808,6 @@ case $basic_machine in basic_machine=m68k-atari os=-mint ;; - mipsEE* | ee | ps2) - basic_machine=mips64r5900el-scei - case $os in - -linux*) - ;; - *) - os=-elf - ;; - esac - ;; - iop) - basic_machine=mipsel-scei - os=-irx - ;; - dvp) - basic_machine=dvp-scei - os=-elf - ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; @@ -733,10 +829,18 @@ case $basic_machine in ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; + msys) + basic_machine=i686-pc + os=-msys + ;; mvs) basic_machine=i370-ibm os=-mvs ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -801,6 +905,12 @@ case $basic_machine in np1) basic_machine=np1-gould ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -831,6 +941,14 @@ case $basic_machine in basic_machine=i860-intel os=-osf ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; pbd) basic_machine=sparc-tti ;; @@ -875,9 +993,10 @@ case $basic_machine in ;; power) basic_machine=power-ibm ;; - ppc) basic_machine=powerpc-unknown + ppc | ppcbe) basic_machine=powerpc-unknown ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown @@ -902,7 +1021,11 @@ case $basic_machine in basic_machine=i586-unknown os=-pw32 ;; - rdos) + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) basic_machine=i386-pc os=-rdos ;; @@ -971,6 +1094,9 @@ case $basic_machine in basic_machine=i860-stratus os=-sysv4 ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; sun2) basic_machine=m68000-sun ;; @@ -1027,17 +1153,9 @@ case $basic_machine in basic_machine=t90-cray os=-unicos ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown @@ -1106,6 +1224,9 @@ case $basic_machine in xps | xps100) basic_machine=xps100-honeywell ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; ymp) basic_machine=ymp-cray os=-unicos @@ -1114,6 +1235,10 @@ case $basic_machine in basic_machine=z8k-unknown os=-sim ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; none) basic_machine=none-none os=-none @@ -1152,7 +1277,7 @@ case $basic_machine in we32k) basic_machine=we32k-att ;; - sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) @@ -1199,9 +1324,12 @@ esac if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # First match some system type aliases + # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; @@ -1222,21 +1350,23 @@ case $os in # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ + | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ @@ -1244,7 +1374,7 @@ case $os in | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -irx*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1283,7 +1413,7 @@ case $os in -opened*) os=-openedition ;; - -os400*) + -os400*) os=-os400 ;; -wince*) @@ -1332,7 +1462,7 @@ case $os in -sinix*) os=-sysv4 ;; - -tpf*) + -tpf*) os=-tpf ;; -triton*) @@ -1368,12 +1498,14 @@ case $os in -aros*) os=-aros ;; - -kaos*) - os=-kaos - ;; -zvmoe) os=-zvmoe ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; -none) ;; *) @@ -1396,10 +1528,10 @@ else # system, and we'll never get to this point. case $basic_machine in - score-*) + score-*) os=-elf ;; - spu-*) + spu-*) os=-elf ;; *-acorn) @@ -1411,8 +1543,23 @@ case $basic_machine in arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1432,14 +1579,11 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout ;; - mep-*) + mep-*) os=-elf ;; mips*-cisco) @@ -1448,6 +1592,9 @@ case $basic_machine in mips*-*) os=-elf ;; + or1k-*) + os=-elf + ;; or32-*) os=-coff ;; @@ -1466,7 +1613,7 @@ case $basic_machine in *-ibm) os=-aix ;; - *-knuth) + *-knuth) os=-mmixware ;; *-wec) @@ -1571,7 +1718,7 @@ case $basic_machine in -sunos*) vendor=sun ;; - -aix*) + -cnk*|-aix*) vendor=ibm ;; -beos*) From 03219240348cac0ac37f9b3f9bfdbecadfdc79e6 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 21 Jun 2016 15:41:41 +0800 Subject: [PATCH 02/94] Workaround Android pread64/pwrite64 support. Bionic treats off_t and pread/pwrite as 32-bit version even with -D_FILE_OFFSET_BITS=64 --- src/os_unix.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/os_unix.c b/src/os_unix.c index fe1fc6af19..0721eaafe7 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -392,7 +392,11 @@ static struct unix_syscall { #else { "pread64", (sqlite3_syscall_ptr)0, 0 }, #endif +#if defined(__ANDROID__) +#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) +#else #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) +#endif { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) @@ -410,8 +414,13 @@ static struct unix_syscall { #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif +#if defined(__ANDROID__) +#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ + aSyscall[13].pCurrent) +#else #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[13].pCurrent) +#endif { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) From a619be9a9c3741ce9ee258d3f1b9a01c8ea89d80 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 22 Jun 2016 01:15:32 +0800 Subject: [PATCH 03/94] Add readme for WeChat. --- README-WeChat.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 README-WeChat.md diff --git a/README-WeChat.md b/README-WeChat.md new file mode 100644 index 0000000000..d4a69cf9e7 --- /dev/null +++ b/README-WeChat.md @@ -0,0 +1,40 @@ +## WeChat (MMDB) Specific Configurations + +For compatibility reasons, WeChat uses SQLCipher 1.x format. + + * KDF Iterations set to 4000; + * Do NOT use HMAC. + +WeChat specific configurations: + + * Custom FTS3 tokenizer registeration must be enabled. + +Additional configurations for Android environment: + + * Optimize for size rather than speed; (-Os) + * Thread-safe mode set to multi-threaded; + * Use pread64/pwrite64 for disk I/O; + * Other options from official Android source. + +## How to Build SQLCipher for MMDB + +```shell +CFLAGS='-I/path/to/openssl/include -Os \ +-DPBKDF2_ITER=4000 \ +-DDEFAULT_CIPHER_FLAGS=CIPHER_FLAG_LE_PGNO \ +-DUSE_PREAD64=1 \ +-DSQLITE_ENABLE_FTS3_TOKENIZER \ +-DSQLITE_HAS_CODEC \ +-DSQLITE_HAVE_ISNAN \ +-DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ +-DSQLITE_THREADSAFE=2 \ +-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ +-DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ +-DSQLITE_ENABLE_UNLOCK_NOTIFY' +LDFLAGS='-L/path/to/openssl/lib' + +./configure --host=arm-linux-androideabi --prefix='/path/to/install' --disable-shared \ + --enable-fts3 --enable-fts4 --enable-fts5 --enable-tempstore=always +make -j4 +make install +``` \ No newline at end of file From 1f0950917a0301b7957e7f95a83e5d9415eafa7e Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 28 Jun 2016 18:20:02 +0800 Subject: [PATCH 04/94] Fix makefile on MinGW/Cygwin environment. --- Makefile.in | 4 ++-- aclocal.m4 | 6 +++++- config.h.in | 3 +++ configure | 9 +++++++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Makefile.in b/Makefile.in index 31f039f475..372cc9be56 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1055,10 +1055,10 @@ FTS5_SRC = \ $(TOP)/ext/fts5/fts5_varint.c \ $(TOP)/ext/fts5/fts5_vocab.c \ -fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon +fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE) cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h - ./lemon $(OPTS) fts5parse.y + ./lemon$(BEXE) $(OPTS) fts5parse.y fts5parse.h: fts5parse.c diff --git a/aclocal.m4 b/aclocal.m4 index c4c8a2bc00..7bc688e947 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -8529,7 +8529,11 @@ AC_ARG_ENABLE([shared], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; - no) enable_shared=no ;; + no) + enable_shared=no + AC_DEFINE([LT_MINGW_STATIC_TESTSUITE_HACK], [1], + [Define if running the test suite so that test #27 works on MinGW.]) + ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. diff --git a/config.h.in b/config.h.in index 803c5ea81d..1cf2365304 100644 --- a/config.h.in +++ b/config.h.in @@ -96,6 +96,9 @@ /* Define to 1 if you have the `utime' function. */ #undef HAVE_UTIME +/* Define if running the test suite so that test #27 works on MinGW. */ +#undef LT_MINGW_STATIC_TESTSUITE_HACK + /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR diff --git a/configure b/configure index ec79279fdf..3d916d7a06 100755 --- a/configure +++ b/configure @@ -6954,7 +6954,12 @@ if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; - no) enable_shared=no ;; + no) + enable_shared=no + +$as_echo "#define LT_MINGW_STATIC_TESTSUITE_HACK 1" >>confdefs.h + + ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. @@ -12183,7 +12188,7 @@ fi if test "$CYGWIN" != "yes"; then case $host_os in - *cygwin* ) CYGWIN=yes;; + *cygwin* | *msys*) CYGWIN=yes;; * ) CYGWIN=no;; esac From d0330189b27a1c9ed2cad2818f608031dbf4c466 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 29 Jun 2016 01:31:31 +0800 Subject: [PATCH 05/94] Update README-WeChat --- README-WeChat.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README-WeChat.md b/README-WeChat.md index d4a69cf9e7..0f14bdaf91 100644 --- a/README-WeChat.md +++ b/README-WeChat.md @@ -11,7 +11,8 @@ WeChat specific configurations: Additional configurations for Android environment: - * Optimize for size rather than speed; (-Os) + * Optimize for size rather than speed; (`-Os`) + * PIE (position independent executable) must be enabled for Android >= 5.0; (`-fPIE -pie`) * Thread-safe mode set to multi-threaded; * Use pread64/pwrite64 for disk I/O; * Other options from official Android source. @@ -19,7 +20,7 @@ Additional configurations for Android environment: ## How to Build SQLCipher for MMDB ```shell -CFLAGS='-I/path/to/openssl/include -Os \ +$ CFLAGS='-I/path/to/openssl/include -Os -fPIC -fPIE -pie \ -DPBKDF2_ITER=4000 \ -DDEFAULT_CIPHER_FLAGS=CIPHER_FLAG_LE_PGNO \ -DUSE_PREAD64=1 \ @@ -31,10 +32,10 @@ CFLAGS='-I/path/to/openssl/include -Os \ -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ -DSQLITE_ENABLE_UNLOCK_NOTIFY' -LDFLAGS='-L/path/to/openssl/lib' +$ LDFLAGS='-L/path/to/openssl/lib -fPIE -pie' -./configure --host=arm-linux-androideabi --prefix='/path/to/install' --disable-shared \ +$ ./configure --host=arm-linux-androideabi --prefix='/path/to/install' --disable-shared \ --enable-fts3 --enable-fts4 --enable-fts5 --enable-tempstore=always -make -j4 -make install +$ make -j4 +$ make install ``` \ No newline at end of file From 9306025952ce351807688df7360fe4b7c2bc460c Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 1 Jul 2016 02:17:37 +0800 Subject: [PATCH 06/94] Add SQLITE_THREADSAFE=2 option to configure.ac --- README-WeChat.md | 14 +++++++++----- configure | 8 ++++++-- configure.ac | 5 ++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/README-WeChat.md b/README-WeChat.md index 0f14bdaf91..3ad7f8fcd0 100644 --- a/README-WeChat.md +++ b/README-WeChat.md @@ -11,16 +11,20 @@ WeChat specific configurations: Additional configurations for Android environment: + * Generate Thumb code rather than ARM; (`-mthumb`) * Optimize for size rather than speed; (`-Os`) + * PIC must be enabled; (`-fPIC`) * PIE (position independent executable) must be enabled for Android >= 5.0; (`-fPIE -pie`) * Thread-safe mode set to multi-threaded; * Use pread64/pwrite64 for disk I/O; - * Other options from official Android source. + * Other options from official Android source; + * **For armeabi-v7a targets**, generate Thumb-2 code. (`-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3`) ## How to Build SQLCipher for MMDB ```shell -$ CFLAGS='-I/path/to/openssl/include -Os -fPIC -fPIE -pie \ +$ CFLAGS='-I/path/to/openssl/include -Os -mthumb \ +-fPIC -fPIE -pie \ -DPBKDF2_ITER=4000 \ -DDEFAULT_CIPHER_FLAGS=CIPHER_FLAG_LE_PGNO \ -DUSE_PREAD64=1 \ @@ -28,14 +32,14 @@ $ CFLAGS='-I/path/to/openssl/include -Os -fPIC -fPIE -pie \ -DSQLITE_HAS_CODEC \ -DSQLITE_HAVE_ISNAN \ -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ --DSQLITE_THREADSAFE=2 \ -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ -DSQLITE_ENABLE_UNLOCK_NOTIFY' $ LDFLAGS='-L/path/to/openssl/lib -fPIE -pie' -$ ./configure --host=arm-linux-androideabi --prefix='/path/to/install' --disable-shared \ - --enable-fts3 --enable-fts4 --enable-fts5 --enable-tempstore=always +$ ./configure --host=arm-linux-androideabi --prefix='/path/to/install' \ + --disable-shared --enable-fts3 --enable-fts4 --enable-tempstore=always \ + --enable-threadsafe=multi $ make -j4 $ make install ``` \ No newline at end of file diff --git a/configure b/configure index 3d916d7a06..6908feaf29 100755 --- a/configure +++ b/configure @@ -11829,10 +11829,14 @@ if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } +elif test "$enable_threadsafe" = "multi"; then + SQLITE_THREADSAFE=2 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: multi-threaded" >&5 +$as_echo "multi-threaded" >&6; } else SQLITE_THREADSAFE=1 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: serialized" >&5 +$as_echo "serialized" >&6; } fi diff --git a/configure.ac b/configure.ac index 9a1fe1a415..65ddf7cbad 100644 --- a/configure.ac +++ b/configure.ac @@ -186,9 +186,12 @@ AC_MSG_CHECKING([whether to support threadsafe operation]) if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 AC_MSG_RESULT([no]) +elif test "$enable_threadsafe" = "multi"; then + SQLITE_THREADSAFE=2 + AC_MSG_RESULT([multi-threaded]) else SQLITE_THREADSAFE=1 - AC_MSG_RESULT([yes]) + AC_MSG_RESULT([serialized]) fi AC_SUBST(SQLITE_THREADSAFE) From 19977a8d82b05819cde2d7a2cd491b96359ec4ac Mon Sep 17 00:00:00 2001 From: John_He Date: Mon, 1 Aug 2016 03:27:55 +0800 Subject: [PATCH 07/94] Add FTS5 generated files to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f68644eb92..7ecdac7960 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,7 @@ xcuserdata/* /sqlcipher.pc /sqlite3ext.h /libsqlcipher.la +/fts5.c +/fts5.h +/fts5parse.* /.DS_Store From 50e896c75ff7ba77b397132d0d2de240f966238a Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 5 Aug 2016 23:11:59 +0800 Subject: [PATCH 08/94] Fix not included in amalgamation with -DOMIT_MEMLOCK decleared --- src/crypto_impl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 5a45454ddf..a8de5cdfcf 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -35,13 +35,11 @@ #include "btreeInt.h" #include "sqlcipher.h" #include "crypto.h" -#ifndef OMIT_MEMLOCK #if defined(__unix__) || defined(__APPLE__) || defined(_AIX) #include #elif defined(_WIN32) # include #endif -#endif /* the default implementation of SQLCipher uses a cipher_ctx to keep track of read / write state separately. The following From dfae464a1c3ccfae09a706d476f1b34dbd10bd3a Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 5 Aug 2016 23:12:47 +0800 Subject: [PATCH 09/94] Update README --- README-WeChat.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README-WeChat.md b/README-WeChat.md index 3ad7f8fcd0..72185ddb04 100644 --- a/README-WeChat.md +++ b/README-WeChat.md @@ -15,6 +15,7 @@ Additional configurations for Android environment: * Optimize for size rather than speed; (`-Os`) * PIC must be enabled; (`-fPIC`) * PIE (position independent executable) must be enabled for Android >= 5.0; (`-fPIE -pie`) + * Omit memory lock in SQLCipher, which will cause problems with some drivers; (`-DOMIT_MEMLOCK`) * Thread-safe mode set to multi-threaded; * Use pread64/pwrite64 for disk I/O; * Other options from official Android source; @@ -30,7 +31,7 @@ $ CFLAGS='-I/path/to/openssl/include -Os -mthumb \ -DUSE_PREAD64=1 \ -DSQLITE_ENABLE_FTS3_TOKENIZER \ -DSQLITE_HAS_CODEC \ --DSQLITE_HAVE_ISNAN \ +-DOMIT_MEMLOCK \ -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ From 8f81c17f2d630e469fe3f8a9ad2888840b63874a Mon Sep 17 00:00:00 2001 From: johnwhe Date: Mon, 26 Sep 2016 00:48:23 +0800 Subject: [PATCH 10/94] Add OMIT_CONSTTIME_MEM option to switch between constant-time memory operations or generic optimized ones. --- src/crypto_impl.c | 80 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index a8de5cdfcf..0de98d035d 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -165,43 +165,93 @@ void sqlcipher_deactivate() { Note: As suggested by Joachim Schipper (joachim.schipper@fox-it.com) */ void* sqlcipher_memset(void *v, unsigned char value, int len) { - int i = 0; - volatile unsigned char *a = v; - +#ifndef OMIT_CONSTTIME_MEM if (v == NULL) return v; - for(i = 0; i < len; i++) { - a[i] = value; + unsigned long val = 0; + int i; + for (i = 0; i < sizeof(unsigned long); i++) { + val = (val << 8) | (value & 0xff); + } + int len2 = len % sizeof(unsigned long); + len = len / sizeof(unsigned long); + + unsigned long *aa = (unsigned long *) v; + for (i = 0; i < len; i++) { + *aa++ = val; + } + unsigned char *a = (unsigned char *) aa; + for (i = 0; i < len; i++) { + *a++ = value; } return v; +#else + return memset(v, value, len); +#endif } /* constant time memory check tests every position of a memory segement matches a single value (i.e. the memory is all zeros) returns 0 if match, 1 of no match */ int sqlcipher_ismemset(const void *v, unsigned char value, int len) { - const unsigned char *a = v; - int i = 0, result = 0; - - for(i = 0; i < len; i++) { - result |= a[i] ^ value; + unsigned long val = 0; + int i; + for (i = 0; i < sizeof(unsigned long); i++) { + val = (val << 8) | (value & 0xff); + } + int len2 = len % sizeof(unsigned long); + len = len / sizeof(unsigned long); + +#ifndef OMIT_CONSTTIME_MEM + int result = 0; + const unsigned long *aa = (const unsigned long *) v; + for (i = 0; i < len; i++) { + result |= *aa++ ^ val; + } + const unsigned char *a = (const unsigned char *) aa; + for (i = 0; i < len2; i++) { + result |= *a++ ^ value; } return (result != 0); +#else + const unsigned long *aa = (const unsigned long *) v; + for (i = 0; i < len; i++) { + if (*aa++ != val) return 1; + } + const unsigned char *a = (const unsigned char *) aa; + for (i = 0; i < len2; i++) { + if (*a++ != value) return 1; + } + + return 0; +#endif } /* constant time memory comparison routine. returns 0 if match, 1 if no match */ int sqlcipher_memcmp(const void *v0, const void *v1, int len) { - const unsigned char *a0 = v0, *a1 = v1; - int i = 0, result = 0; - - for(i = 0; i < len; i++) { - result |= a0[i] ^ a1[i]; +#ifndef OMIT_CONSTTIME_MEM + int len2 = len % sizeof(unsigned long); + len = len / sizeof(unsigned long); + int i, result = 0; + + const unsigned long *aa0 = (const unsigned long *) v0; + const unsigned long *aa1 = (const unsigned long *) v1; + for (i = 0; i < len; i++) { + result |= *aa0++ ^ *aa1++; + } + const unsigned char *a0 = (const unsigned char *) aa0; + const unsigned char *a1 = (const unsigned char *) aa1; + for (i = 0; i < len2; i++) { + result |= *a0++ ^ *a1++; } return (result != 0); +#else + return memcmp(v0, v1, len); +#endif } /** From c81ea6283be64a1171f79bbab8d4589075b5bc72 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Mon, 26 Sep 2016 19:49:17 +0800 Subject: [PATCH 11/94] Add custom sqlcipher_provider implementation. --- src/crypto_custom.c | 343 ++++++++++++++++++++++++++++++++++++++++++++ src/crypto_impl.c | 16 +-- 2 files changed, 347 insertions(+), 12 deletions(-) create mode 100644 src/crypto_custom.c diff --git a/src/crypto_custom.c b/src/crypto_custom.c new file mode 100644 index 0000000000..d67dc614ea --- /dev/null +++ b/src/crypto_custom.c @@ -0,0 +1,343 @@ + +#ifdef SQLITE_HAS_CODEC + +#include "sqliteInt.h" +#include "sqlcipher.h" + +/* Structure to store registered custom providers, in a list */ +typedef struct sqlcipher_named_provider { + sqlcipher_provider p; + char name[0]; /* dynamic length */ +} sqlcipher_named_provider; + +/* Provider context */ +typedef struct custom_ctx { + sqlcipher_provider *p; /* Currently selected provider */ + void *p_ctx; /* Context for selected provider */ +} custom_ctx; + + +/* Custom provider list */ +static sqlcipher_named_provider **custom_providers; +static int custom_providers_count; +static int custom_providers_capacity; +static sqlite3_mutex *custom_providers_mutex; + +static sqlcipher_provider *default_provider; /* Default fallback provider, should be openssl, libtomcrypt or commoncrypto */ +static int activate_count = 0; + +static void provider_overload(sqlcipher_provider *base, sqlcipher_provider *p) { + /* sqlcipher_provider is actually a pile of function pointers, which has the same size of (void *). + We can just run a loop comparing and assigning raw pointers. */ + int n = sizeof(sqlcipher_provider) / sizeof(void *); + int i; + for (i = 0; i < n; i++) { + if ( ((void **) p)[i] == 0 ) + ((void **) p)[i] = ((void **) base)[i]; + } +} + +static int select_provider(custom_ctx *ctx, const char *name) { + int rc = SQLITE_OK; + + sqlite3_mutex_enter(custom_providers_mutex); + if (ctx->p) goto end; + + /* Select provider according to name. */ + if (name) { + int i; + for (i = 0; i < custom_providers_count; i++) { + if (strcmp(custom_providers[i].name, name) == 0) { + ctx->p = &custom_providers[i].p; + break; + } + } + } + + if (!ctx->p) + ctx->p = default_provider; + + /* Now we have chosen which provider will be used, + we can initialize the real provider context. */ + ctx->p_ctx = NULL; + rc = ctx->p->ctx_init(&ctx->p_ctx); + +end: + sqlite3_mutex_leave(custom_providers_mutex); + return rc; +} + +int sqlcipher_register_custom_provider(const char *name, sqlcipher_provider *p) { + sqlite3_mutex_enter(custom_providers_mutex); + + /* Grow custom provider list if it's full. */ + if (custom_provider_count >= custom_providers_capacity) { + /* Linear growth should be enough here as we probably don't have so much providers. */ + int new_capacity = custom_providers_capacity + 16; + void *new_list = sqlite3_realloc(custom_providers, new_capacity * sizeof(sqlcipher_named_provider *)); + if (!new_list) goto bail; + + custom_providers = (sqlcipher_named_provider **) new_list; + custom_providers_capacity = new_capacity; + } + + size_t len = strlen(name) + 1; + sqlcipher_named_provider *np = sqlite3_malloc(sizeof(sqlcipher_named_provider) + len * sizeof(char)); + if (!np) goto bail; + + /* Overload provider functions. */ + strncpy(np->name, name, len); + memcpy(&np->p, p, sizeof(sqlcipher_provider)); + provider_overload(default_provider, &np->p); + + /* Find existing provider. */ + int i; + for (i = 0; i < custom_providers_count; i++) { + if (strcmp(custom_providers[i].name, name) == 0) + break; + } + if (i < custom_providers_count) { + /* Free previous provider and replace with new one. */ + sqlite3_free(custom_providers[i]); + } else { + /* Not found, enlarge the list. */ + custom_providers_count++; + } + custom_providers[i] = np; + + sqlite3_mutex_leave(custom_providers_mutex); + return SQLITE_OK; + +bail: + sqlite3_mutex_leave(custom_providers_mutex); + return SQLITE_NOMEM; +} + +int sqlcipher_unregister_custom_provider(const char *name) { + sqlite3_mutex_enter(custom_providers_mutex); + + /* Find existing provider. */ + int i; + for (i = 0; i < custom_providers_count; i++) { + if (strcmp(custom_providers[i].name, name) == 0) + break; + } + if (i < custom_providers_count) { + /* Found, free the provider and swap it to the end of the list. */ + sqlite3_free(custom_providers[i]); + custom_providers_count--; + custom_providers[i] = custom_providers[custom_providers_count]; + } + + sqlite3_mutex_leave(custom_providers_mutex); + return SQLITE_OK; +} + +static int sqlcipher_custom_activate(void *ctx) { + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutex); + + if (!default_provider) { + default_provider = (sqlcipher_provider *) malloc(sizeof(sqlcipher_provider)); + if (!default_provider) goto bail; + +#if defined (SQLCIPHER_CRYPTO_CC) + extern int sqlcipher_cc_setup(sqlcipher_provider *p); + sqlcipher_cc_setup(default_provider); +#elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) + extern int sqlcipher_ltc_setup(sqlcipher_provider *p); + sqlcipher_ltc_setup(default_provider); +#elif defined (SQLCIPHER_CRYPTO_OPENSSL) + extern int sqlcipher_custom_setup(sqlcipher_provider *p); + sqlcipher_custom_setup(default_provider); +#else +#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED" +#endif + + custom_provider_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + } + + activate_count++; + sqlite3_mutex_leave(mutex); + return SQLITE_OK; + +bail: + sqlite3_mutex_leave(mutex); + return SQLITE_NOMEM; +} + +static int sqlcipher_custom_deactivate(void *ctx) { + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutex); + + if (--activate_count == 0) { + sqlite3_free(default_provider); + default_provider = NULL; + sqlite3_mutex_free(custom_provider_mutex); + } + + sqlite3_mutex_leave(mutex); + return SQLITE_OK; +} + +static int sqlcipher_custom_ctx_init(void **ctx) { + custom_ctx *c; + *ctx = c = sqlite3_malloc(sizeof(sizeof(custom_ctx))); + if (!c) return SQLITE_NOMEM; + + sqlcipher_custom_activate(c); + c->p = NULL; + c->p_ctx = NULL; + return SQLITE_OK; +} + +static int sqlcipher_custom_ctx_free(void **ctx) { + sqlcipher_custom_deactivate(*ctx); + sqlite3_free(*ctx); + return SQLITE_OK; +} + +static int sqlcipher_custom_ctx_copy(void *target_ctx, void *source_ctx) { + memcpy(target_ctx, source_ctx, sizeof(custom_ctx)); + return SQLITE_OK; +} + +static int sqlcipher_custom_ctx_cmp(void *c1, void *c2) { + custom_ctx *ctx1 = (custom_ctx *) c1; + custom_ctx *ctx2 = (custom_ctx *) c2; + if (ctx1->p != ctx2->p) return 0; + if (ctx1->p_ctx && ctx2->p_ctx) + return ctx1->p->ctx_cmp(ctx1->p_ctx, ctx2->p_ctx); + if (!ctx1->p_ctx && !ctx2->p_ctx) + return 1; + return 0; +} + +static const char* sqlcipher_custom_get_provider_name(void *ctx) { + return "custom"; +} + +static const char* sqlcipher_custom_get_provider_version(void *ctx) { + return "0.2.2"; +} + +static int sqlcipher_custom_set_cipher(void *ctx_, const char *cipher_name) { + custom_ctx *ctx = (custom_ctx *) ctx_; + int rc; + /* Initialize provider accroding to cipher_name. */ + if (!ctx->p && (rc = select_provider(ctx, cipher_name)) != SQLITE_OK) + return rc; + return ctx->p->set_cipher(ctx->p_ctx, cipher_name); +} + +static const char* sqlcipher_custom_get_cipher(void *ctx_) { + custom_ctx *ctx = (custom_ctx *) ctx_; + if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) + return ""; + return ctx->p->get_cipher(ctx->p_ctx); +} + +static int sqlcipher_custom_random(void *ctx_, void *buffer, int length) { + custom_ctx *ctx = (custom_ctx *) ctx_; + int rc; + if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) + return rc; + return ctx->p->random(p->p_ctx, buffer, length); +} + +static int sqlcipher_custom_add_random(void *ctx_, void *buffer, int length) { + custom_ctx *ctx = (custom_ctx *) ctx_; + int rc; + if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) + return rc; + return ctx->p->add_random(ctx->p_ctx, buffer, length); +} + +static int sqlcipher_custom_hmac(void *ctx_, unsigned char *hmac_key, int key_sz, + unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) { + custom_ctx *ctx = (custom_ctx *) ctx_; + int rc; + if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) + return rc; + return ctx->p->hmac(ctx->p_ctx, hmac_key, key_sz, in, in_sz, in2, in2_sz, out); +} + +static int sqlcipher_custom_kdf(void *ctx_, const unsigned char *pass, int pass_sz, + unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) { + custom_ctx *ctx = (custom_ctx *) ctx_; + int rc; + if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) + return rc; + return ctx->p->kdf(ctx->p_ctx, pass, pass_sz, salt, salt_sz, workfactor, key_sz, key); +} + +static int sqlcipher_custom_cipher(void *ctx_, int mode, unsigned char *key, int key_sz, + unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) { + custom_ctx *ctx = (custom_ctx *) ctx_; + int rc; + if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) + return rc; + return ctx->p->cipher(ctx->p_ctx, mode, key, key_sz, iv, in, in_sz, out); +} + +static int sqlcipher_custom_get_key_sz(void *ctx) { + custom_ctx *ctx = (custom_ctx *) ctx_; + if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) + return 0; + return ctx->p->get_key_sz(ctx->p_ctx); +} + +static int sqlcipher_custom_get_iv_sz(void *ctx) { + custom_ctx *ctx = (custom_ctx *) ctx_; + if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) + return 0; + return ctx->p->get_iv_sz(ctx->p_ctx); +} + +static int sqlcipher_custom_get_block_sz(void *ctx) { + custom_ctx *ctx = (custom_ctx *) ctx_; + if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) + return 0; + return ctx->p->get_block_sz(ctx->p_ctx); +} + +static int sqlcipher_custom_get_hmac_sz(void *ctx) { + custom_ctx *ctx = (custom_ctx *) ctx_; + if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) + return 0; + return ctx->p->get_hmac_sz(ctx->p_ctx); +} + +static int sqlcipher_custom_fips_status(void *ctx_) { + custom_ctx *ctx = (custom_ctx *) ctx_; + if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) + return 0; + return ctx->p->fips_status(ctx->p_ctx); +} + + +int sqlcipher_custom_setup(sqlcipher_provider *p) { + p->activate = sqlcipher_custom_activate; + p->deactivate = sqlcipher_custom_deactivate; + p->get_provider_name = sqlcipher_custom_get_provider_name; + p->random = sqlcipher_custom_random; + p->hmac = sqlcipher_custom_hmac; + p->kdf = sqlcipher_custom_kdf; + p->cipher = sqlcipher_custom_cipher; + p->set_cipher = sqlcipher_custom_set_cipher; + p->get_cipher = sqlcipher_custom_get_cipher; + p->get_key_sz = sqlcipher_custom_get_key_sz; + p->get_iv_sz = sqlcipher_custom_get_iv_sz; + p->get_block_sz = sqlcipher_custom_get_block_sz; + p->get_hmac_sz = sqlcipher_custom_get_hmac_sz; + p->ctx_copy = sqlcipher_custom_ctx_copy; + p->ctx_cmp = sqlcipher_custom_ctx_cmp; + p->ctx_init = sqlcipher_custom_ctx_init; + p->ctx_free = sqlcipher_custom_ctx_free; + p->add_random = sqlcipher_custom_add_random; + p->fips_status = sqlcipher_custom_fips_status; + p->get_provider_version = sqlcipher_custom_get_provider_version; + return SQLITE_OK; +} + +#endif /* SQLITE_HAS_CODEC */ \ No newline at end of file diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 0de98d035d..ad45053a8d 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -119,18 +119,10 @@ void sqlcipher_activate() { default provider */ if(sqlcipher_get_provider() == NULL) { sqlcipher_provider *p = sqlcipher_malloc(sizeof(sqlcipher_provider)); -#if defined (SQLCIPHER_CRYPTO_CC) - extern int sqlcipher_cc_setup(sqlcipher_provider *p); - sqlcipher_cc_setup(p); -#elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) - extern int sqlcipher_ltc_setup(sqlcipher_provider *p); - sqlcipher_ltc_setup(p); -#elif defined (SQLCIPHER_CRYPTO_OPENSSL) - extern int sqlcipher_openssl_setup(sqlcipher_provider *p); - sqlcipher_openssl_setup(p); -#else -#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED" -#endif + + extern int sqlcipher_custom_setup(sqlcipher_provider *p); + sqlcipher_custom_setup(p); + sqlcipher_register_provider(p); } From de1683530735e24eb39076ef4957f003e90573a1 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 27 Sep 2016 12:40:49 +0800 Subject: [PATCH 12/94] Export SQLCipher APIs to loadext structure. --- src/loadext.c | 23 ++++++++++++++++++++++- src/sqlite3ext.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/loadext.c b/src/loadext.c index 94298c4763..b75be5e6ef 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -126,6 +126,19 @@ ** also check to make sure that the pointer to the function is ** not NULL before calling it. */ +#ifdef SQLITE_HAS_CODEC +static const sqlcipher_api_routines sqlcipherApis = { + sqlcipher_register_provider, + sqlcipher_get_provider, + sqlcipher_register_custom_provider, + sqlcipher_unregister_custom_provider, + sqlite3_key, + sqlite3_key_v2, + sqlite3_rekey, + sqlite3_rekey_v2 +}; +#endif + static const sqlite3_api_routines sqlite3Apis = { sqlite3_aggregate_context, #ifndef SQLITE_OMIT_DEPRECATED @@ -198,7 +211,15 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_get_autocommit, sqlite3_get_auxdata, sqlite3_get_table, - 0, /* Was sqlite3_global_recover(), but that function is deprecated */ + +#ifdef SQLITE_HAS_CODEC + /* Was sqlite3_global_recover(), but that function is deprecated. + We 'steal' this slot to place pointers to SQLCipher APIs. */ + &sqlcipherApis, +#else + 0, +#endif + sqlite3_interrupt, sqlite3_last_insert_rowid, sqlite3_libversion, diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 2e1c764a52..955d479b5f 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -18,7 +18,9 @@ #ifndef _SQLITE3EXT_H_ #define _SQLITE3EXT_H_ #include "sqlite3.h" +#include "sqlcipher.h" +typedef struct sqlcipher_api_routines sqlcipher_api_routines; typedef struct sqlite3_api_routines sqlite3_api_routines; /* @@ -31,6 +33,19 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** versions of SQLite will not be able to load each other's shared ** libraries! */ +#ifdef SQLITE_HAS_CODEC +struct sqlcipher_api_routines { + int (*register_provider)(sqlcipher_provider *p); + sqlcipher_provider* (*get_provider)(); + int (*register_custom_provider)(const char *name, sqlcipher_provider *p); + int (*unregister_custom_provider)(const char *name); + int (*key)(sqlite3 *db, const void *pKey, int nKey); + int (*key_v2)(sqlite3 *db, const char *zDb, const void *pKey, int nKey); + int (*rekey)(sqlite3 *db, const void *pKey, int nKey); + int (*rekey_v2)(sqlite3 *db, const char *zDb, const void *pKey, int nKey); +}; +#endif + struct sqlite3_api_routines { void * (*aggregate_context)(sqlite3_context*,int nBytes); int (*aggregate_count)(sqlite3_context*); @@ -105,7 +120,15 @@ struct sqlite3_api_routines { int (*get_autocommit)(sqlite3*); void * (*get_auxdata)(sqlite3_context*,int); int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); + +#ifdef SQLITE_HAS_CODEC + /* Was `int (*global_recover)(void);`, but no longer used. + Replaced with sqlcipher api pointers. */ + sqlcipher_api_routines *sqlcipher; +#else int (*global_recover)(void); +#endif + void (*interruptx)(sqlite3*); sqlite_int64 (*last_insert_rowid)(sqlite3*); const char * (*libversion)(void); @@ -522,6 +545,19 @@ struct sqlite3_api_routines { #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush + +/* SQLCipher APIs */ +#ifdef SQLITE_HAS_CODEC +#define sqlite3_key sqlite3_api->sqlcipher->key +#define sqlite3_key_v2 sqlite3_api->sqlcipher->key_v2 +#define sqlite3_rekey sqlite3_api->sqlcipher->rekey +#define sqlite3_rekey_v2 sqlite3_api->sqlcipher->rekey_v2 +#define sqlcipher_register_provider sqlite3_api->sqlcipher->register_provider +#define sqlcipher_get_provider sqlite3_api->sqlcipher->get_provider +#define sqlcipher_register_custom_provider sqlite3_api->sqlcipher->register_custom_provider +#define sqlcipher_unregister_custom_provider sqlite3_api->sqlcipher->unregister_custom_provider +#endif + #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) From 548cf94cb8304d0f1083f9d3911aaa63c05d3eb3 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 28 Sep 2016 15:25:55 +0800 Subject: [PATCH 13/94] Adjust SQLCipher API. Export sqlcipher_(un)register_custom_provider(). --- src/crypto.h | 8 ++++++++ src/sqlcipher.h | 14 ++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/crypto.h b/src/crypto.h index f58f9d1d04..0bf25aaaae 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -123,6 +123,14 @@ #define CODEC_HEXDUMP(DESC,BUFFER,LEN) #endif +/* utility functions */ +void sqlcipher_free(void *ptr, int sz); +void* sqlcipher_malloc(int sz); +void* sqlcipher_memset(void *v, unsigned char value, int len); +int sqlcipher_ismemset(const void *v, unsigned char value, int len); +int sqlcipher_memcmp(const void *v0, const void *v1, int len); +void sqlcipher_free(void *, int); + /* extensions defined in pager.c */ void sqlite3pager_get_codec(Pager *pPager, void **ctx); int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno); diff --git a/src/sqlcipher.h b/src/sqlcipher.h index 6da19447f7..8110826262 100644 --- a/src/sqlcipher.h +++ b/src/sqlcipher.h @@ -59,17 +59,11 @@ typedef struct { const char* (*get_provider_version)(void *ctx); } sqlcipher_provider; -/* utility functions */ -void sqlcipher_free(void *ptr, int sz); -void* sqlcipher_malloc(int sz); -void* sqlcipher_memset(void *v, unsigned char value, int len); -int sqlcipher_ismemset(const void *v, unsigned char value, int len); -int sqlcipher_memcmp(const void *v0, const void *v1, int len); -void sqlcipher_free(void *, int); - /* provider interfaces */ -int sqlcipher_register_provider(sqlcipher_provider *p); -sqlcipher_provider* sqlcipher_get_provider(); +SQLITE_API int SQLITE_STDCALL sqlcipher_register_provider(sqlcipher_provider *p); +SQLITE_API sqlcipher_provider* SQLITE_STDCALL sqlcipher_get_provider(); +SQLITE_API int SQLITE_STDCALL sqlcipher_register_custom_provider(const char *name, sqlcipher_provider *p); +SQLITE_API int SQLITE_STDCALL sqlcipher_unregister_custom_provider(const char *name); #endif #endif From 98d382693fa7907b9f69afdb83069eb68500f936 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 28 Sep 2016 15:30:27 +0800 Subject: [PATCH 14/94] Remove sqlcipher_cipher_profile, which is conflict with MMDB profile callback. --- src/crypto.c | 7 +------ src/crypto.h | 2 -- src/crypto_impl.c | 26 +------------------------- 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index c8941f7ac1..d6b0aad57e 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -108,11 +108,6 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value); sqlite3_free(store_pass_value); } - } - if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){ - char *profile_status = sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight)); - codec_vdbe_return_static_string(pParse, "cipher_profile", profile_status); - sqlite3_free(profile_status); } else if( sqlite3StrICmp(zLeft, "cipher_add_random")==0 && zRight ){ if(ctx) { @@ -140,7 +135,7 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef } else if( sqlite3StrICmp(zLeft, "cipher_version")==0 && !zRight ){ codec_vdbe_return_static_string(pParse, "cipher_version", codec_get_cipher_version()); - }else + } else if( sqlite3StrICmp(zLeft, "cipher")==0 ){ if(ctx) { if( zRight ) { diff --git a/src/crypto.h b/src/crypto.h index 0bf25aaaae..6db0ff23ce 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -242,8 +242,6 @@ int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx); int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz); -int sqlcipher_cipher_profile(sqlite3 *db, const char *destination); -static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time); static int sqlcipher_codec_get_store_pass(codec_ctx *ctx); static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); diff --git a/src/crypto_impl.c b/src/crypto_impl.c index ad45053a8d..4cf2a880ad 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -122,7 +122,7 @@ void sqlcipher_activate() { extern int sqlcipher_custom_setup(sqlcipher_provider *p); sqlcipher_custom_setup(p); - + sqlcipher_register_provider(p); } @@ -1241,30 +1241,6 @@ int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz return SQLITE_ERROR; } -int sqlcipher_cipher_profile(sqlite3 *db, const char *destination){ - FILE *f; - if( strcmp(destination,"stdout")==0 ){ - f = stdout; - }else if( strcmp(destination, "stderr")==0 ){ - f = stderr; - }else if( strcmp(destination, "off")==0 ){ - f = 0; - }else{ - f = fopen(destination, "wb"); - if( f==0 ){ - return SQLITE_ERROR; - } - } - sqlite3_profile(db, sqlcipher_profile_callback, f); - return SQLITE_OK; -} - -static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time){ - FILE *f = (FILE*)file; - double elapsed = run_time/1000000.0; - if( f ) fprintf(f, "Elapsed time:%.3f ms - %s\n", elapsed, sql); -} - int sqlcipher_codec_fips_status(codec_ctx *ctx) { return ctx->read_ctx->provider->fips_status(ctx->read_ctx); } From 660236721ac6c24498472e3119d8da078353e199 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 28 Sep 2016 15:31:02 +0800 Subject: [PATCH 15/94] Add XXTEA cipher implementation. --- ext/crypto/xxtea.c | 208 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 ext/crypto/xxtea.c diff --git a/ext/crypto/xxtea.c b/ext/crypto/xxtea.c new file mode 100644 index 0000000000..66ffe85cce --- /dev/null +++ b/ext/crypto/xxtea.c @@ -0,0 +1,208 @@ +/* BEGIN SQLCIPHER */ +#ifdef SQLITE_HAS_CODEC +#if defined(SQLCIPHER_CRYPTO_XXTEA) || !defined(SQLITE_CORE) + +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 + + +#define XXTEA_BLOCKBIT 32 +#define XXTEA_KEYBIT 128 +#define XXTEA_BLOCKBYTE (XXTEA_BLOCKBIT >> 3) +#define XXTEA_KEYBYTE (XXTEA_KEYBIT >> 3) + +#define XXTEA_DELTA 0x61C88647 /* -(0x9E3779B9) */ +#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) + + +static void xxtea_encode(uint32_t *v, int n, uint32_t const key[4]) +{ + uint32_t y, z, sum; + unsigned p, rounds, e; + + /* rounds = 6 + 52/n; */ + /* For SQLCipher, encode/decode is done on a whole page, which is 512 bytes at least. + n = (page_size - reserved_size) / 4, which will be always greater than 52, so we + save a division. */ + rounds = 6; + sum = 0; + z = v[n-1]; + do { + sum -= XXTEA_DELTA; + e = (sum >> 2) & 3; + for (p = 0; p < n - 1; p++) { + y = v[p + 1]; + z = v[p] += MX; + } + y = v[0]; + z = v[n - 1] += MX; + } while (--rounds); +} + +static void xxtea_decode(uint32_t *v, int n, uint32_t const key[4]) +{ + uint32_t y, z, sum; + unsigned p, rounds, e; + + /* rounds = 6 + 52/n; */ + /* For SQLCipher, encode/decode is done on a whole page, which is 512 bytes at least. + n = (page_size - reserved_size) / 4, which will be always greater than 52, so we + save a division. */ + rounds = 6; + sum = rounds * (-XXTEA_DELTA); + y = v[0]; + do { + e = (sum >> 2) & 3; + for (p = n - 1; p > 0; p--) { + z = v[p - 1]; + y = v[p] -= MX; + } + z = v[n - 1]; + y = v[0] -= MX; + } while ((sum += XXTEA_DELTA) != 0); +} + + +typedef struct xxtea_context { + int turns; +} xxtea_context; + +static int sqlcipher_xxtea_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, + unsigned char *in, int in_sz, unsigned char *out) { + int n = in_sz / XXTEA_BLOCKBYTE; + int turns = ((xxtea_context *) ctx)->turns; + uint32_t xor_key = *(uint32_t *) iv; + int i; + if (!mode) n = -n; + + //CODEC_TRACE(("sqlcipher_xxtea_cipher: cipher data %d\n",xxtea_turns)); + //CODEC_HEXDUMP("sqlcipher_xxtea_cipher: key data ", key,key_sz); + + if (!mode) { + /* Decryption */ + for (i = 0; i < turns; i++) { + /* It's OK to modify input buffer on decrytion mode, because it will be overwriten + by plain-text page later on. */ + xxtea_decode((uint32_t *) in, n, (uint32_t *) key); + } + + uint32_t *p_in = (uint32_t *) in; + uint32_t *p_out = (uint32_t *) out; + for (i = 0; i < in_sz; i += 4) { + xor_key ^= *p_in++; + *p_out++ = xor_key; + } + } else { + /* Encryption */ + uint32_t *p_in = (uint32_t *) in; + uint32_t *p_out = (uint32_t *) out; + for (i = 0; i < in_sz; i += 4) { + xor_key ^= *p_in++; + *p_out++ = xor_key; + } + + for (i = 0; i < turns; i++) { + xxtea_encode((uint32_t *) out, n, (uint32_t *) key); + } + } + + return SQLITE_OK; +} + +static const char *sqlcipher_xxtea_get_provider_name(void *ctx) { + return "xxtea"; +} + +static const char *sqlcipher_xxtea_get_provider_version(void *ctx) { + return "0.1" +} + +static int sqlcipher_xxtea_set_cipher(void *ctx, const char *cipher_name) { + return SQLITE_OK; +} + +static const char *sqlcipher_xxtea_get_cipher(void *ctx) { + return "xxtea"; +} + +static int sqlcipher_xxtea_get_key_sz(void *ctx) { + return XXTEA_KEYBYTE; +} + +static int sqlcipher_xxtea_get_iv_sz(void *ctx) { + return 4; +} + +static int sqlcipher_xxtea_get_block_sz(void *ctx) { + return XXTEA_BLOCKBYTE; +} + +static int sqlcipher_xxtea_ctx_copy(void *target_ctx, void *source_ctx) { + ((xxtea_context *) target_ctx)->turns = ((xxtea_context *) source_ctx)->turns; + return SQLITE_OK; +} + +static int sqlcipher_xxtea_ctx_cmp(void *c1, void *c2) { + return memcmp(c1, c2, sizeof(xxtea_context)) == 0; +} + +static int sqlcipher_xxtea_ctx_init(void **ctx) { + xxtea_context *c = sqlcipher_malloc(sizeof(xxtea_context)); + if (!c) return SQLITE_NOMEM; + + c->turns = 1; + *ctx = c; + return SQLITE_OK; +} + +static int sqlcipher_xxtea_ctx_free(void **ctx) { + sqlcipher_free(*ctx); +} + +static int sqlcipher_xxtea_fips_status(void *ctx) { + return 0; +} + +static int sqlcipher_xxtea_dummy_activate(void *ctx) { + return SQLITE_OK; +} + +static volatile int g_cipher_registered = 0; +static const sqlcipher_provider g_xxtea_provider = { + sqlcipher_xxtea_dummy_activate, /* activate */ + sqlcipher_xxtea_dummy_activate, /* deactivate */ + sqlcipher_xxtea_get_provider_name, /* get_provider_name */ + 0, /* add_random */ + 0, /* random */ + 0, /* hmac */ + 0, /* kdf */ + sqlcipher_xxtea_cipher, /* cipher */ + sqlcipher_xxtea_set_cipher, /* set_cipher */ + sqlcipher_xxtea_get_cipher, /* get_cipher */ + sqlcipher_xxtea_get_key_sz, /* get_key_sz */ + sqlcipher_xxtea_get_iv_sz, /* get_iv_sz */ + sqlcipher_xxtea_get_block_sz, /* get_block_sz */ + 0, /* get_hmac_sz */ + sqlcipher_xxtea_ctx_copy, /* ctx_copy */ + sqlcipher_xxtea_ctx_cmp, /* ctx_cmp */ + sqlcipher_xxtea_ctx_init, /* ctx_init */ + sqlcipher_xxtea_ctx_free, /* ctx_free */ + sqlcipher_xxtea_get_provider_version +}; + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_xxtea_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { + SQLITE_EXTENSION_INIT2(pApi); + + if (!g_cipher_registered) { + g_cipher_registered = 1; + sqlcipher_register_custom_provider("xxtea", &g_xxtea_provider); + } + + return SQLITE_OK; +} + +#endif /* defined(SQLCIPHER_CRYPTO_XXTEA) || !defined(SQLITE_CORE) */ +#endif /* SQLITE_HAS_CODEC */ From 1d0e55e0b36bd8d083a46d0379f0b3bd9b6379eb Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 28 Sep 2016 18:07:21 +0800 Subject: [PATCH 16/94] Update Makefile.in to include new source files. --- Makefile.in | 14 +- aclocal.m4 | 56 ++++---- config.guess | 355 +++++++++++++++++++-------------------------------- config.h.in | 3 - config.sub | 88 +++++++++---- configure | 45 +++---- 6 files changed, 250 insertions(+), 311 deletions(-) diff --git a/Makefile.in b/Makefile.in index 372cc9be56..2d726b257e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -143,16 +143,18 @@ CRYPTOLIBOBJ = \ crypto_impl.lo \ crypto_openssl.lo \ crypto_libtomcrypt.lo \ - crypto_cc.lo + crypto_cc.lo \ + crypto_custom.lo \ CRYPTOSRC = \ $(TOP)/src/crypto.h \ $(TOP)/src/sqlcipher.h \ $(TOP)/src/crypto.c \ $(TOP)/src/crypto_impl.c \ - $(TOP)/src/crypto_libtomcrypt.c \ - $(TOP)/src/crypto_openssl.c \ - $(TOP)/src/crypto_cc.c + $(TOP)/src/crypto_libtomcrypt.c \ + $(TOP)/src/crypto_openssl.c \ + $(TOP)/src/crypto_cc.c \ + $(TOP)/src/crypto_custom.c # END CRYPTO @@ -368,6 +370,10 @@ SRC += \ SRC += \ $(TOP)/ext/misc/json1.c +# Source code for crypto extensions +# +SRC += \ + $(TOP)/ext/crypto/xxtea.c # Generated source code files diff --git a/aclocal.m4 b/aclocal.m4 index 7bc688e947..666c0407d9 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1698,7 +1698,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -1946,7 +1946,7 @@ else lt_cv_dlopen_libs= ;; - cygwin*) + cygwin* | msys*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; @@ -2527,7 +2527,7 @@ bsdi[[45]]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no @@ -2556,6 +2556,12 @@ cygwin* | mingw* | pw32* | cegcc*) cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + msys*) + # MSYS DLLs use 'msys-' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/msys-/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; @@ -2593,7 +2599,7 @@ m4_if([$1], [],[ # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; - cygwin*) + cygwin* | msys*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... @@ -3371,7 +3377,7 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi @@ -3464,7 +3470,7 @@ bsdi[[45]]*) lt_cv_file_magic_test_file=/shlib/libc.so ;; -cygwin*) +cygwin* | msys*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' @@ -3777,7 +3783,7 @@ lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in @@ -3847,7 +3853,7 @@ AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-msys* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) @@ -3922,7 +3928,7 @@ case $host_os in aix*) symcode='[[BCDT]]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) @@ -4228,7 +4234,7 @@ m4_if([$1], [CXX], [ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | cygwin* | msys* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4304,7 +4310,7 @@ m4_if([$1], [CXX], [ ;; esac ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | cygwin* | msys* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4552,7 +4558,7 @@ m4_if([$1], [CXX], [ # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4656,7 +4662,7 @@ m4_if([$1], [CXX], [ esac ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4931,7 +4937,7 @@ m4_if([$1], [CXX], [ pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' @@ -4989,7 +4995,7 @@ dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. @@ -5104,7 +5110,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -5560,7 +5566,7 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -6631,7 +6637,7 @@ if test yes != "$_lt_caught_CXX_error"; then esac ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC @@ -8309,7 +8315,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd, *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; - *-*-cygwin* ) + *-*-cygwin* | *-*-msys* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix @@ -8317,12 +8323,12 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd, ;; esac ;; - *-*-cygwin* ) + *-*-cygwin* | *-*-msys* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; - *-*-cygwin* ) + *-*-cygwin* | *-*-msys* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix @@ -8487,7 +8493,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) +*-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) @@ -8529,11 +8535,7 @@ AC_ARG_ENABLE([shared], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; - no) - enable_shared=no - AC_DEFINE([LT_MINGW_STATIC_TESTSUITE_HACK], [1], - [Define if running the test suite so that test #27 works on MinGW.]) - ;; + no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. diff --git a/config.guess b/config.guess index b79252d6b1..2cc768c0fc 100644 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2013-06-10' +timestamp='2016-09-11' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ timestamp='2013-06-10' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -149,7 +149,7 @@ Linux|GNU|GNU/*) LIBC=gnu #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac @@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" + echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -579,8 +603,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -617,13 +642,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -662,11 +687,11 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -679,12 +704,12 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -789,14 +814,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -826,7 +851,7 @@ EOF *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; - i*:MSYS*:*) + *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) @@ -878,7 +903,7 @@ EOF exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix @@ -901,7 +926,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -932,6 +957,9 @@ EOF crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -944,6 +972,9 @@ EOF ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -969,10 +1000,10 @@ EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; - or1k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} exit ;; - or32:Linux:*:*) + or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) @@ -1001,6 +1032,9 @@ EOF ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; @@ -1020,7 +1054,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -1099,7 +1133,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1248,6 +1282,9 @@ EOF SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; @@ -1260,22 +1297,32 @@ EOF if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1306,7 +1353,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1348,7 +1395,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos @@ -1359,171 +1406,25 @@ EOF x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; -esac - -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs exit ;; - esac -fi +esac cat >&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp @@ -1555,4 +1456,4 @@ exit 1 # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" -# End: +# End: \ No newline at end of file diff --git a/config.h.in b/config.h.in index 1cf2365304..803c5ea81d 100644 --- a/config.h.in +++ b/config.h.in @@ -96,9 +96,6 @@ /* Define to 1 if you have the `utime' function. */ #undef HAVE_UTIME -/* Define if running the test suite so that test #27 works on MinGW. */ -#undef LT_MINGW_STATIC_TESTSUITE_HACK - /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR diff --git a/config.sub b/config.sub index 9633db7046..39dbf60da0 100644 --- a/config.sub +++ b/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2013-08-10' +timestamp='2016-09-05' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ timestamp='2013-08-10' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -33,7 +33,7 @@ timestamp='2013-08-10' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -53,8 +53,7 @@ timestamp='2013-08-10' me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. @@ -68,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -255,16 +254,18 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ @@ -282,8 +283,10 @@ case $basic_machine in | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ @@ -295,14 +298,14 @@ case $basic_machine in | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | open8 \ - | or1k | or32 \ + | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -310,6 +313,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -324,7 +328,10 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; @@ -369,18 +376,20 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ + | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ @@ -400,8 +409,10 @@ case $basic_machine in | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ @@ -413,16 +424,18 @@ case $basic_machine in | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ + | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -430,6 +443,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -506,6 +520,9 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -626,6 +643,14 @@ case $basic_machine in basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -767,6 +792,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -822,6 +850,10 @@ case $basic_machine in basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -998,7 +1030,7 @@ case $basic_machine in ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1008,7 +1040,7 @@ case $basic_machine in ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1354,27 +1386,28 @@ case $os in | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1506,6 +1539,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) @@ -1592,9 +1627,6 @@ case $basic_machine in mips*-*) os=-elf ;; - or1k-*) - os=-elf - ;; or32-*) os=-coff ;; @@ -1788,4 +1820,4 @@ exit # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" -# End: +# End: \ No newline at end of file diff --git a/configure b/configure index 6908feaf29..75cb8f93f9 100755 --- a/configure +++ b/configure @@ -3942,7 +3942,7 @@ else lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -4108,7 +4108,7 @@ else *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; - *-*-cygwin* ) + *-*-cygwin* | *-*-msys* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix @@ -4116,12 +4116,12 @@ else ;; esac ;; - *-*-cygwin* ) + *-*-cygwin* | *-*-msys* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; - *-*-cygwin* ) + *-*-cygwin* | *-*-msys* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix @@ -4187,7 +4187,7 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi @@ -4345,7 +4345,7 @@ bsdi[45]*) lt_cv_file_magic_test_file=/shlib/libc.so ;; -cygwin*) +cygwin* | msys*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' @@ -4664,7 +4664,7 @@ else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in @@ -5199,7 +5199,7 @@ case $host_os in aix*) symcode='[BCDT]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) @@ -6954,12 +6954,7 @@ if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; - no) - enable_shared=no - -$as_echo "#define LT_MINGW_STATIC_TESTSUITE_HACK 1" >>confdefs.h - - ;; + no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. @@ -7549,7 +7544,7 @@ lt_prog_compiler_static= # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -7652,7 +7647,7 @@ lt_prog_compiler_static= esac ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' @@ -8154,7 +8149,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. @@ -8269,7 +8264,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' @@ -8809,7 +8804,7 @@ fi export_dynamic_flag_spec=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -9844,7 +9839,7 @@ bsdi[45]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no @@ -9874,6 +9869,12 @@ cygwin* | mingw* | pw32* | cegcc*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + msys*) + # MSYS DLLs use 'msys-' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/msys-/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) @@ -9910,7 +9911,7 @@ cygwin* | mingw* | pw32* | cegcc*) # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; - cygwin*) + cygwin* | msys*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... @@ -10612,7 +10613,7 @@ else lt_cv_dlopen_libs= ;; - cygwin*) + cygwin* | msys*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; From 397eca10860ad7b0a1c0c8d37951431699b3c071 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 28 Sep 2016 22:48:53 +0800 Subject: [PATCH 17/94] Fix compile error. --- Makefile.in | 7 ++++++- ext/crypto/xxtea.c | 5 +++-- src/crypto_custom.c | 28 ++++++++++++++-------------- src/sqlcipher.h | 2 +- src/sqlite3ext.h | 4 ++-- tool/mksqlite3c.tcl | 2 ++ 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Makefile.in b/Makefile.in index 2d726b257e..70f18f3282 100644 --- a/Makefile.in +++ b/Makefile.in @@ -144,7 +144,7 @@ CRYPTOLIBOBJ = \ crypto_openssl.lo \ crypto_libtomcrypt.lo \ crypto_cc.lo \ - crypto_custom.lo \ + crypto_custom.lo CRYPTOSRC = \ $(TOP)/src/crypto.h \ @@ -707,6 +707,8 @@ crypto_libtomcrypt.lo: $(TOP)/src/crypto_libtomcrypt.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/crypto_libtomcrypt.c crypto_cc.lo: $(TOP)/src/crypto_cc.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/crypto_cc.c +crypto_custom.lo: $(TOP)/src/crypto_crypto.c $(HDR) + $(LTCOMPILE) -c $(TOP)/src/crypto_crypto.c # END CRYPTO # Rules to build individual *.o files from files in the src directory. @@ -1042,6 +1044,9 @@ rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) json1.lo: $(TOP)/ext/misc/json1.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c +xxtea.lo: $(TOP)/ext/crypto/xxtea.c + $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/crypto/xxtea.c + # FTS5 things # FTS5_SRC = \ diff --git a/ext/crypto/xxtea.c b/ext/crypto/xxtea.c index 66ffe85cce..ce8d16f837 100644 --- a/ext/crypto/xxtea.c +++ b/ext/crypto/xxtea.c @@ -114,7 +114,7 @@ static const char *sqlcipher_xxtea_get_provider_name(void *ctx) { } static const char *sqlcipher_xxtea_get_provider_version(void *ctx) { - return "0.1" + return "0.1"; } static int sqlcipher_xxtea_set_cipher(void *ctx, const char *cipher_name) { @@ -156,7 +156,7 @@ static int sqlcipher_xxtea_ctx_init(void **ctx) { } static int sqlcipher_xxtea_ctx_free(void **ctx) { - sqlcipher_free(*ctx); + sqlcipher_free(*ctx, sizeof(xxtea_context)); } static int sqlcipher_xxtea_fips_status(void *ctx) { @@ -187,6 +187,7 @@ static const sqlcipher_provider g_xxtea_provider = { sqlcipher_xxtea_ctx_cmp, /* ctx_cmp */ sqlcipher_xxtea_ctx_init, /* ctx_init */ sqlcipher_xxtea_ctx_free, /* ctx_free */ + sqlcipher_xxtea_fips_status, /* fips_status */ sqlcipher_xxtea_get_provider_version }; diff --git a/src/crypto_custom.c b/src/crypto_custom.c index d67dc614ea..866c99d64b 100644 --- a/src/crypto_custom.c +++ b/src/crypto_custom.c @@ -26,7 +26,7 @@ static sqlite3_mutex *custom_providers_mutex; static sqlcipher_provider *default_provider; /* Default fallback provider, should be openssl, libtomcrypt or commoncrypto */ static int activate_count = 0; -static void provider_overload(sqlcipher_provider *base, sqlcipher_provider *p) { +static void provider_overload(const sqlcipher_provider *base, sqlcipher_provider *p) { /* sqlcipher_provider is actually a pile of function pointers, which has the same size of (void *). We can just run a loop comparing and assigning raw pointers. */ int n = sizeof(sqlcipher_provider) / sizeof(void *); @@ -47,8 +47,8 @@ static int select_provider(custom_ctx *ctx, const char *name) { if (name) { int i; for (i = 0; i < custom_providers_count; i++) { - if (strcmp(custom_providers[i].name, name) == 0) { - ctx->p = &custom_providers[i].p; + if (strcmp(custom_providers[i]->name, name) == 0) { + ctx->p = &custom_providers[i]->p; break; } } @@ -67,11 +67,11 @@ static int select_provider(custom_ctx *ctx, const char *name) { return rc; } -int sqlcipher_register_custom_provider(const char *name, sqlcipher_provider *p) { +int sqlcipher_register_custom_provider(const char *name, const sqlcipher_provider *p) { sqlite3_mutex_enter(custom_providers_mutex); /* Grow custom provider list if it's full. */ - if (custom_provider_count >= custom_providers_capacity) { + if (custom_providers_count >= custom_providers_capacity) { /* Linear growth should be enough here as we probably don't have so much providers. */ int new_capacity = custom_providers_capacity + 16; void *new_list = sqlite3_realloc(custom_providers, new_capacity * sizeof(sqlcipher_named_provider *)); @@ -93,7 +93,7 @@ int sqlcipher_register_custom_provider(const char *name, sqlcipher_provider *p) /* Find existing provider. */ int i; for (i = 0; i < custom_providers_count; i++) { - if (strcmp(custom_providers[i].name, name) == 0) + if (strcmp(custom_providers[i]->name, name) == 0) break; } if (i < custom_providers_count) { @@ -119,7 +119,7 @@ int sqlcipher_unregister_custom_provider(const char *name) { /* Find existing provider. */ int i; for (i = 0; i < custom_providers_count; i++) { - if (strcmp(custom_providers[i].name, name) == 0) + if (strcmp(custom_providers[i]->name, name) == 0) break; } if (i < custom_providers_count) { @@ -154,7 +154,7 @@ static int sqlcipher_custom_activate(void *ctx) { #error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED" #endif - custom_provider_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + custom_providers_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); } activate_count++; @@ -173,7 +173,7 @@ static int sqlcipher_custom_deactivate(void *ctx) { if (--activate_count == 0) { sqlite3_free(default_provider); default_provider = NULL; - sqlite3_mutex_free(custom_provider_mutex); + sqlite3_mutex_free(custom_providers_mutex); } sqlite3_mutex_leave(mutex); @@ -242,7 +242,7 @@ static int sqlcipher_custom_random(void *ctx_, void *buffer, int length) { int rc; if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) return rc; - return ctx->p->random(p->p_ctx, buffer, length); + return ctx->p->random(ctx->p_ctx, buffer, length); } static int sqlcipher_custom_add_random(void *ctx_, void *buffer, int length) { @@ -280,28 +280,28 @@ static int sqlcipher_custom_cipher(void *ctx_, int mode, unsigned char *key, int return ctx->p->cipher(ctx->p_ctx, mode, key, key_sz, iv, in, in_sz, out); } -static int sqlcipher_custom_get_key_sz(void *ctx) { +static int sqlcipher_custom_get_key_sz(void *ctx_) { custom_ctx *ctx = (custom_ctx *) ctx_; if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) return 0; return ctx->p->get_key_sz(ctx->p_ctx); } -static int sqlcipher_custom_get_iv_sz(void *ctx) { +static int sqlcipher_custom_get_iv_sz(void *ctx_) { custom_ctx *ctx = (custom_ctx *) ctx_; if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) return 0; return ctx->p->get_iv_sz(ctx->p_ctx); } -static int sqlcipher_custom_get_block_sz(void *ctx) { +static int sqlcipher_custom_get_block_sz(void *ctx_) { custom_ctx *ctx = (custom_ctx *) ctx_; if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) return 0; return ctx->p->get_block_sz(ctx->p_ctx); } -static int sqlcipher_custom_get_hmac_sz(void *ctx) { +static int sqlcipher_custom_get_hmac_sz(void *ctx_) { custom_ctx *ctx = (custom_ctx *) ctx_; if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) return 0; diff --git a/src/sqlcipher.h b/src/sqlcipher.h index 8110826262..d93727086c 100644 --- a/src/sqlcipher.h +++ b/src/sqlcipher.h @@ -62,7 +62,7 @@ typedef struct { /* provider interfaces */ SQLITE_API int SQLITE_STDCALL sqlcipher_register_provider(sqlcipher_provider *p); SQLITE_API sqlcipher_provider* SQLITE_STDCALL sqlcipher_get_provider(); -SQLITE_API int SQLITE_STDCALL sqlcipher_register_custom_provider(const char *name, sqlcipher_provider *p); +SQLITE_API int SQLITE_STDCALL sqlcipher_register_custom_provider(const char *name, const sqlcipher_provider *p); SQLITE_API int SQLITE_STDCALL sqlcipher_unregister_custom_provider(const char *name); #endif diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 955d479b5f..d5ff8fd9e2 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -37,7 +37,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; struct sqlcipher_api_routines { int (*register_provider)(sqlcipher_provider *p); sqlcipher_provider* (*get_provider)(); - int (*register_custom_provider)(const char *name, sqlcipher_provider *p); + int (*register_custom_provider)(const char *name, const sqlcipher_provider *p); int (*unregister_custom_provider)(const char *name); int (*key)(sqlite3 *db, const void *pKey, int nKey); int (*key_v2)(sqlite3 *db, const char *zDb, const void *pKey, int nKey); @@ -124,7 +124,7 @@ struct sqlite3_api_routines { #ifdef SQLITE_HAS_CODEC /* Was `int (*global_recover)(void);`, but no longer used. Replaced with sqlcipher api pointers. */ - sqlcipher_api_routines *sqlcipher; + const sqlcipher_api_routines *sqlcipher; #else int (*global_recover)(void); #endif diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 65cc10dfd9..93314f69f6 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -284,6 +284,7 @@ foreach file { crypto_libtomcrypt.c crypto_openssl.c crypto_cc.c + crypto_custom.c global.c ctime.c @@ -391,6 +392,7 @@ foreach file { dbstat.c json1.c fts5.c + xxtea.c } { copy_file tsrc/$file } From ae7a4cb1af5a0f9356f73ed4458895c4a3fda66f Mon Sep 17 00:00:00 2001 From: johnwhe Date: Thu, 29 Sep 2016 18:41:02 +0800 Subject: [PATCH 18/94] Fix MinGW build. --- src/shell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shell.c b/src/shell.c index d9631498c8..119e23bf71 100644 --- a/src/shell.c +++ b/src/shell.c @@ -5003,7 +5003,9 @@ int SQLITE_CDECL main(int argc, char **argv){ if( zHistory ){ shell_read_history(zHistory); } rc = process_input(&data, 0); if( zHistory ){ +#ifndef __MINGW32__ shell_stifle_history(100); +#endif shell_write_history(zHistory); free(zHistory); } From 97e0f71683fb193ed38bc9ef8874b4402bc132f8 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Thu, 29 Sep 2016 18:47:32 +0800 Subject: [PATCH 19/94] Fix dead loop. --- src/crypto.c | 8 ++------ src/crypto_custom.c | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index d6b0aad57e..6efdccbd93 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -79,7 +79,6 @@ static int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, } int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const char *zRight) { - char *pragma_cipher_deprecated_msg = "PRAGMA cipher command is deprecated, please remove from usage."; struct Db *pDb = &db->aDb[iDb]; codec_ctx *ctx = NULL; int rc; @@ -140,18 +139,15 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef if(ctx) { if( zRight ) { sqlcipher_codec_ctx_set_cipher(ctx, zRight, 2); // change cipher for both - codec_vdbe_return_static_string(pParse, "cipher", pragma_cipher_deprecated_msg); - sqlite3_log(SQLITE_WARNING, pragma_cipher_deprecated_msg); - return SQLITE_ERROR; }else { codec_vdbe_return_static_string(pParse, "cipher", sqlcipher_codec_ctx_get_cipher(ctx, 2)); } } - }else + } else if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){ if(ctx) sqlcipher_codec_ctx_set_cipher(ctx, zRight, 1); // change write cipher only - }else + } else if( sqlite3StrICmp(zLeft,"cipher_default_kdf_iter")==0 ){ if( zRight ) { sqlcipher_set_default_kdf_iter(atoi(zRight)); // change default KDF iterations diff --git a/src/crypto_custom.c b/src/crypto_custom.c index 866c99d64b..857bcfbe3d 100644 --- a/src/crypto_custom.c +++ b/src/crypto_custom.c @@ -23,7 +23,7 @@ static int custom_providers_count; static int custom_providers_capacity; static sqlite3_mutex *custom_providers_mutex; -static sqlcipher_provider *default_provider; /* Default fallback provider, should be openssl, libtomcrypt or commoncrypto */ +static sqlcipher_provider *fallback_provider; /* Default fallback provider, should be openssl, libtomcrypt or commoncrypto */ static int activate_count = 0; static void provider_overload(const sqlcipher_provider *base, sqlcipher_provider *p) { @@ -55,7 +55,7 @@ static int select_provider(custom_ctx *ctx, const char *name) { } if (!ctx->p) - ctx->p = default_provider; + ctx->p = fallback_provider; /* Now we have chosen which provider will be used, we can initialize the real provider context. */ @@ -88,7 +88,7 @@ int sqlcipher_register_custom_provider(const char *name, const sqlcipher_provide /* Overload provider functions. */ strncpy(np->name, name, len); memcpy(&np->p, p, sizeof(sqlcipher_provider)); - provider_overload(default_provider, &np->p); + provider_overload(fallback_provider, &np->p); /* Find existing provider. */ int i; @@ -137,19 +137,19 @@ static int sqlcipher_custom_activate(void *ctx) { sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(mutex); - if (!default_provider) { - default_provider = (sqlcipher_provider *) malloc(sizeof(sqlcipher_provider)); - if (!default_provider) goto bail; + if (!fallback_provider) { + fallback_provider = (sqlcipher_provider *) malloc(sizeof(sqlcipher_provider)); + if (!fallback_provider) goto bail; #if defined (SQLCIPHER_CRYPTO_CC) extern int sqlcipher_cc_setup(sqlcipher_provider *p); - sqlcipher_cc_setup(default_provider); + sqlcipher_cc_setup(fallback_provider); #elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) extern int sqlcipher_ltc_setup(sqlcipher_provider *p); - sqlcipher_ltc_setup(default_provider); + sqlcipher_ltc_setup(fallback_provider); #elif defined (SQLCIPHER_CRYPTO_OPENSSL) - extern int sqlcipher_custom_setup(sqlcipher_provider *p); - sqlcipher_custom_setup(default_provider); + extern int sqlcipher_openssl_setup(sqlcipher_provider *p); + sqlcipher_openssl_setup(fallback_provider); #else #error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED" #endif @@ -171,8 +171,8 @@ static int sqlcipher_custom_deactivate(void *ctx) { sqlite3_mutex_enter(mutex); if (--activate_count == 0) { - sqlite3_free(default_provider); - default_provider = NULL; + sqlite3_free(fallback_provider); + fallback_provider = NULL; sqlite3_mutex_free(custom_providers_mutex); } From f0142922c403f68719774c0444875255054745ef Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 30 Sep 2016 18:26:13 +0800 Subject: [PATCH 20/94] When compile with SQLITE_CRYPTO_XXTEA, register xxtea provider on initialization. Also fix various of runtime fault. --- ext/crypto/xxtea.c | 18 +++-- src/crypto_custom.c | 181 ++++++++++++++++++++++++-------------------- 2 files changed, 113 insertions(+), 86 deletions(-) diff --git a/ext/crypto/xxtea.c b/ext/crypto/xxtea.c index ce8d16f837..f921d4707a 100644 --- a/ext/crypto/xxtea.c +++ b/ext/crypto/xxtea.c @@ -73,7 +73,6 @@ static int sqlcipher_xxtea_cipher(void *ctx, int mode, unsigned char *key, int k int turns = ((xxtea_context *) ctx)->turns; uint32_t xor_key = *(uint32_t *) iv; int i; - if (!mode) n = -n; //CODEC_TRACE(("sqlcipher_xxtea_cipher: cipher data %d\n",xxtea_turns)); //CODEC_HEXDUMP("sqlcipher_xxtea_cipher: key data ", key,key_sz); @@ -88,15 +87,15 @@ static int sqlcipher_xxtea_cipher(void *ctx, int mode, unsigned char *key, int k uint32_t *p_in = (uint32_t *) in; uint32_t *p_out = (uint32_t *) out; - for (i = 0; i < in_sz; i += 4) { - xor_key ^= *p_in++; - *p_out++ = xor_key; + for (i = 0; i < n; i++) { + *p_out++ = xor_key ^ *p_in; + xor_key = *p_in++; } } else { /* Encryption */ uint32_t *p_in = (uint32_t *) in; uint32_t *p_out = (uint32_t *) out; - for (i = 0; i < in_sz; i += 4) { + for (i = 0; i < n; i++) { xor_key ^= *p_in++; *p_out++ = xor_key; } @@ -191,6 +190,7 @@ static const sqlcipher_provider g_xxtea_provider = { sqlcipher_xxtea_get_provider_version }; +#ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -199,11 +199,17 @@ int sqlite3_xxtea_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines if (!g_cipher_registered) { g_cipher_registered = 1; - sqlcipher_register_custom_provider("xxtea", &g_xxtea_provider); + return sqlcipher_register_custom_provider("xxtea", &g_xxtea_provider); } return SQLITE_OK; } +#else /* SQLITE_CORE */ +int sqlcipherCryptoXxteaInit() { + g_cipher_registered = 1; + return sqlcipher_register_custom_provider("xxtea", &g_xxtea_provider); +} +#endif #endif /* defined(SQLCIPHER_CRYPTO_XXTEA) || !defined(SQLITE_CORE) */ #endif /* SQLITE_HAS_CODEC */ diff --git a/src/crypto_custom.c b/src/crypto_custom.c index 857bcfbe3d..b62a0529c8 100644 --- a/src/crypto_custom.c +++ b/src/crypto_custom.c @@ -3,6 +3,8 @@ #include "sqliteInt.h" #include "sqlcipher.h" +#include + /* Structure to store registered custom providers, in a list */ typedef struct sqlcipher_named_provider { @@ -18,12 +20,13 @@ typedef struct custom_ctx { /* Custom provider list */ -static sqlcipher_named_provider **custom_providers; -static int custom_providers_count; -static int custom_providers_capacity; +static sqlcipher_named_provider **custom_providers = NULL; +static int custom_providers_count = 0; +static int custom_providers_capacity = 0; static sqlite3_mutex *custom_providers_mutex; -static sqlcipher_provider *fallback_provider; /* Default fallback provider, should be openssl, libtomcrypt or commoncrypto */ +/* Default fallback provider, should be openssl, libtomcrypt or commoncrypto */ +static sqlcipher_provider *fallback_provider; static int activate_count = 0; static void provider_overload(const sqlcipher_provider *base, sqlcipher_provider *p) { @@ -41,25 +44,33 @@ static int select_provider(custom_ctx *ctx, const char *name) { int rc = SQLITE_OK; sqlite3_mutex_enter(custom_providers_mutex); - if (ctx->p) goto end; + sqlcipher_provider *p = NULL; /* Select provider according to name. */ if (name) { int i; for (i = 0; i < custom_providers_count; i++) { if (strcmp(custom_providers[i]->name, name) == 0) { - ctx->p = &custom_providers[i]->p; + p = &custom_providers[i]->p; break; } } } - if (!ctx->p) - ctx->p = fallback_provider; + /* No provider can match the name, use default provider. */ + if (!p) + p = fallback_provider; + + /* Cleanup previous context if exists. */ + if (p == ctx->p) goto end; + if (ctx->p_ctx) { + ctx->p->ctx_free(&ctx->p_ctx); + ctx->p_ctx = NULL; + } /* Now we have chosen which provider will be used, we can initialize the real provider context. */ - ctx->p_ctx = NULL; + ctx->p = p; rc = ctx->p->ctx_init(&ctx->p_ctx); end: @@ -138,7 +149,8 @@ static int sqlcipher_custom_activate(void *ctx) { sqlite3_mutex_enter(mutex); if (!fallback_provider) { - fallback_provider = (sqlcipher_provider *) malloc(sizeof(sqlcipher_provider)); + fallback_provider = (sqlcipher_provider *) + sqlite3_malloc(sizeof(sqlcipher_provider)); if (!fallback_provider) goto bail; #if defined (SQLCIPHER_CRYPTO_CC) @@ -155,6 +167,16 @@ static int sqlcipher_custom_activate(void *ctx) { #endif custom_providers_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + + /* initialize static-linked crypto modules. */ + int rc = SQLITE_OK; +#ifdef SQLCIPHER_CRYPTO_XXTEA + if (rc == SQLITE_OK) { + extern int sqlcipherCryptoXxteaInit(); + rc = sqlcipherCryptoXxteaInit(); + } +#endif + (void) rc; } activate_count++; @@ -173,6 +195,12 @@ static int sqlcipher_custom_deactivate(void *ctx) { if (--activate_count == 0) { sqlite3_free(fallback_provider); fallback_provider = NULL; + + sqlite3_free(custom_providers); + custom_providers = NULL; + custom_providers_count = 0; + custom_providers_capacity = 0; + sqlite3_mutex_free(custom_providers_mutex); } @@ -182,24 +210,33 @@ static int sqlcipher_custom_deactivate(void *ctx) { static int sqlcipher_custom_ctx_init(void **ctx) { custom_ctx *c; - *ctx = c = sqlite3_malloc(sizeof(sizeof(custom_ctx))); + c = sqlite3_malloc(sizeof(custom_ctx)); + *ctx = c; if (!c) return SQLITE_NOMEM; sqlcipher_custom_activate(c); - c->p = NULL; + c->p = fallback_provider; c->p_ctx = NULL; - return SQLITE_OK; + return c->p->ctx_init(&c->p_ctx); } static int sqlcipher_custom_ctx_free(void **ctx) { + int rc; + custom_ctx *c = (custom_ctx *) *ctx; + if (c->p_ctx && (rc = c->p->ctx_free(&c->p_ctx)) != SQLITE_OK) + return rc; + sqlcipher_custom_deactivate(*ctx); sqlite3_free(*ctx); return SQLITE_OK; } static int sqlcipher_custom_ctx_copy(void *target_ctx, void *source_ctx) { - memcpy(target_ctx, source_ctx, sizeof(custom_ctx)); - return SQLITE_OK; + custom_ctx *src = (custom_ctx *) source_ctx; + custom_ctx *dst = (custom_ctx *) target_ctx; + + dst->p = src->p; + return dst->p->ctx_copy(dst->p_ctx, src->p_ctx); } static int sqlcipher_custom_ctx_cmp(void *c1, void *c2) { @@ -221,98 +258,82 @@ static const char* sqlcipher_custom_get_provider_version(void *ctx) { return "0.2.2"; } -static int sqlcipher_custom_set_cipher(void *ctx_, const char *cipher_name) { - custom_ctx *ctx = (custom_ctx *) ctx_; +static int sqlcipher_custom_set_cipher(void *ctx, const char *cipher_name) { + custom_ctx *c = (custom_ctx *) ctx; int rc; /* Initialize provider accroding to cipher_name. */ - if (!ctx->p && (rc = select_provider(ctx, cipher_name)) != SQLITE_OK) + if ((rc = select_provider(c, cipher_name)) != SQLITE_OK) return rc; - return ctx->p->set_cipher(ctx->p_ctx, cipher_name); + return c->p->set_cipher(c->p_ctx, cipher_name); } -static const char* sqlcipher_custom_get_cipher(void *ctx_) { - custom_ctx *ctx = (custom_ctx *) ctx_; - if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) - return ""; - return ctx->p->get_cipher(ctx->p_ctx); +static const char* sqlcipher_custom_get_cipher(void *ctx) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->get_cipher(c->p_ctx); } -static int sqlcipher_custom_random(void *ctx_, void *buffer, int length) { - custom_ctx *ctx = (custom_ctx *) ctx_; - int rc; - if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) - return rc; - return ctx->p->random(ctx->p_ctx, buffer, length); +static int sqlcipher_custom_random(void *ctx, void *buffer, int length) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->random(c->p_ctx, buffer, length); } -static int sqlcipher_custom_add_random(void *ctx_, void *buffer, int length) { - custom_ctx *ctx = (custom_ctx *) ctx_; - int rc; - if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) - return rc; - return ctx->p->add_random(ctx->p_ctx, buffer, length); +static int sqlcipher_custom_add_random(void *ctx, void *buffer, int length) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->add_random(c->p_ctx, buffer, length); } -static int sqlcipher_custom_hmac(void *ctx_, unsigned char *hmac_key, int key_sz, +static int sqlcipher_custom_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) { - custom_ctx *ctx = (custom_ctx *) ctx_; - int rc; - if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) - return rc; - return ctx->p->hmac(ctx->p_ctx, hmac_key, key_sz, in, in_sz, in2, in2_sz, out); + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->hmac(c->p_ctx, hmac_key, key_sz, in, in_sz, in2, in2_sz, out); } -static int sqlcipher_custom_kdf(void *ctx_, const unsigned char *pass, int pass_sz, +static int sqlcipher_custom_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) { - custom_ctx *ctx = (custom_ctx *) ctx_; - int rc; - if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) - return rc; - return ctx->p->kdf(ctx->p_ctx, pass, pass_sz, salt, salt_sz, workfactor, key_sz, key); + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->kdf(c->p_ctx, pass, pass_sz, salt, salt_sz, workfactor, key_sz, key); } -static int sqlcipher_custom_cipher(void *ctx_, int mode, unsigned char *key, int key_sz, +static int sqlcipher_custom_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) { - custom_ctx *ctx = (custom_ctx *) ctx_; - int rc; - if (!ctx->p && (rc = select_provider(ctx, NULL)) != SQLITE_OK) - return rc; - return ctx->p->cipher(ctx->p_ctx, mode, key, key_sz, iv, in, in_sz, out); + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->cipher(c->p_ctx, mode, key, key_sz, iv, in, in_sz, out); } -static int sqlcipher_custom_get_key_sz(void *ctx_) { - custom_ctx *ctx = (custom_ctx *) ctx_; - if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) - return 0; - return ctx->p->get_key_sz(ctx->p_ctx); +static int sqlcipher_custom_get_key_sz(void *ctx) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->get_key_sz(c->p_ctx); } -static int sqlcipher_custom_get_iv_sz(void *ctx_) { - custom_ctx *ctx = (custom_ctx *) ctx_; - if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) - return 0; - return ctx->p->get_iv_sz(ctx->p_ctx); +static int sqlcipher_custom_get_iv_sz(void *ctx) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->get_iv_sz(c->p_ctx); } -static int sqlcipher_custom_get_block_sz(void *ctx_) { - custom_ctx *ctx = (custom_ctx *) ctx_; - if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) - return 0; - return ctx->p->get_block_sz(ctx->p_ctx); +static int sqlcipher_custom_get_block_sz(void *ctx) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->get_block_sz(c->p_ctx); } -static int sqlcipher_custom_get_hmac_sz(void *ctx_) { - custom_ctx *ctx = (custom_ctx *) ctx_; - if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) - return 0; - return ctx->p->get_hmac_sz(ctx->p_ctx); +static int sqlcipher_custom_get_hmac_sz(void *ctx) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->get_hmac_sz(c->p_ctx); } -static int sqlcipher_custom_fips_status(void *ctx_) { - custom_ctx *ctx = (custom_ctx *) ctx_; - if (!ctx->p && select_provider(ctx, NULL) != SQLITE_OK) - return 0; - return ctx->p->fips_status(ctx->p_ctx); +static int sqlcipher_custom_fips_status(void *ctx) { + custom_ctx *c = (custom_ctx *) ctx; + assert(c->p && c->p_ctx); + return c->p->fips_status(c->p_ctx); } @@ -340,4 +361,4 @@ int sqlcipher_custom_setup(sqlcipher_provider *p) { return SQLITE_OK; } -#endif /* SQLITE_HAS_CODEC */ \ No newline at end of file +#endif /* SQLITE_HAS_CODEC */ From 7f5028075e2709cca8db20dcf87b0697f7e5c477 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 7 Oct 2016 15:10:06 +0800 Subject: [PATCH 21/94] Install on `make install`. --- Makefile.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.in b/Makefile.in index 70f18f3282..57d6d61c51 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1242,6 +1242,7 @@ install: sqlcipher$(TEXE) lib_install sqlite3.h sqlcipher.pc ${HAVE_TCL:1=tcl_in $(INSTALL) -d $(DESTDIR)$(includedir) $(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir) $(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir) + $(INSTALL) -m 0644 $(TOP)/src/sqlcipher.h $(DESTDIR)$(includedir) $(INSTALL) -d $(DESTDIR)$(pkgconfigdir) $(INSTALL) -m 0644 sqlcipher.pc $(DESTDIR)$(pkgconfigdir) From ba0083167507510d443923bd1039effd73478113 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 22 Nov 2016 18:01:14 +0800 Subject: [PATCH 22/94] Use ftruncate64 on Android platform. --- ext/crypto/xxtea.c | 1 + src/os_unix.c | 34 ++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ext/crypto/xxtea.c b/ext/crypto/xxtea.c index f921d4707a..9fac9ff6ba 100644 --- a/ext/crypto/xxtea.c +++ b/ext/crypto/xxtea.c @@ -156,6 +156,7 @@ static int sqlcipher_xxtea_ctx_init(void **ctx) { static int sqlcipher_xxtea_ctx_free(void **ctx) { sqlcipher_free(*ctx, sizeof(xxtea_context)); + return SQLITE_OK; } static int sqlcipher_xxtea_fips_status(void *ctx) { diff --git a/src/os_unix.c b/src/os_unix.c index 0721eaafe7..b37669e952 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -312,6 +312,16 @@ static pid_t randomnessPid = 0; ** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. */ #ifdef __ANDROID__ + +# include +# if __ANDROID_API__ < 12 +/* Android API < 12 lacks ftruncate64 implementation. */ +# include +static int ftruncate64(int fd, off64_t size) { + return syscall(__NR_ftruncate64, fd, 0, size & 0xFFFFFFFF, size >> 32); +} +# endif + # define lseek lseek64 #endif @@ -371,8 +381,13 @@ static struct unix_syscall { #define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent) #endif +#if defined(__ANDROID__) + { "ftruncate", (sqlite3_syscall_ptr)ftruncate64, 0 }, +# define osFtruncate ((int(*)(int,off64_t))aSyscall[6].pCurrent) +#else { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 }, -#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent) +# define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent) +#endif { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 }, #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) @@ -393,9 +408,9 @@ static struct unix_syscall { { "pread64", (sqlite3_syscall_ptr)0, 0 }, #endif #if defined(__ANDROID__) -#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) +# define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) #else -#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) +# define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) #endif { "write", (sqlite3_syscall_ptr)write, 0 }, @@ -415,10 +430,10 @@ static struct unix_syscall { { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif #if defined(__ANDROID__) -#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ +# define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) #else -#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ +# define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[13].pCurrent) #endif @@ -772,15 +787,6 @@ static int lockTrace(int fd, int op, struct flock *p){ */ static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; -#ifdef __ANDROID__ - /* On Android, ftruncate() always uses 32-bit offsets, even if - ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to - ** truncate a file to any size larger than 2GiB. Silently ignore any - ** such attempts. */ - if( sz>(sqlite3_int64)0x7FFFFFFF ){ - rc = SQLITE_OK; - }else -#endif do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); return rc; } From 4b73a9e14b5a9b0edf21661ca989763f51270a10 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 17 Feb 2017 18:10:46 +0800 Subject: [PATCH 23/94] Remove out-dated readme. --- README-WeChat.md | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 README-WeChat.md diff --git a/README-WeChat.md b/README-WeChat.md deleted file mode 100644 index 72185ddb04..0000000000 --- a/README-WeChat.md +++ /dev/null @@ -1,46 +0,0 @@ -## WeChat (MMDB) Specific Configurations - -For compatibility reasons, WeChat uses SQLCipher 1.x format. - - * KDF Iterations set to 4000; - * Do NOT use HMAC. - -WeChat specific configurations: - - * Custom FTS3 tokenizer registeration must be enabled. - -Additional configurations for Android environment: - - * Generate Thumb code rather than ARM; (`-mthumb`) - * Optimize for size rather than speed; (`-Os`) - * PIC must be enabled; (`-fPIC`) - * PIE (position independent executable) must be enabled for Android >= 5.0; (`-fPIE -pie`) - * Omit memory lock in SQLCipher, which will cause problems with some drivers; (`-DOMIT_MEMLOCK`) - * Thread-safe mode set to multi-threaded; - * Use pread64/pwrite64 for disk I/O; - * Other options from official Android source; - * **For armeabi-v7a targets**, generate Thumb-2 code. (`-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3`) - -## How to Build SQLCipher for MMDB - -```shell -$ CFLAGS='-I/path/to/openssl/include -Os -mthumb \ --fPIC -fPIE -pie \ --DPBKDF2_ITER=4000 \ --DDEFAULT_CIPHER_FLAGS=CIPHER_FLAG_LE_PGNO \ --DUSE_PREAD64=1 \ --DSQLITE_ENABLE_FTS3_TOKENIZER \ --DSQLITE_HAS_CODEC \ --DOMIT_MEMLOCK \ --DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ --DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 \ --DSQLITE_DEFAULT_FILE_PERMISSIONS=0600 \ --DSQLITE_ENABLE_UNLOCK_NOTIFY' -$ LDFLAGS='-L/path/to/openssl/lib -fPIE -pie' - -$ ./configure --host=arm-linux-androideabi --prefix='/path/to/install' \ - --disable-shared --enable-fts3 --enable-fts4 --enable-tempstore=always \ - --enable-threadsafe=multi -$ make -j4 -$ make install -``` \ No newline at end of file From 86fcc4877a1086a911b5797f4afc1dbf082c0c63 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Thu, 23 Feb 2017 17:16:05 +0800 Subject: [PATCH 24/94] Add "sqlite3session.h" to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7ecdac7960..79f41d65ab 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ xcuserdata/* /sqlite3.pc /sqlcipher.pc /sqlite3ext.h +/sqlite3session.h /libsqlcipher.la /fts5.c /fts5.h From 18bfbc4697ce00bcf9fafa85a16a18a2b381beb0 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Thu, 23 Feb 2017 17:28:05 +0800 Subject: [PATCH 25/94] Try reading KDF salt from file header again before generating new salt. The salt may have been initialized by another connection already. This fixes problems on connection pooling. --- src/crypto_impl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index dbe6403a51..f651a5939d 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -924,8 +924,14 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null - if(ctx->need_kdf_salt) { - if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) return SQLITE_ERROR; + if (ctx->need_kdf_salt) { + /* Try reading KDF salt from file header again before generating new salt. + The salt may have been initialized by another connection already. */ + sqlite3_file *fd = sqlite3PagerFile(ctx->pBt->pBt->pPager); + + if (sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK && + ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) + return SQLITE_ERROR; ctx->need_kdf_salt = 0; } if (c_ctx->pass_sz == ((c_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, c_ctx->key_sz * 2)) { From c7b83456e9401d9c3e3d52dbafa3814d9ea630e0 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 8 Mar 2017 17:38:20 +0800 Subject: [PATCH 26/94] Add non-amagalation xcodeproj --- .../project.pbxproj | 1060 +++++++++++++++++ src/backup.c | 3 + src/crypto.h | 22 + src/crypto_impl.c | 5 +- 4 files changed, 1089 insertions(+), 1 deletion(-) create mode 100644 sqlcipher-preprocessed.xcodeproj/project.pbxproj diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..ef4ab39ce7 --- /dev/null +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -0,0 +1,1060 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + 23121C271E6FFEFA0012B45E /* configure */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 23121C281E6FFEFA0012B45E /* Build configuration list for PBXAggregateTarget "configure" */; + buildPhases = ( + 23121C2B1E6FFF020012B45E /* ShellScript */, + ); + dependencies = ( + ); + name = configure; + productName = configure; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 23121B7D1E6FF93D0012B45E /* keywordhash.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AEB1E6FF93D0012B45E /* keywordhash.h */; }; + 23121B7E1E6FF93D0012B45E /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AEC1E6FF93D0012B45E /* callback.c */; }; + 23121B7F1E6FF93D0012B45E /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AED1E6FF93D0012B45E /* loadext.c */; }; + 23121B801E6FF93D0012B45E /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AEE1E6FF93D0012B45E /* rowset.c */; }; + 23121B811E6FF93D0012B45E /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AEF1E6FF93D0012B45E /* treeview.c */; }; + 23121B821E6FF93D0012B45E /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF01E6FF93D0012B45E /* userauth.c */; }; + 23121B831E6FF93D0012B45E /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF11E6FF93D0012B45E /* vtab.c */; }; + 23121B841E6FF93D0012B45E /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF21E6FF93D0012B45E /* btmutex.c */; }; + 23121B851E6FF93D0012B45E /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF31E6FF93D0012B45E /* btree.c */; }; + 23121B861E6FF93D0012B45E /* btree.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AF41E6FF93D0012B45E /* btree.h */; }; + 23121B871E6FF93D0012B45E /* btreeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AF51E6FF93D0012B45E /* btreeInt.h */; }; + 23121B881E6FF93D0012B45E /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF71E6FF93D0012B45E /* fts5.c */; }; + 23121B891E6FF93D0012B45E /* fts5.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AF81E6FF93D0012B45E /* fts5.h */; }; + 23121B8A1E6FF93D0012B45E /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF91E6FF93D0012B45E /* fts3_aux.c */; }; + 23121B8B1E6FF93D0012B45E /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFA1E6FF93D0012B45E /* fts3_expr.c */; }; + 23121B8C1E6FF93D0012B45E /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFB1E6FF93D0012B45E /* fts3_hash.c */; }; + 23121B8D1E6FF93D0012B45E /* fts3_hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AFC1E6FF93D0012B45E /* fts3_hash.h */; }; + 23121B8E1E6FF93D0012B45E /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFD1E6FF93D0012B45E /* fts3_icu.c */; }; + 23121B8F1E6FF93D0012B45E /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFE1E6FF93D0012B45E /* fts3_porter.c */; }; + 23121B901E6FF93D0012B45E /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFF1E6FF93D0012B45E /* fts3_snippet.c */; }; + 23121B911E6FF93D0012B45E /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B001E6FF93D0012B45E /* fts3_tokenize_vtab.c */; }; + 23121B921E6FF93D0012B45E /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B011E6FF93D0012B45E /* fts3_tokenizer.c */; }; + 23121B931E6FF93D0012B45E /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B021E6FF93D0012B45E /* fts3_tokenizer.h */; }; + 23121B941E6FF93D0012B45E /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B031E6FF93D0012B45E /* fts3_tokenizer1.c */; }; + 23121B951E6FF93D0012B45E /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B041E6FF93D0012B45E /* fts3_unicode.c */; }; + 23121B961E6FF93D0012B45E /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B051E6FF93D0012B45E /* fts3_unicode2.c */; }; + 23121B971E6FF93D0012B45E /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B061E6FF93D0012B45E /* fts3_write.c */; }; + 23121B981E6FF93D0012B45E /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B071E6FF93D0012B45E /* fts3.c */; }; + 23121B991E6FF93D0012B45E /* fts3.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B081E6FF93D0012B45E /* fts3.h */; }; + 23121B9A1E6FF93D0012B45E /* fts3Int.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B091E6FF93D0012B45E /* fts3Int.h */; }; + 23121B9B1E6FF93D0012B45E /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0B1E6FF93D0012B45E /* backup.c */; }; + 23121B9C1E6FF93D0012B45E /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0C1E6FF93D0012B45E /* legacy.c */; }; + 23121B9D1E6FF93D0012B45E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0D1E6FF93D0012B45E /* main.c */; }; + 23121B9E1E6FF93D0012B45E /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0E1E6FF93D0012B45E /* notify.c */; }; + 23121B9F1E6FF93D0012B45E /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0F1E6FF93D0012B45E /* vdbeapi.c */; }; + 23121BA01E6FF93D0012B45E /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B101E6FF93D0012B45E /* table.c */; }; + 23121BA11E6FF93D0012B45E /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B111E6FF93D0012B45E /* wal.c */; }; + 23121BA21E6FF93D0012B45E /* wal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B121E6FF93D0012B45E /* wal.h */; }; + 23121BA31E6FF93D0012B45E /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B131E6FF93D0012B45E /* status.c */; }; + 23121BA41E6FF93D0012B45E /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B141E6FF93D0012B45E /* prepare.c */; }; + 23121BA51E6FF93D0012B45E /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B161E6FF93D0012B45E /* malloc.c */; }; + 23121BA61E6FF93D0012B45E /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B171E6FF93D0012B45E /* mem0.c */; }; + 23121BA71E6FF93D0012B45E /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B181E6FF93D0012B45E /* mem1.c */; }; + 23121BA81E6FF93D0012B45E /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B191E6FF93D0012B45E /* mem2.c */; }; + 23121BA91E6FF93D0012B45E /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1A1E6FF93D0012B45E /* mem3.c */; }; + 23121BAA1E6FF93D0012B45E /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1B1E6FF93D0012B45E /* mem5.c */; }; + 23121BAB1E6FF93D0012B45E /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1C1E6FF93D0012B45E /* memjournal.c */; }; + 23121BAC1E6FF93D0012B45E /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1E1E6FF93D0012B45E /* mutex_unix.c */; }; + 23121BAD1E6FF93D0012B45E /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1F1E6FF93D0012B45E /* mutex.c */; }; + 23121BAE1E6FF93D0012B45E /* mutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B201E6FF93D0012B45E /* mutex.h */; }; + 23121BAF1E6FF93D0012B45E /* os_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B211E6FF93D0012B45E /* os_common.h */; }; + 23121BB01E6FF93D0012B45E /* os_setup.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B221E6FF93D0012B45E /* os_setup.h */; }; + 23121BB11E6FF93D0012B45E /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B231E6FF93D0012B45E /* os_unix.c */; }; + 23121BB21E6FF93D0012B45E /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B241E6FF93D0012B45E /* os.c */; }; + 23121BB31E6FF93D0012B45E /* os.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B251E6FF93D0012B45E /* os.h */; }; + 23121BB41E6FF93D0012B45E /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B261E6FF93D0012B45E /* threads.c */; }; + 23121BB51E6FF93D0012B45E /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B281E6FF93D0012B45E /* bitvec.c */; }; + 23121BB61E6FF93D0012B45E /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B291E6FF93D0012B45E /* pager.c */; }; + 23121BB71E6FF93D0012B45E /* pager.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B2A1E6FF93D0012B45E /* pager.h */; }; + 23121BB81E6FF93D0012B45E /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B2B1E6FF93D0012B45E /* pcache.c */; }; + 23121BB91E6FF93D0012B45E /* pcache.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B2C1E6FF93D0012B45E /* pcache.h */; }; + 23121BBA1E6FF93D0012B45E /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B2D1E6FF93D0012B45E /* pcache1.c */; }; + 23121BBB1E6FF93D0012B45E /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B2F1E6FF93D0012B45E /* rtree.c */; }; + 23121BBC1E6FF93D0012B45E /* rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B301E6FF93D0012B45E /* rtree.h */; }; + 23121BBD1E6FF93D0012B45E /* sqlite3rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B311E6FF93D0012B45E /* sqlite3rtree.h */; }; + 23121BBE1E6FF93D0012B45E /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B331E6FF93D0012B45E /* complete.c */; }; + 23121BBF1E6FF93D0012B45E /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B341E6FF93D0012B45E /* tokenize.c */; }; + 23121BC01E6FF93D0012B45E /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B361E6FF93D0012B45E /* resolve.c */; }; + 23121BC11E6FF93D0012B45E /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B371E6FF93D0012B45E /* parse.c */; }; + 23121BC21E6FF93D0012B45E /* parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B381E6FF93D0012B45E /* parse.h */; }; + 23121BC31E6FF93D0012B45E /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3A1E6FF93D0012B45E /* analyze.c */; }; + 23121BC41E6FF93D0012B45E /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3B1E6FF93D0012B45E /* func.c */; }; + 23121BC51E6FF93D0012B45E /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3C1E6FF93D0012B45E /* wherecode.c */; }; + 23121BC61E6FF93D0012B45E /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3D1E6FF93D0012B45E /* whereexpr.c */; }; + 23121BC71E6FF93D0012B45E /* whereInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B3E1E6FF93D0012B45E /* whereInt.h */; }; + 23121BC81E6FF93D0012B45E /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3F1E6FF93D0012B45E /* alter.c */; }; + 23121BC91E6FF93D0012B45E /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B401E6FF93D0012B45E /* attach.c */; }; + 23121BCA1E6FF93D0012B45E /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B411E6FF93D0012B45E /* auth.c */; }; + 23121BCB1E6FF93D0012B45E /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B421E6FF93D0012B45E /* build.c */; }; + 23121BCC1E6FF93D0012B45E /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B431E6FF93D0012B45E /* delete.c */; }; + 23121BCD1E6FF93D0012B45E /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B441E6FF93D0012B45E /* expr.c */; }; + 23121BCE1E6FF93D0012B45E /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B451E6FF93D0012B45E /* insert.c */; }; + 23121BCF1E6FF93D0012B45E /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B461E6FF93D0012B45E /* pragma.c */; }; + 23121BD01E6FF93D0012B45E /* pragma.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B471E6FF93D0012B45E /* pragma.h */; }; + 23121BD11E6FF93D0012B45E /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B481E6FF93D0012B45E /* select.c */; }; + 23121BD21E6FF93D0012B45E /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B491E6FF93D0012B45E /* trigger.c */; }; + 23121BD31E6FF93D0012B45E /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4A1E6FF93D0012B45E /* update.c */; }; + 23121BD41E6FF93D0012B45E /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4B1E6FF93D0012B45E /* vacuum.c */; }; + 23121BD51E6FF93D0012B45E /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4C1E6FF93D0012B45E /* walker.c */; }; + 23121BD61E6FF93D0012B45E /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4D1E6FF93D0012B45E /* where.c */; }; + 23121BD71E6FF93D0012B45E /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4E1E6FF93D0012B45E /* opcodes.c */; }; + 23121BD81E6FF93D0012B45E /* opcodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B4F1E6FF93D0012B45E /* opcodes.h */; }; + 23121BD91E6FF93D0012B45E /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B521E6FF93D0012B45E /* sqlite3.h */; }; + 23121BDA1E6FF93D0012B45E /* sqlite3userauth.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B531E6FF93D0012B45E /* sqlite3userauth.h */; }; + 23121BDB1E6FF93D0012B45E /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B541E6FF93D0012B45E /* sqlite3rbu.c */; }; + 23121BDC1E6FF93D0012B45E /* sqlite3rbu.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B551E6FF93D0012B45E /* sqlite3rbu.h */; }; + 23121BDD1E6FF93D0012B45E /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B561E6FF93D0012B45E /* json1.c */; }; + 23121BDE1E6FF93D0012B45E /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B571E6FF93D0012B45E /* icu.c */; }; + 23121BDF1E6FF93D0012B45E /* sqliteicu.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B581E6FF93D0012B45E /* sqliteicu.h */; }; + 23121BE01E6FF93D0012B45E /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B591E6FF93D0012B45E /* global.c */; }; + 23121BE11E6FF93D0012B45E /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5A1E6FF93D0012B45E /* ctime.c */; }; + 23121BE21E6FF93D0012B45E /* hwtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B5B1E6FF93D0012B45E /* hwtime.h */; }; + 23121BE31E6FF93D0012B45E /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5C1E6FF93D0012B45E /* date.c */; }; + 23121BE41E6FF93D0012B45E /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5D1E6FF93D0012B45E /* dbstat.c */; }; + 23121BE51E6FF93D0012B45E /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5E1E6FF93D0012B45E /* fault.c */; }; + 23121BE61E6FF93D0012B45E /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5F1E6FF93D0012B45E /* fkey.c */; }; + 23121BE71E6FF93D0012B45E /* sqliteInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B601E6FF93D0012B45E /* sqliteInt.h */; }; + 23121BE81E6FF93D0012B45E /* sqliteLimit.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B611E6FF93D0012B45E /* sqliteLimit.h */; }; + 23121BE91E6FF93D0012B45E /* sqlite3ext.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B621E6FF93D0012B45E /* sqlite3ext.h */; }; + 23121BEA1E6FF93D0012B45E /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B631E6FF93D0012B45E /* hash.c */; }; + 23121BEB1E6FF93D0012B45E /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B641E6FF93D0012B45E /* hash.h */; }; + 23121BEC1E6FF93D0012B45E /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B651E6FF93D0012B45E /* printf.c */; }; + 23121BED1E6FF93D0012B45E /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B661E6FF93D0012B45E /* random.c */; }; + 23121BEE1E6FF93D0012B45E /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B671E6FF93D0012B45E /* utf.c */; }; + 23121BEF1E6FF93D0012B45E /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B681E6FF93D0012B45E /* util.c */; }; + 23121BF01E6FF93D0012B45E /* crypto_custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6A1E6FF93D0012B45E /* crypto_custom.c */; }; + 23121BF11E6FF93D0012B45E /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6B1E6FF93D0012B45E /* vdbe.c */; }; + 23121BF21E6FF93D0012B45E /* vdbe.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B6C1E6FF93D0012B45E /* vdbe.h */; }; + 23121BF31E6FF93D0012B45E /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6D1E6FF93D0012B45E /* vdbeaux.c */; }; + 23121BF41E6FF93D0012B45E /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6E1E6FF93D0012B45E /* vdbeblob.c */; }; + 23121BF51E6FF93D0012B45E /* vdbeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B6F1E6FF93D0012B45E /* vdbeInt.h */; }; + 23121BF61E6FF93D0012B45E /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B701E6FF93D0012B45E /* vdbemem.c */; }; + 23121BF71E6FF93D0012B45E /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B711E6FF93D0012B45E /* vdbesort.c */; }; + 23121BF81E6FF93D0012B45E /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B721E6FF93D0012B45E /* vdbetrace.c */; }; + 23121BF91E6FF93D0012B45E /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B741E6FF93D0012B45E /* crypto.c */; }; + 23121BFA1E6FF93D0012B45E /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B751E6FF93D0012B45E /* crypto.h */; }; + 23121BFB1E6FF93D0012B45E /* sqlcipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B761E6FF93D0012B45E /* sqlcipher.h */; }; + 23121BFC1E6FF93D0012B45E /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B771E6FF93D0012B45E /* crypto_cc.c */; }; + 23121BFD1E6FF93D0012B45E /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B781E6FF93D0012B45E /* crypto_impl.c */; }; + 23121BFE1E6FF93D0012B45E /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B791E6FF93D0012B45E /* crypto_libtomcrypt.c */; }; + 23121BFF1E6FF93D0012B45E /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B7A1E6FF93D0012B45E /* crypto_openssl.c */; }; + 23121C081E6FFA890012B45E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 23121C2C1E6FFFA50012B45E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 23121C271E6FFEFA0012B45E; + remoteInfo = configure; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libsqlcipher-preprocessed.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 23121AEB1E6FF93D0012B45E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = keywordhash.h; path = ../keywordhash.h; sourceTree = ""; }; + 23121AEC1E6FF93D0012B45E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = ../src/callback.c; sourceTree = ""; }; + 23121AED1E6FF93D0012B45E /* loadext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loadext.c; path = ../src/loadext.c; sourceTree = ""; }; + 23121AEE1E6FF93D0012B45E /* rowset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rowset.c; path = ../src/rowset.c; sourceTree = ""; }; + 23121AEF1E6FF93D0012B45E /* treeview.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = treeview.c; path = ../src/treeview.c; sourceTree = ""; }; + 23121AF01E6FF93D0012B45E /* userauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = userauth.c; path = ../ext/userauth/userauth.c; sourceTree = ""; }; + 23121AF11E6FF93D0012B45E /* vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vtab.c; path = ../src/vtab.c; sourceTree = ""; }; + 23121AF21E6FF93D0012B45E /* btmutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btmutex.c; path = ../src/btmutex.c; sourceTree = ""; }; + 23121AF31E6FF93D0012B45E /* btree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btree.c; path = ../src/btree.c; sourceTree = ""; }; + 23121AF41E6FF93D0012B45E /* btree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btree.h; path = ../src/btree.h; sourceTree = ""; }; + 23121AF51E6FF93D0012B45E /* btreeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btreeInt.h; path = ../src/btreeInt.h; sourceTree = ""; }; + 23121AF71E6FF93D0012B45E /* fts5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts5.c; path = ../fts5.c; sourceTree = ""; }; + 23121AF81E6FF93D0012B45E /* fts5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts5.h; path = ../fts5.h; sourceTree = ""; }; + 23121AF91E6FF93D0012B45E /* fts3_aux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_aux.c; path = ../ext/fts3/fts3_aux.c; sourceTree = ""; }; + 23121AFA1E6FF93D0012B45E /* fts3_expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_expr.c; path = ../ext/fts3/fts3_expr.c; sourceTree = ""; }; + 23121AFB1E6FF93D0012B45E /* fts3_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_hash.c; path = ../ext/fts3/fts3_hash.c; sourceTree = ""; }; + 23121AFC1E6FF93D0012B45E /* fts3_hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_hash.h; path = ../ext/fts3/fts3_hash.h; sourceTree = ""; }; + 23121AFD1E6FF93D0012B45E /* fts3_icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_icu.c; path = ../ext/fts3/fts3_icu.c; sourceTree = ""; }; + 23121AFE1E6FF93D0012B45E /* fts3_porter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_porter.c; path = ../ext/fts3/fts3_porter.c; sourceTree = ""; }; + 23121AFF1E6FF93D0012B45E /* fts3_snippet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_snippet.c; path = ../ext/fts3/fts3_snippet.c; sourceTree = ""; }; + 23121B001E6FF93D0012B45E /* fts3_tokenize_vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenize_vtab.c; path = ../ext/fts3/fts3_tokenize_vtab.c; sourceTree = ""; }; + 23121B011E6FF93D0012B45E /* fts3_tokenizer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer.c; path = ../ext/fts3/fts3_tokenizer.c; sourceTree = ""; }; + 23121B021E6FF93D0012B45E /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ../ext/fts3/fts3_tokenizer.h; sourceTree = ""; }; + 23121B031E6FF93D0012B45E /* fts3_tokenizer1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer1.c; path = ../ext/fts3/fts3_tokenizer1.c; sourceTree = ""; }; + 23121B041E6FF93D0012B45E /* fts3_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode.c; path = ../ext/fts3/fts3_unicode.c; sourceTree = ""; }; + 23121B051E6FF93D0012B45E /* fts3_unicode2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode2.c; path = ../ext/fts3/fts3_unicode2.c; sourceTree = ""; }; + 23121B061E6FF93D0012B45E /* fts3_write.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_write.c; path = ../ext/fts3/fts3_write.c; sourceTree = ""; }; + 23121B071E6FF93D0012B45E /* fts3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3.c; path = ../ext/fts3/fts3.c; sourceTree = ""; }; + 23121B081E6FF93D0012B45E /* fts3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3.h; path = ../ext/fts3/fts3.h; sourceTree = ""; }; + 23121B091E6FF93D0012B45E /* fts3Int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3Int.h; path = ../ext/fts3/fts3Int.h; sourceTree = ""; }; + 23121B0B1E6FF93D0012B45E /* backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = backup.c; path = ../src/backup.c; sourceTree = ""; }; + 23121B0C1E6FF93D0012B45E /* legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = legacy.c; path = ../src/legacy.c; sourceTree = ""; }; + 23121B0D1E6FF93D0012B45E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../src/main.c; sourceTree = ""; }; + 23121B0E1E6FF93D0012B45E /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = ../src/notify.c; sourceTree = ""; }; + 23121B0F1E6FF93D0012B45E /* vdbeapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeapi.c; path = ../src/vdbeapi.c; sourceTree = ""; }; + 23121B101E6FF93D0012B45E /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = table.c; path = ../src/table.c; sourceTree = ""; }; + 23121B111E6FF93D0012B45E /* wal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wal.c; path = ../src/wal.c; sourceTree = ""; }; + 23121B121E6FF93D0012B45E /* wal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wal.h; path = ../src/wal.h; sourceTree = ""; }; + 23121B131E6FF93D0012B45E /* status.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = status.c; path = ../src/status.c; sourceTree = ""; }; + 23121B141E6FF93D0012B45E /* prepare.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prepare.c; path = ../src/prepare.c; sourceTree = ""; }; + 23121B161E6FF93D0012B45E /* malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = malloc.c; path = ../src/malloc.c; sourceTree = ""; }; + 23121B171E6FF93D0012B45E /* mem0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem0.c; path = ../src/mem0.c; sourceTree = ""; }; + 23121B181E6FF93D0012B45E /* mem1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem1.c; path = ../src/mem1.c; sourceTree = ""; }; + 23121B191E6FF93D0012B45E /* mem2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem2.c; path = ../src/mem2.c; sourceTree = ""; }; + 23121B1A1E6FF93D0012B45E /* mem3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem3.c; path = ../src/mem3.c; sourceTree = ""; }; + 23121B1B1E6FF93D0012B45E /* mem5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem5.c; path = ../src/mem5.c; sourceTree = ""; }; + 23121B1C1E6FF93D0012B45E /* memjournal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memjournal.c; path = ../src/memjournal.c; sourceTree = ""; }; + 23121B1E1E6FF93D0012B45E /* mutex_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_unix.c; path = ../src/mutex_unix.c; sourceTree = ""; }; + 23121B1F1E6FF93D0012B45E /* mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex.c; path = ../src/mutex.c; sourceTree = ""; }; + 23121B201E6FF93D0012B45E /* mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex.h; path = ../src/mutex.h; sourceTree = ""; }; + 23121B211E6FF93D0012B45E /* os_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_common.h; path = ../src/os_common.h; sourceTree = ""; }; + 23121B221E6FF93D0012B45E /* os_setup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_setup.h; path = ../src/os_setup.h; sourceTree = ""; }; + 23121B231E6FF93D0012B45E /* os_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_unix.c; path = ../src/os_unix.c; sourceTree = ""; }; + 23121B241E6FF93D0012B45E /* os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os.c; path = ../src/os.c; sourceTree = ""; }; + 23121B251E6FF93D0012B45E /* os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os.h; path = ../src/os.h; sourceTree = ""; }; + 23121B261E6FF93D0012B45E /* threads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threads.c; path = ../src/threads.c; sourceTree = ""; }; + 23121B281E6FF93D0012B45E /* bitvec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitvec.c; path = ../src/bitvec.c; sourceTree = ""; }; + 23121B291E6FF93D0012B45E /* pager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pager.c; path = ../src/pager.c; sourceTree = ""; }; + 23121B2A1E6FF93D0012B45E /* pager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pager.h; path = ../src/pager.h; sourceTree = ""; }; + 23121B2B1E6FF93D0012B45E /* pcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache.c; path = ../src/pcache.c; sourceTree = ""; }; + 23121B2C1E6FF93D0012B45E /* pcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pcache.h; path = ../src/pcache.h; sourceTree = ""; }; + 23121B2D1E6FF93D0012B45E /* pcache1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache1.c; path = ../src/pcache1.c; sourceTree = ""; }; + 23121B2F1E6FF93D0012B45E /* rtree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rtree.c; path = ../ext/rtree/rtree.c; sourceTree = ""; }; + 23121B301E6FF93D0012B45E /* rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rtree.h; path = ../ext/rtree/rtree.h; sourceTree = ""; }; + 23121B311E6FF93D0012B45E /* sqlite3rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rtree.h; path = ../ext/rtree/sqlite3rtree.h; sourceTree = ""; }; + 23121B331E6FF93D0012B45E /* complete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = complete.c; path = ../src/complete.c; sourceTree = ""; }; + 23121B341E6FF93D0012B45E /* tokenize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tokenize.c; path = ../src/tokenize.c; sourceTree = ""; }; + 23121B361E6FF93D0012B45E /* resolve.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = resolve.c; path = ../src/resolve.c; sourceTree = ""; }; + 23121B371E6FF93D0012B45E /* parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parse.c; path = ../parse.c; sourceTree = ""; }; + 23121B381E6FF93D0012B45E /* parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parse.h; path = ../parse.h; sourceTree = ""; }; + 23121B3A1E6FF93D0012B45E /* analyze.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = analyze.c; path = ../src/analyze.c; sourceTree = ""; }; + 23121B3B1E6FF93D0012B45E /* func.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = func.c; path = ../src/func.c; sourceTree = ""; }; + 23121B3C1E6FF93D0012B45E /* wherecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wherecode.c; path = ../src/wherecode.c; sourceTree = ""; }; + 23121B3D1E6FF93D0012B45E /* whereexpr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = whereexpr.c; path = ../src/whereexpr.c; sourceTree = ""; }; + 23121B3E1E6FF93D0012B45E /* whereInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = whereInt.h; path = ../src/whereInt.h; sourceTree = ""; }; + 23121B3F1E6FF93D0012B45E /* alter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alter.c; path = ../src/alter.c; sourceTree = ""; }; + 23121B401E6FF93D0012B45E /* attach.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = attach.c; path = ../src/attach.c; sourceTree = ""; }; + 23121B411E6FF93D0012B45E /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = ../src/auth.c; sourceTree = ""; }; + 23121B421E6FF93D0012B45E /* build.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = build.c; path = ../src/build.c; sourceTree = ""; }; + 23121B431E6FF93D0012B45E /* delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = delete.c; path = ../src/delete.c; sourceTree = ""; }; + 23121B441E6FF93D0012B45E /* expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = expr.c; path = ../src/expr.c; sourceTree = ""; }; + 23121B451E6FF93D0012B45E /* insert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = insert.c; path = ../src/insert.c; sourceTree = ""; }; + 23121B461E6FF93D0012B45E /* pragma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pragma.c; path = ../src/pragma.c; sourceTree = ""; }; + 23121B471E6FF93D0012B45E /* pragma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pragma.h; path = ../src/pragma.h; sourceTree = ""; }; + 23121B481E6FF93D0012B45E /* select.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = select.c; path = ../src/select.c; sourceTree = ""; }; + 23121B491E6FF93D0012B45E /* trigger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trigger.c; path = ../src/trigger.c; sourceTree = ""; }; + 23121B4A1E6FF93D0012B45E /* update.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = update.c; path = ../src/update.c; sourceTree = ""; }; + 23121B4B1E6FF93D0012B45E /* vacuum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vacuum.c; path = ../src/vacuum.c; sourceTree = ""; }; + 23121B4C1E6FF93D0012B45E /* walker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = walker.c; path = ../src/walker.c; sourceTree = ""; }; + 23121B4D1E6FF93D0012B45E /* where.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = where.c; path = ../src/where.c; sourceTree = ""; }; + 23121B4E1E6FF93D0012B45E /* opcodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = opcodes.c; path = ../opcodes.c; sourceTree = ""; }; + 23121B4F1E6FF93D0012B45E /* opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = opcodes.h; path = ../opcodes.h; sourceTree = ""; }; + 23121B521E6FF93D0012B45E /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3.h; path = ../sqlite3.h; sourceTree = ""; }; + 23121B531E6FF93D0012B45E /* sqlite3userauth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3userauth.h; path = ../ext/userauth/sqlite3userauth.h; sourceTree = ""; }; + 23121B541E6FF93D0012B45E /* sqlite3rbu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sqlite3rbu.c; path = ../ext/rbu/sqlite3rbu.c; sourceTree = ""; }; + 23121B551E6FF93D0012B45E /* sqlite3rbu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rbu.h; path = ../ext/rbu/sqlite3rbu.h; sourceTree = ""; }; + 23121B561E6FF93D0012B45E /* json1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = json1.c; path = ../ext/misc/json1.c; sourceTree = ""; }; + 23121B571E6FF93D0012B45E /* icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = icu.c; path = ../ext/icu/icu.c; sourceTree = ""; }; + 23121B581E6FF93D0012B45E /* sqliteicu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteicu.h; path = ../ext/icu/sqliteicu.h; sourceTree = ""; }; + 23121B591E6FF93D0012B45E /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = global.c; path = ../src/global.c; sourceTree = ""; }; + 23121B5A1E6FF93D0012B45E /* ctime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctime.c; path = ../src/ctime.c; sourceTree = ""; }; + 23121B5B1E6FF93D0012B45E /* hwtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwtime.h; path = ../src/hwtime.h; sourceTree = ""; }; + 23121B5C1E6FF93D0012B45E /* date.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = date.c; path = ../src/date.c; sourceTree = ""; }; + 23121B5D1E6FF93D0012B45E /* dbstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dbstat.c; path = ../src/dbstat.c; sourceTree = ""; }; + 23121B5E1E6FF93D0012B45E /* fault.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fault.c; path = ../src/fault.c; sourceTree = ""; }; + 23121B5F1E6FF93D0012B45E /* fkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fkey.c; path = ../src/fkey.c; sourceTree = ""; }; + 23121B601E6FF93D0012B45E /* sqliteInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteInt.h; path = ../src/sqliteInt.h; sourceTree = ""; }; + 23121B611E6FF93D0012B45E /* sqliteLimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteLimit.h; path = ../src/sqliteLimit.h; sourceTree = ""; }; + 23121B621E6FF93D0012B45E /* sqlite3ext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3ext.h; path = ../src/sqlite3ext.h; sourceTree = ""; }; + 23121B631E6FF93D0012B45E /* hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hash.c; path = ../src/hash.c; sourceTree = ""; }; + 23121B641E6FF93D0012B45E /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hash.h; path = ../src/hash.h; sourceTree = ""; }; + 23121B651E6FF93D0012B45E /* printf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = printf.c; path = ../src/printf.c; sourceTree = ""; }; + 23121B661E6FF93D0012B45E /* random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = random.c; path = ../src/random.c; sourceTree = ""; }; + 23121B671E6FF93D0012B45E /* utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf.c; path = ../src/utf.c; sourceTree = ""; }; + 23121B681E6FF93D0012B45E /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = ../src/util.c; sourceTree = ""; }; + 23121B6A1E6FF93D0012B45E /* crypto_custom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_custom.c; path = ../src/crypto_custom.c; sourceTree = ""; }; + 23121B6B1E6FF93D0012B45E /* vdbe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbe.c; path = ../src/vdbe.c; sourceTree = ""; }; + 23121B6C1E6FF93D0012B45E /* vdbe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbe.h; path = ../src/vdbe.h; sourceTree = ""; }; + 23121B6D1E6FF93D0012B45E /* vdbeaux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeaux.c; path = ../src/vdbeaux.c; sourceTree = ""; }; + 23121B6E1E6FF93D0012B45E /* vdbeblob.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeblob.c; path = ../src/vdbeblob.c; sourceTree = ""; }; + 23121B6F1E6FF93D0012B45E /* vdbeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbeInt.h; path = ../src/vdbeInt.h; sourceTree = ""; }; + 23121B701E6FF93D0012B45E /* vdbemem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbemem.c; path = ../src/vdbemem.c; sourceTree = ""; }; + 23121B711E6FF93D0012B45E /* vdbesort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbesort.c; path = ../src/vdbesort.c; sourceTree = ""; }; + 23121B721E6FF93D0012B45E /* vdbetrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbetrace.c; path = ../src/vdbetrace.c; sourceTree = ""; }; + 23121B741E6FF93D0012B45E /* crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto.c; path = ../src/crypto.c; sourceTree = ""; }; + 23121B751E6FF93D0012B45E /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = ../src/crypto.h; sourceTree = ""; }; + 23121B761E6FF93D0012B45E /* sqlcipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlcipher.h; path = ../src/sqlcipher.h; sourceTree = ""; }; + 23121B771E6FF93D0012B45E /* crypto_cc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_cc.c; path = ../src/crypto_cc.c; sourceTree = ""; }; + 23121B781E6FF93D0012B45E /* crypto_impl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_impl.c; path = ../src/crypto_impl.c; sourceTree = ""; }; + 23121B791E6FF93D0012B45E /* crypto_libtomcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_libtomcrypt.c; path = ../src/crypto_libtomcrypt.c; sourceTree = ""; }; + 23121B7A1E6FF93D0012B45E /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_openssl.c; path = ../src/crypto_openssl.c; sourceTree = ""; }; + 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 23121AE11E6FF9110012B45E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 23121C081E6FFA890012B45E /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 23121ADB1E6FF9110012B45E = { + isa = PBXGroup; + children = ( + 23121B7C1E6FF93D0012B45E /* src */, + 23121C061E6FFA890012B45E /* Frameworks */, + 23121AE51E6FF9110012B45E /* Products */, + ); + sourceTree = ""; + }; + 23121AE51E6FF9110012B45E /* Products */ = { + isa = PBXGroup; + children = ( + 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */, + ); + name = Products; + sourceTree = ""; + }; + 23121AF61E6FF93D0012B45E /* btree */ = { + isa = PBXGroup; + children = ( + 23121AF21E6FF93D0012B45E /* btmutex.c */, + 23121AF31E6FF93D0012B45E /* btree.c */, + 23121AF41E6FF93D0012B45E /* btree.h */, + 23121AF51E6FF93D0012B45E /* btreeInt.h */, + ); + name = btree; + sourceTree = ""; + }; + 23121B0A1E6FF93D0012B45E /* fts */ = { + isa = PBXGroup; + children = ( + 23121AF71E6FF93D0012B45E /* fts5.c */, + 23121AF81E6FF93D0012B45E /* fts5.h */, + 23121AF91E6FF93D0012B45E /* fts3_aux.c */, + 23121AFA1E6FF93D0012B45E /* fts3_expr.c */, + 23121AFB1E6FF93D0012B45E /* fts3_hash.c */, + 23121AFC1E6FF93D0012B45E /* fts3_hash.h */, + 23121AFD1E6FF93D0012B45E /* fts3_icu.c */, + 23121AFE1E6FF93D0012B45E /* fts3_porter.c */, + 23121AFF1E6FF93D0012B45E /* fts3_snippet.c */, + 23121B001E6FF93D0012B45E /* fts3_tokenize_vtab.c */, + 23121B011E6FF93D0012B45E /* fts3_tokenizer.c */, + 23121B021E6FF93D0012B45E /* fts3_tokenizer.h */, + 23121B031E6FF93D0012B45E /* fts3_tokenizer1.c */, + 23121B041E6FF93D0012B45E /* fts3_unicode.c */, + 23121B051E6FF93D0012B45E /* fts3_unicode2.c */, + 23121B061E6FF93D0012B45E /* fts3_write.c */, + 23121B071E6FF93D0012B45E /* fts3.c */, + 23121B081E6FF93D0012B45E /* fts3.h */, + 23121B091E6FF93D0012B45E /* fts3Int.h */, + ); + name = fts; + sourceTree = ""; + }; + 23121B151E6FF93D0012B45E /* interface */ = { + isa = PBXGroup; + children = ( + 23121B0B1E6FF93D0012B45E /* backup.c */, + 23121B0C1E6FF93D0012B45E /* legacy.c */, + 23121B0D1E6FF93D0012B45E /* main.c */, + 23121B0E1E6FF93D0012B45E /* notify.c */, + 23121B0F1E6FF93D0012B45E /* vdbeapi.c */, + 23121B101E6FF93D0012B45E /* table.c */, + 23121B111E6FF93D0012B45E /* wal.c */, + 23121B121E6FF93D0012B45E /* wal.h */, + 23121B131E6FF93D0012B45E /* status.c */, + 23121B141E6FF93D0012B45E /* prepare.c */, + ); + name = interface; + sourceTree = ""; + }; + 23121B1D1E6FF93D0012B45E /* memory */ = { + isa = PBXGroup; + children = ( + 23121B161E6FF93D0012B45E /* malloc.c */, + 23121B171E6FF93D0012B45E /* mem0.c */, + 23121B181E6FF93D0012B45E /* mem1.c */, + 23121B191E6FF93D0012B45E /* mem2.c */, + 23121B1A1E6FF93D0012B45E /* mem3.c */, + 23121B1B1E6FF93D0012B45E /* mem5.c */, + 23121B1C1E6FF93D0012B45E /* memjournal.c */, + ); + name = memory; + sourceTree = ""; + }; + 23121B271E6FF93D0012B45E /* os interface */ = { + isa = PBXGroup; + children = ( + 23121B1E1E6FF93D0012B45E /* mutex_unix.c */, + 23121B1F1E6FF93D0012B45E /* mutex.c */, + 23121B201E6FF93D0012B45E /* mutex.h */, + 23121B211E6FF93D0012B45E /* os_common.h */, + 23121B221E6FF93D0012B45E /* os_setup.h */, + 23121B231E6FF93D0012B45E /* os_unix.c */, + 23121B241E6FF93D0012B45E /* os.c */, + 23121B251E6FF93D0012B45E /* os.h */, + 23121B261E6FF93D0012B45E /* threads.c */, + ); + name = "os interface"; + sourceTree = ""; + }; + 23121B2E1E6FF93D0012B45E /* page */ = { + isa = PBXGroup; + children = ( + 23121B281E6FF93D0012B45E /* bitvec.c */, + 23121B291E6FF93D0012B45E /* pager.c */, + 23121B2A1E6FF93D0012B45E /* pager.h */, + 23121B2B1E6FF93D0012B45E /* pcache.c */, + 23121B2C1E6FF93D0012B45E /* pcache.h */, + 23121B2D1E6FF93D0012B45E /* pcache1.c */, + ); + name = page; + sourceTree = ""; + }; + 23121B321E6FF93D0012B45E /* rtree */ = { + isa = PBXGroup; + children = ( + 23121B2F1E6FF93D0012B45E /* rtree.c */, + 23121B301E6FF93D0012B45E /* rtree.h */, + 23121B311E6FF93D0012B45E /* sqlite3rtree.h */, + ); + name = rtree; + sourceTree = ""; + }; + 23121B351E6FF93D0012B45E /* tokenizer */ = { + isa = PBXGroup; + children = ( + 23121B331E6FF93D0012B45E /* complete.c */, + 23121B341E6FF93D0012B45E /* tokenize.c */, + ); + name = tokenizer; + sourceTree = ""; + }; + 23121B391E6FF93D0012B45E /* parser */ = { + isa = PBXGroup; + children = ( + 23121B361E6FF93D0012B45E /* resolve.c */, + 23121B371E6FF93D0012B45E /* parse.c */, + 23121B381E6FF93D0012B45E /* parse.h */, + ); + name = parser; + sourceTree = ""; + }; + 23121B501E6FF93D0012B45E /* code generator */ = { + isa = PBXGroup; + children = ( + 23121B3A1E6FF93D0012B45E /* analyze.c */, + 23121B3B1E6FF93D0012B45E /* func.c */, + 23121B3C1E6FF93D0012B45E /* wherecode.c */, + 23121B3D1E6FF93D0012B45E /* whereexpr.c */, + 23121B3E1E6FF93D0012B45E /* whereInt.h */, + 23121B3F1E6FF93D0012B45E /* alter.c */, + 23121B401E6FF93D0012B45E /* attach.c */, + 23121B411E6FF93D0012B45E /* auth.c */, + 23121B421E6FF93D0012B45E /* build.c */, + 23121B431E6FF93D0012B45E /* delete.c */, + 23121B441E6FF93D0012B45E /* expr.c */, + 23121B451E6FF93D0012B45E /* insert.c */, + 23121B461E6FF93D0012B45E /* pragma.c */, + 23121B471E6FF93D0012B45E /* pragma.h */, + 23121B481E6FF93D0012B45E /* select.c */, + 23121B491E6FF93D0012B45E /* trigger.c */, + 23121B4A1E6FF93D0012B45E /* update.c */, + 23121B4B1E6FF93D0012B45E /* vacuum.c */, + 23121B4C1E6FF93D0012B45E /* walker.c */, + 23121B4D1E6FF93D0012B45E /* where.c */, + 23121B4E1E6FF93D0012B45E /* opcodes.c */, + 23121B4F1E6FF93D0012B45E /* opcodes.h */, + ); + name = "code generator"; + sourceTree = ""; + }; + 23121B511E6FF93D0012B45E /* sql compiler */ = { + isa = PBXGroup; + children = ( + 23121B351E6FF93D0012B45E /* tokenizer */, + 23121B391E6FF93D0012B45E /* parser */, + 23121B501E6FF93D0012B45E /* code generator */, + ); + name = "sql compiler"; + sourceTree = ""; + }; + 23121B691E6FF93D0012B45E /* utilities */ = { + isa = PBXGroup; + children = ( + 23121B521E6FF93D0012B45E /* sqlite3.h */, + 23121B531E6FF93D0012B45E /* sqlite3userauth.h */, + 23121B541E6FF93D0012B45E /* sqlite3rbu.c */, + 23121B551E6FF93D0012B45E /* sqlite3rbu.h */, + 23121B561E6FF93D0012B45E /* json1.c */, + 23121B571E6FF93D0012B45E /* icu.c */, + 23121B581E6FF93D0012B45E /* sqliteicu.h */, + 23121B591E6FF93D0012B45E /* global.c */, + 23121B5A1E6FF93D0012B45E /* ctime.c */, + 23121B5B1E6FF93D0012B45E /* hwtime.h */, + 23121B5C1E6FF93D0012B45E /* date.c */, + 23121B5D1E6FF93D0012B45E /* dbstat.c */, + 23121B5E1E6FF93D0012B45E /* fault.c */, + 23121B5F1E6FF93D0012B45E /* fkey.c */, + 23121B601E6FF93D0012B45E /* sqliteInt.h */, + 23121B611E6FF93D0012B45E /* sqliteLimit.h */, + 23121B621E6FF93D0012B45E /* sqlite3ext.h */, + 23121B631E6FF93D0012B45E /* hash.c */, + 23121B641E6FF93D0012B45E /* hash.h */, + 23121B651E6FF93D0012B45E /* printf.c */, + 23121B661E6FF93D0012B45E /* random.c */, + 23121B671E6FF93D0012B45E /* utf.c */, + 23121B681E6FF93D0012B45E /* util.c */, + ); + name = utilities; + sourceTree = ""; + }; + 23121B731E6FF93D0012B45E /* vm */ = { + isa = PBXGroup; + children = ( + 23121B6B1E6FF93D0012B45E /* vdbe.c */, + 23121B6C1E6FF93D0012B45E /* vdbe.h */, + 23121B6D1E6FF93D0012B45E /* vdbeaux.c */, + 23121B6E1E6FF93D0012B45E /* vdbeblob.c */, + 23121B6F1E6FF93D0012B45E /* vdbeInt.h */, + 23121B701E6FF93D0012B45E /* vdbemem.c */, + 23121B711E6FF93D0012B45E /* vdbesort.c */, + 23121B721E6FF93D0012B45E /* vdbetrace.c */, + ); + name = vm; + sourceTree = ""; + }; + 23121B7B1E6FF93D0012B45E /* cipher */ = { + isa = PBXGroup; + children = ( + 23121B741E6FF93D0012B45E /* crypto.c */, + 23121B751E6FF93D0012B45E /* crypto.h */, + 23121B761E6FF93D0012B45E /* sqlcipher.h */, + 23121B771E6FF93D0012B45E /* crypto_cc.c */, + 23121B781E6FF93D0012B45E /* crypto_impl.c */, + 23121B791E6FF93D0012B45E /* crypto_libtomcrypt.c */, + 23121B7A1E6FF93D0012B45E /* crypto_openssl.c */, + ); + name = cipher; + sourceTree = ""; + }; + 23121B7C1E6FF93D0012B45E /* src */ = { + isa = PBXGroup; + children = ( + 23121AEB1E6FF93D0012B45E /* keywordhash.h */, + 23121AEC1E6FF93D0012B45E /* callback.c */, + 23121AED1E6FF93D0012B45E /* loadext.c */, + 23121AEE1E6FF93D0012B45E /* rowset.c */, + 23121AEF1E6FF93D0012B45E /* treeview.c */, + 23121AF01E6FF93D0012B45E /* userauth.c */, + 23121AF11E6FF93D0012B45E /* vtab.c */, + 23121AF61E6FF93D0012B45E /* btree */, + 23121B0A1E6FF93D0012B45E /* fts */, + 23121B151E6FF93D0012B45E /* interface */, + 23121B1D1E6FF93D0012B45E /* memory */, + 23121B271E6FF93D0012B45E /* os interface */, + 23121B2E1E6FF93D0012B45E /* page */, + 23121B321E6FF93D0012B45E /* rtree */, + 23121B511E6FF93D0012B45E /* sql compiler */, + 23121B691E6FF93D0012B45E /* utilities */, + 23121B6A1E6FF93D0012B45E /* crypto_custom.c */, + 23121B731E6FF93D0012B45E /* vm */, + 23121B7B1E6FF93D0012B45E /* cipher */, + ); + name = src; + path = "sqlcipher-preprocessed"; + sourceTree = ""; + }; + 23121C061E6FFA890012B45E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 23121C071E6FFA890012B45E /* Security.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 23121AE21E6FF9110012B45E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 23121BDC1E6FF93D0012B45E /* sqlite3rbu.h in Headers */, + 23121BE71E6FF93D0012B45E /* sqliteInt.h in Headers */, + 23121BFA1E6FF93D0012B45E /* crypto.h in Headers */, + 23121BD91E6FF93D0012B45E /* sqlite3.h in Headers */, + 23121BAE1E6FF93D0012B45E /* mutex.h in Headers */, + 23121BF21E6FF93D0012B45E /* vdbe.h in Headers */, + 23121BDF1E6FF93D0012B45E /* sqliteicu.h in Headers */, + 23121B931E6FF93D0012B45E /* fts3_tokenizer.h in Headers */, + 23121BBD1E6FF93D0012B45E /* sqlite3rtree.h in Headers */, + 23121BB71E6FF93D0012B45E /* pager.h in Headers */, + 23121BDA1E6FF93D0012B45E /* sqlite3userauth.h in Headers */, + 23121BB01E6FF93D0012B45E /* os_setup.h in Headers */, + 23121BF51E6FF93D0012B45E /* vdbeInt.h in Headers */, + 23121B8D1E6FF93D0012B45E /* fts3_hash.h in Headers */, + 23121BE21E6FF93D0012B45E /* hwtime.h in Headers */, + 23121BC21E6FF93D0012B45E /* parse.h in Headers */, + 23121BD81E6FF93D0012B45E /* opcodes.h in Headers */, + 23121B9A1E6FF93D0012B45E /* fts3Int.h in Headers */, + 23121BA21E6FF93D0012B45E /* wal.h in Headers */, + 23121BE81E6FF93D0012B45E /* sqliteLimit.h in Headers */, + 23121BB31E6FF93D0012B45E /* os.h in Headers */, + 23121BE91E6FF93D0012B45E /* sqlite3ext.h in Headers */, + 23121BD01E6FF93D0012B45E /* pragma.h in Headers */, + 23121BEB1E6FF93D0012B45E /* hash.h in Headers */, + 23121B7D1E6FF93D0012B45E /* keywordhash.h in Headers */, + 23121BAF1E6FF93D0012B45E /* os_common.h in Headers */, + 23121BFB1E6FF93D0012B45E /* sqlcipher.h in Headers */, + 23121B871E6FF93D0012B45E /* btreeInt.h in Headers */, + 23121B891E6FF93D0012B45E /* fts5.h in Headers */, + 23121BB91E6FF93D0012B45E /* pcache.h in Headers */, + 23121B861E6FF93D0012B45E /* btree.h in Headers */, + 23121B991E6FF93D0012B45E /* fts3.h in Headers */, + 23121BC71E6FF93D0012B45E /* whereInt.h in Headers */, + 23121BBC1E6FF93D0012B45E /* rtree.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */ = { + isa = PBXNativeTarget; + buildConfigurationList = 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher-preprocessed" */; + buildPhases = ( + 23121AE01E6FF9110012B45E /* Sources */, + 23121AE11E6FF9110012B45E /* Frameworks */, + 23121AE21E6FF9110012B45E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + 23121C2D1E6FFFA50012B45E /* PBXTargetDependency */, + ); + name = "sqlcipher-preprocessed"; + productName = "sqlcipher-preprocessed"; + productReference = 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 23121ADC1E6FF9110012B45E /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = sanhuazhang; + TargetAttributes = { + 23121AE31E6FF9110012B45E = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + 23121C271E6FFEFA0012B45E = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 23121ADF1E6FF9110012B45E /* Build configuration list for PBXProject "sqlcipher-preprocessed" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 23121ADB1E6FF9110012B45E; + productRefGroup = 23121AE51E6FF9110012B45E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */, + 23121C271E6FFEFA0012B45E /* configure */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + 23121C2B1E6FFF020012B45E /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS=\"-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2\" --disable-amalgamation\nmake opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 23121AE01E6FF9110012B45E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 23121BCE1E6FF93D0012B45E /* insert.c in Sources */, + 23121BD71E6FF93D0012B45E /* opcodes.c in Sources */, + 23121B821E6FF93D0012B45E /* userauth.c in Sources */, + 23121B7E1E6FF93D0012B45E /* callback.c in Sources */, + 23121BB51E6FF93D0012B45E /* bitvec.c in Sources */, + 23121BF01E6FF93D0012B45E /* crypto_custom.c in Sources */, + 23121B8E1E6FF93D0012B45E /* fts3_icu.c in Sources */, + 23121BDD1E6FF93D0012B45E /* json1.c in Sources */, + 23121BEA1E6FF93D0012B45E /* hash.c in Sources */, + 23121B8F1E6FF93D0012B45E /* fts3_porter.c in Sources */, + 23121B851E6FF93D0012B45E /* btree.c in Sources */, + 23121BCC1E6FF93D0012B45E /* delete.c in Sources */, + 23121BC31E6FF93D0012B45E /* analyze.c in Sources */, + 23121BAB1E6FF93D0012B45E /* memjournal.c in Sources */, + 23121BFC1E6FF93D0012B45E /* crypto_cc.c in Sources */, + 23121BDB1E6FF93D0012B45E /* sqlite3rbu.c in Sources */, + 23121B8C1E6FF93D0012B45E /* fts3_hash.c in Sources */, + 23121BFF1E6FF93D0012B45E /* crypto_openssl.c in Sources */, + 23121BF71E6FF93D0012B45E /* vdbesort.c in Sources */, + 23121BC51E6FF93D0012B45E /* wherecode.c in Sources */, + 23121BF31E6FF93D0012B45E /* vdbeaux.c in Sources */, + 23121BA11E6FF93D0012B45E /* wal.c in Sources */, + 23121BA31E6FF93D0012B45E /* status.c in Sources */, + 23121BBF1E6FF93D0012B45E /* tokenize.c in Sources */, + 23121B901E6FF93D0012B45E /* fts3_snippet.c in Sources */, + 23121B831E6FF93D0012B45E /* vtab.c in Sources */, + 23121BEE1E6FF93D0012B45E /* utf.c in Sources */, + 23121BF91E6FF93D0012B45E /* crypto.c in Sources */, + 23121BCF1E6FF93D0012B45E /* pragma.c in Sources */, + 23121BC81E6FF93D0012B45E /* alter.c in Sources */, + 23121BA81E6FF93D0012B45E /* mem2.c in Sources */, + 23121BD21E6FF93D0012B45E /* trigger.c in Sources */, + 23121B881E6FF93D0012B45E /* fts5.c in Sources */, + 23121BF11E6FF93D0012B45E /* vdbe.c in Sources */, + 23121B981E6FF93D0012B45E /* fts3.c in Sources */, + 23121BA91E6FF93D0012B45E /* mem3.c in Sources */, + 23121BB21E6FF93D0012B45E /* os.c in Sources */, + 23121B9E1E6FF93D0012B45E /* notify.c in Sources */, + 23121BAC1E6FF93D0012B45E /* mutex_unix.c in Sources */, + 23121BBA1E6FF93D0012B45E /* pcache1.c in Sources */, + 23121BD51E6FF93D0012B45E /* walker.c in Sources */, + 23121BCB1E6FF93D0012B45E /* build.c in Sources */, + 23121BEF1E6FF93D0012B45E /* util.c in Sources */, + 23121B911E6FF93D0012B45E /* fts3_tokenize_vtab.c in Sources */, + 23121BF61E6FF93D0012B45E /* vdbemem.c in Sources */, + 23121BF41E6FF93D0012B45E /* vdbeblob.c in Sources */, + 23121BC01E6FF93D0012B45E /* resolve.c in Sources */, + 23121B7F1E6FF93D0012B45E /* loadext.c in Sources */, + 23121BA41E6FF93D0012B45E /* prepare.c in Sources */, + 23121B9F1E6FF93D0012B45E /* vdbeapi.c in Sources */, + 23121BD41E6FF93D0012B45E /* vacuum.c in Sources */, + 23121BA51E6FF93D0012B45E /* malloc.c in Sources */, + 23121BFD1E6FF93D0012B45E /* crypto_impl.c in Sources */, + 23121BE31E6FF93D0012B45E /* date.c in Sources */, + 23121BC91E6FF93D0012B45E /* attach.c in Sources */, + 23121B8B1E6FF93D0012B45E /* fts3_expr.c in Sources */, + 23121B921E6FF93D0012B45E /* fts3_tokenizer.c in Sources */, + 23121BA01E6FF93D0012B45E /* table.c in Sources */, + 23121B8A1E6FF93D0012B45E /* fts3_aux.c in Sources */, + 23121BAA1E6FF93D0012B45E /* mem5.c in Sources */, + 23121B9D1E6FF93D0012B45E /* main.c in Sources */, + 23121BE51E6FF93D0012B45E /* fault.c in Sources */, + 23121BB61E6FF93D0012B45E /* pager.c in Sources */, + 23121BFE1E6FF93D0012B45E /* crypto_libtomcrypt.c in Sources */, + 23121BB11E6FF93D0012B45E /* os_unix.c in Sources */, + 23121BBE1E6FF93D0012B45E /* complete.c in Sources */, + 23121BC61E6FF93D0012B45E /* whereexpr.c in Sources */, + 23121BDE1E6FF93D0012B45E /* icu.c in Sources */, + 23121BED1E6FF93D0012B45E /* random.c in Sources */, + 23121B951E6FF93D0012B45E /* fts3_unicode.c in Sources */, + 23121B811E6FF93D0012B45E /* treeview.c in Sources */, + 23121BE41E6FF93D0012B45E /* dbstat.c in Sources */, + 23121BD11E6FF93D0012B45E /* select.c in Sources */, + 23121B9B1E6FF93D0012B45E /* backup.c in Sources */, + 23121B971E6FF93D0012B45E /* fts3_write.c in Sources */, + 23121BD61E6FF93D0012B45E /* where.c in Sources */, + 23121BA71E6FF93D0012B45E /* mem1.c in Sources */, + 23121B961E6FF93D0012B45E /* fts3_unicode2.c in Sources */, + 23121BA61E6FF93D0012B45E /* mem0.c in Sources */, + 23121BAD1E6FF93D0012B45E /* mutex.c in Sources */, + 23121BCA1E6FF93D0012B45E /* auth.c in Sources */, + 23121BC41E6FF93D0012B45E /* func.c in Sources */, + 23121BEC1E6FF93D0012B45E /* printf.c in Sources */, + 23121BB41E6FF93D0012B45E /* threads.c in Sources */, + 23121BBB1E6FF93D0012B45E /* rtree.c in Sources */, + 23121BF81E6FF93D0012B45E /* vdbetrace.c in Sources */, + 23121BE11E6FF93D0012B45E /* ctime.c in Sources */, + 23121BE61E6FF93D0012B45E /* fkey.c in Sources */, + 23121BE01E6FF93D0012B45E /* global.c in Sources */, + 23121B801E6FF93D0012B45E /* rowset.c in Sources */, + 23121BD31E6FF93D0012B45E /* update.c in Sources */, + 23121BCD1E6FF93D0012B45E /* expr.c in Sources */, + 23121B841E6FF93D0012B45E /* btmutex.c in Sources */, + 23121B9C1E6FF93D0012B45E /* legacy.c in Sources */, + 23121B941E6FF93D0012B45E /* fts3_tokenizer1.c in Sources */, + 23121BB81E6FF93D0012B45E /* pcache.c in Sources */, + 23121BC11E6FF93D0012B45E /* parse.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 23121C2D1E6FFFA50012B45E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 23121C271E6FFEFA0012B45E /* configure */; + targetProxy = 23121C2C1E6FFFA50012B45E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 23121AE61E6FF9110012B45E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + arm64, + armv7, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + armv7, + arm64, + ); + "ARCHS[sdk=macosx*]" = ( + "$(ARCHS_STANDARD)", + i386, + x86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + SQLITE_ENABLE_FTS3, + SQLITE_ENABLE_FTS3_PARENTHESIS, + SQLITE_ENABLE_API_ARMOR, + SQLITE_OMIT_BUILTIN_TEST, + SQLITE_OMIT_AUTORESET, + SQLITE_ENABLE_UPDATE_DELETE_LIMIT, + SQLITE_ENABLE_RTREE, + "SQLITE_ENABLE_LOCKING_STYLE=1", + SQLITE_SYSTEM_MALLOC, + SQLITE_OMIT_LOAD_EXTENSION, + SQLITE_CORE, + "SQLITE_THREADSAFE=2", + "SQLITE_DEFAULT_CACHE_SIZE=250", + "SQLITE_DEFAULT_CKPTFULLFSYNC=1", + "SQLITE_DEFAULT_PAGE_SIZE=4096", + SQLITE_OMIT_SHARED_CACHE, + SQLITE_HAS_CODEC, + SQLCIPHER_CRYPTO_CC, + "USE_PREAD=1", + "SQLITE_TEMP_STORE=2", + SQLCIPHER_PREPROCESSED, + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; + VALID_ARCHS = "i386 x86_64 armv7s armv7 arm64"; + }; + name = Debug; + }; + 23121AE71E6FF9110012B45E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + armv7, + arm64, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7s, + armv7, + arm64, + ); + "ARCHS[sdk=macosx*]" = ( + "$(ARCHS_STANDARD)", + i386, + i86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + SQLITE_ENABLE_FTS3, + SQLITE_ENABLE_FTS3_PARENTHESIS, + SQLITE_ENABLE_API_ARMOR, + "$(inherited)", + SQLITE_ENABLE_RTREE, + "SQLITE_ENABLE_LOCKING_STYLE=1", + SQLITE_OMIT_LOAD_EXTENSION, + SQLITE_OMIT_BUILTIN_TEST, + SQLITE_OMIT_SHARED_CACHE, + SQLITE_OMIT_AUTORESET, + SQLITE_ENABLE_UPDATE_DELETE_LIMIT, + SQLITE_SYSTEM_MALLOC, + "SQLITE_THREADSAFE=2", + "SQLITE_DEFAULT_PAGE_SIZE=4096", + "SQLITE_DEFAULT_CKPTFULLFSYNC=1", + "SQLITE_DEFAULT_CACHE_SIZE=250", + SQLITE_CORE, + SQLITE_HAS_CODEC, + "SQLITE_TEMP_STORE=2", + SQLCIPHER_CRYPTO_CC, + "USE_PREAD=1", + SQLCIPHER_PREPROCESSED, + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; + VALID_ARCHS = "i386 x86_64 armv7s armv7 arm64"; + }; + name = Release; + }; + 23121AE91E6FF9110012B45E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 23121AEA1E6FF9110012B45E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 23121C291E6FFEFA0012B45E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 23121C2A1E6FFEFA0012B45E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 23121ADF1E6FF9110012B45E /* Build configuration list for PBXProject "sqlcipher-preprocessed" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23121AE61E6FF9110012B45E /* Debug */, + 23121AE71E6FF9110012B45E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher-preprocessed" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23121AE91E6FF9110012B45E /* Debug */, + 23121AEA1E6FF9110012B45E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 23121C281E6FFEFA0012B45E /* Build configuration list for PBXAggregateTarget "configure" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23121C291E6FFEFA0012B45E /* Debug */, + 23121C2A1E6FFEFA0012B45E /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 23121ADC1E6FF9110012B45E /* Project object */; +} diff --git a/src/backup.c b/src/backup.c index 165144d965..15a24d74f6 100644 --- a/src/backup.c +++ b/src/backup.c @@ -262,6 +262,9 @@ static int backupOnePage( /* Backup is not possible if the page size of the destination is changing ** and a codec is in use. */ +#if defined (SQLCIPHER_PREPROCESSED) + extern void *sqlite3PagerGetCodec(Pager *pPager); +#endif /* SQLCIPHER_PREPROCESSED */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ rc = SQLITE_READONLY; } diff --git a/src/crypto.h b/src/crypto.h index 1a26b700ca..41419f0c0c 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -41,6 +41,10 @@ #define SQLCIPHER_CRYPTO_OPENSSL #endif +#if defined (SQLCIPHER_PREPROCESSED) +#include "sqliteInt.h" +#endif /* SQLCIPHER_PREPROCESSED */ + #define FILE_HEADER_SZ 16 #ifndef CIPHER_VERSION @@ -154,21 +158,33 @@ static int cipher_hex2int(char c) { (c>='a' && c<='f') ? (c)-'a'+10 : 0; } +#if defined (SQLCIPHER_PREPROCESSED) +void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out){ +#else /* SQLCIPHER_PREPROCESSED */ static void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out){ +#endif /* SQLCIPHER_PREPROCESSED */ int i; for(i = 0; i < sz; i += 2){ out[i/2] = (cipher_hex2int(hex[i])<<4) | cipher_hex2int(hex[i+1]); } } +#if defined (SQLCIPHER_PREPROCESSED) +void cipher_bin2hex(const unsigned char* in, int sz, char *out) { +#else /* SQLCIPHER_PREPROCESSED */ static void cipher_bin2hex(const unsigned char* in, int sz, char *out) { +#endif /* SQLCIPHER_PREPROCESSED */ int i; for(i=0; i < sz; i++) { sqlite3_snprintf(3, out + (i*2), "%02x ", in[i]); } } +#if defined (SQLCIPHER_PREPROCESSED) +int cipher_isHex(const unsigned char *hex, int sz){ +#else /* SQLCIPHER_PREPROCESSED */ static int cipher_isHex(const unsigned char *hex, int sz){ +#endif /* SQLCIPHER_PREPROCESSED */ int i; for(i = 0; i < sz; i++) { unsigned char c = hex[i]; @@ -242,9 +258,15 @@ int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx); int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz); +#if defined (SQLCIPHER_PREPROCESSED) +int sqlcipher_codec_get_store_pass(codec_ctx *ctx); +void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); +void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); +#else /* SQLCIPHER_PREPROCESSED */ static int sqlcipher_codec_get_store_pass(codec_ctx *ctx); static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey); static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value); +#endif /* SQLCIPHER_PREPROCESSED */ int sqlcipher_codec_fips_status(codec_ctx *ctx); const char* sqlcipher_codec_get_provider_version(codec_ctx *ctx); #endif diff --git a/src/crypto_impl.c b/src/crypto_impl.c index f651a5939d..1a8c394be8 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -1186,7 +1186,10 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { assert( 1==sqlite3BtreeIsInTrans(pDest) ); assert( 1==sqlite3BtreeIsInTrans(pSrc) ); - +#if defined (SQLCIPHER_PREPROCESSED) + extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); +#endif /* SQLCIPHER_PREPROCESSED */ sqlite3CodecGetKey(db, db->nDb - 1, (void**)&key, &password_sz); sqlite3CodecAttach(db, 0, key, password_sz); sqlite3pager_get_codec(pDest->pBt->pPager, (void**)&ctx); From 89aceaf24e603a3c02dddef70c4366c2c2026883 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 8 Mar 2017 20:16:21 +0800 Subject: [PATCH 27/94] compatible for preprocess --- src/crypto.c | 34 ++++++++++++++++++++++++++++++++++ src/crypto.h | 12 ++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 2c1176e16e..a25b6cc859 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -516,6 +516,40 @@ void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) { } } +#if defined (SQLCIPHER_PREPROCESSED) +void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out){ + int i; + for(i = 0; i < sz; i += 2){ + out[i/2] = (cipher_hex2int(hex[i])<<4) | cipher_hex2int(hex[i+1]); + } +} +#endif /* SQLCIPHER_PREPROCESSED */ + +#if defined (SQLCIPHER_PREPROCESSED) +void cipher_bin2hex(const unsigned char* in, int sz, char *out) { + int i; + for(i=0; i < sz; i++) { + sqlite3_snprintf(3, out + (i*2), "%02x ", in[i]); + } +} +#endif /* SQLCIPHER_PREPROCESSED */ + +#if defined (SQLCIPHER_PREPROCESSED) +int cipher_isHex(const unsigned char *hex, int sz){ + int i; + for(i = 0; i < sz; i++) { + unsigned char c = hex[i]; + if ((c < '0' || c > '9') && + (c < 'A' || c > 'F') && + (c < 'a' || c > 'f')) { + return 0; + } + } + return 1; +} +#endif /* SQLCIPHER_PREPROCESSED */ + + #ifndef OMIT_EXPORT /* diff --git a/src/crypto.h b/src/crypto.h index 41419f0c0c..66c994979c 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -159,32 +159,31 @@ static int cipher_hex2int(char c) { } #if defined (SQLCIPHER_PREPROCESSED) -void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out){ +void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out); #else /* SQLCIPHER_PREPROCESSED */ static void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out){ -#endif /* SQLCIPHER_PREPROCESSED */ int i; for(i = 0; i < sz; i += 2){ out[i/2] = (cipher_hex2int(hex[i])<<4) | cipher_hex2int(hex[i+1]); } } +#endif /* SQLCIPHER_PREPROCESSED */ #if defined (SQLCIPHER_PREPROCESSED) -void cipher_bin2hex(const unsigned char* in, int sz, char *out) { +void cipher_bin2hex(const unsigned char* in, int sz, char *out); #else /* SQLCIPHER_PREPROCESSED */ static void cipher_bin2hex(const unsigned char* in, int sz, char *out) { -#endif /* SQLCIPHER_PREPROCESSED */ int i; for(i=0; i < sz; i++) { sqlite3_snprintf(3, out + (i*2), "%02x ", in[i]); } } +#endif /* SQLCIPHER_PREPROCESSED */ #if defined (SQLCIPHER_PREPROCESSED) -int cipher_isHex(const unsigned char *hex, int sz){ +int cipher_isHex(const unsigned char *hex, int sz); #else /* SQLCIPHER_PREPROCESSED */ static int cipher_isHex(const unsigned char *hex, int sz){ -#endif /* SQLCIPHER_PREPROCESSED */ int i; for(i = 0; i < sz; i++) { unsigned char c = hex[i]; @@ -196,6 +195,7 @@ static int cipher_isHex(const unsigned char *hex, int sz){ } return 1; } +#endif /* SQLCIPHER_PREPROCESSED */ /* extensions defined in crypto_impl.c */ typedef struct codec_ctx codec_ctx; From 4a9c8b5e74a3abe8960973feec599dc585747c1f Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 8 Mar 2017 20:16:52 +0800 Subject: [PATCH 28/94] makefile for preprocess --- Makefile.preprocessed | 20 + .../project.pbxproj | 1252 ++++++++--------- 2 files changed, 592 insertions(+), 680 deletions(-) create mode 100644 Makefile.preprocessed diff --git a/Makefile.preprocessed b/Makefile.preprocessed new file mode 100644 index 0000000000..79a2945f08 --- /dev/null +++ b/Makefile.preprocessed @@ -0,0 +1,20 @@ +#!/usr/make + +SRC = \ + opcodes.h \ +opcodes.c \ +keywordhash.h \ +fts5.c \ +fts5.h \ +sqlite3.h \ +parse.h \ +parse.c + +all: $(SRC) +$(SRC): Makefile + make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c +Makefile: configure + ./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2" --disable-amalgamation + make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c +clean: + make clean diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index ef4ab39ce7..abf9293684 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -6,299 +6,287 @@ objectVersion = 46; objects = { -/* Begin PBXAggregateTarget section */ - 23121C271E6FFEFA0012B45E /* configure */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 23121C281E6FFEFA0012B45E /* Build configuration list for PBXAggregateTarget "configure" */; - buildPhases = ( - 23121C2B1E6FFF020012B45E /* ShellScript */, - ); - dependencies = ( - ); - name = configure; - productName = configure; - }; -/* End PBXAggregateTarget section */ - /* Begin PBXBuildFile section */ - 23121B7D1E6FF93D0012B45E /* keywordhash.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AEB1E6FF93D0012B45E /* keywordhash.h */; }; - 23121B7E1E6FF93D0012B45E /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AEC1E6FF93D0012B45E /* callback.c */; }; - 23121B7F1E6FF93D0012B45E /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AED1E6FF93D0012B45E /* loadext.c */; }; - 23121B801E6FF93D0012B45E /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AEE1E6FF93D0012B45E /* rowset.c */; }; - 23121B811E6FF93D0012B45E /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AEF1E6FF93D0012B45E /* treeview.c */; }; - 23121B821E6FF93D0012B45E /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF01E6FF93D0012B45E /* userauth.c */; }; - 23121B831E6FF93D0012B45E /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF11E6FF93D0012B45E /* vtab.c */; }; - 23121B841E6FF93D0012B45E /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF21E6FF93D0012B45E /* btmutex.c */; }; - 23121B851E6FF93D0012B45E /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF31E6FF93D0012B45E /* btree.c */; }; - 23121B861E6FF93D0012B45E /* btree.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AF41E6FF93D0012B45E /* btree.h */; }; - 23121B871E6FF93D0012B45E /* btreeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AF51E6FF93D0012B45E /* btreeInt.h */; }; - 23121B881E6FF93D0012B45E /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF71E6FF93D0012B45E /* fts5.c */; }; - 23121B891E6FF93D0012B45E /* fts5.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AF81E6FF93D0012B45E /* fts5.h */; }; - 23121B8A1E6FF93D0012B45E /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AF91E6FF93D0012B45E /* fts3_aux.c */; }; - 23121B8B1E6FF93D0012B45E /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFA1E6FF93D0012B45E /* fts3_expr.c */; }; - 23121B8C1E6FF93D0012B45E /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFB1E6FF93D0012B45E /* fts3_hash.c */; }; - 23121B8D1E6FF93D0012B45E /* fts3_hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121AFC1E6FF93D0012B45E /* fts3_hash.h */; }; - 23121B8E1E6FF93D0012B45E /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFD1E6FF93D0012B45E /* fts3_icu.c */; }; - 23121B8F1E6FF93D0012B45E /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFE1E6FF93D0012B45E /* fts3_porter.c */; }; - 23121B901E6FF93D0012B45E /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121AFF1E6FF93D0012B45E /* fts3_snippet.c */; }; - 23121B911E6FF93D0012B45E /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B001E6FF93D0012B45E /* fts3_tokenize_vtab.c */; }; - 23121B921E6FF93D0012B45E /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B011E6FF93D0012B45E /* fts3_tokenizer.c */; }; - 23121B931E6FF93D0012B45E /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B021E6FF93D0012B45E /* fts3_tokenizer.h */; }; - 23121B941E6FF93D0012B45E /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B031E6FF93D0012B45E /* fts3_tokenizer1.c */; }; - 23121B951E6FF93D0012B45E /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B041E6FF93D0012B45E /* fts3_unicode.c */; }; - 23121B961E6FF93D0012B45E /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B051E6FF93D0012B45E /* fts3_unicode2.c */; }; - 23121B971E6FF93D0012B45E /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B061E6FF93D0012B45E /* fts3_write.c */; }; - 23121B981E6FF93D0012B45E /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B071E6FF93D0012B45E /* fts3.c */; }; - 23121B991E6FF93D0012B45E /* fts3.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B081E6FF93D0012B45E /* fts3.h */; }; - 23121B9A1E6FF93D0012B45E /* fts3Int.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B091E6FF93D0012B45E /* fts3Int.h */; }; - 23121B9B1E6FF93D0012B45E /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0B1E6FF93D0012B45E /* backup.c */; }; - 23121B9C1E6FF93D0012B45E /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0C1E6FF93D0012B45E /* legacy.c */; }; - 23121B9D1E6FF93D0012B45E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0D1E6FF93D0012B45E /* main.c */; }; - 23121B9E1E6FF93D0012B45E /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0E1E6FF93D0012B45E /* notify.c */; }; - 23121B9F1E6FF93D0012B45E /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B0F1E6FF93D0012B45E /* vdbeapi.c */; }; - 23121BA01E6FF93D0012B45E /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B101E6FF93D0012B45E /* table.c */; }; - 23121BA11E6FF93D0012B45E /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B111E6FF93D0012B45E /* wal.c */; }; - 23121BA21E6FF93D0012B45E /* wal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B121E6FF93D0012B45E /* wal.h */; }; - 23121BA31E6FF93D0012B45E /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B131E6FF93D0012B45E /* status.c */; }; - 23121BA41E6FF93D0012B45E /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B141E6FF93D0012B45E /* prepare.c */; }; - 23121BA51E6FF93D0012B45E /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B161E6FF93D0012B45E /* malloc.c */; }; - 23121BA61E6FF93D0012B45E /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B171E6FF93D0012B45E /* mem0.c */; }; - 23121BA71E6FF93D0012B45E /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B181E6FF93D0012B45E /* mem1.c */; }; - 23121BA81E6FF93D0012B45E /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B191E6FF93D0012B45E /* mem2.c */; }; - 23121BA91E6FF93D0012B45E /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1A1E6FF93D0012B45E /* mem3.c */; }; - 23121BAA1E6FF93D0012B45E /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1B1E6FF93D0012B45E /* mem5.c */; }; - 23121BAB1E6FF93D0012B45E /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1C1E6FF93D0012B45E /* memjournal.c */; }; - 23121BAC1E6FF93D0012B45E /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1E1E6FF93D0012B45E /* mutex_unix.c */; }; - 23121BAD1E6FF93D0012B45E /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B1F1E6FF93D0012B45E /* mutex.c */; }; - 23121BAE1E6FF93D0012B45E /* mutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B201E6FF93D0012B45E /* mutex.h */; }; - 23121BAF1E6FF93D0012B45E /* os_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B211E6FF93D0012B45E /* os_common.h */; }; - 23121BB01E6FF93D0012B45E /* os_setup.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B221E6FF93D0012B45E /* os_setup.h */; }; - 23121BB11E6FF93D0012B45E /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B231E6FF93D0012B45E /* os_unix.c */; }; - 23121BB21E6FF93D0012B45E /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B241E6FF93D0012B45E /* os.c */; }; - 23121BB31E6FF93D0012B45E /* os.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B251E6FF93D0012B45E /* os.h */; }; - 23121BB41E6FF93D0012B45E /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B261E6FF93D0012B45E /* threads.c */; }; - 23121BB51E6FF93D0012B45E /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B281E6FF93D0012B45E /* bitvec.c */; }; - 23121BB61E6FF93D0012B45E /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B291E6FF93D0012B45E /* pager.c */; }; - 23121BB71E6FF93D0012B45E /* pager.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B2A1E6FF93D0012B45E /* pager.h */; }; - 23121BB81E6FF93D0012B45E /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B2B1E6FF93D0012B45E /* pcache.c */; }; - 23121BB91E6FF93D0012B45E /* pcache.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B2C1E6FF93D0012B45E /* pcache.h */; }; - 23121BBA1E6FF93D0012B45E /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B2D1E6FF93D0012B45E /* pcache1.c */; }; - 23121BBB1E6FF93D0012B45E /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B2F1E6FF93D0012B45E /* rtree.c */; }; - 23121BBC1E6FF93D0012B45E /* rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B301E6FF93D0012B45E /* rtree.h */; }; - 23121BBD1E6FF93D0012B45E /* sqlite3rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B311E6FF93D0012B45E /* sqlite3rtree.h */; }; - 23121BBE1E6FF93D0012B45E /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B331E6FF93D0012B45E /* complete.c */; }; - 23121BBF1E6FF93D0012B45E /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B341E6FF93D0012B45E /* tokenize.c */; }; - 23121BC01E6FF93D0012B45E /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B361E6FF93D0012B45E /* resolve.c */; }; - 23121BC11E6FF93D0012B45E /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B371E6FF93D0012B45E /* parse.c */; }; - 23121BC21E6FF93D0012B45E /* parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B381E6FF93D0012B45E /* parse.h */; }; - 23121BC31E6FF93D0012B45E /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3A1E6FF93D0012B45E /* analyze.c */; }; - 23121BC41E6FF93D0012B45E /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3B1E6FF93D0012B45E /* func.c */; }; - 23121BC51E6FF93D0012B45E /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3C1E6FF93D0012B45E /* wherecode.c */; }; - 23121BC61E6FF93D0012B45E /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3D1E6FF93D0012B45E /* whereexpr.c */; }; - 23121BC71E6FF93D0012B45E /* whereInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B3E1E6FF93D0012B45E /* whereInt.h */; }; - 23121BC81E6FF93D0012B45E /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B3F1E6FF93D0012B45E /* alter.c */; }; - 23121BC91E6FF93D0012B45E /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B401E6FF93D0012B45E /* attach.c */; }; - 23121BCA1E6FF93D0012B45E /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B411E6FF93D0012B45E /* auth.c */; }; - 23121BCB1E6FF93D0012B45E /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B421E6FF93D0012B45E /* build.c */; }; - 23121BCC1E6FF93D0012B45E /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B431E6FF93D0012B45E /* delete.c */; }; - 23121BCD1E6FF93D0012B45E /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B441E6FF93D0012B45E /* expr.c */; }; - 23121BCE1E6FF93D0012B45E /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B451E6FF93D0012B45E /* insert.c */; }; - 23121BCF1E6FF93D0012B45E /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B461E6FF93D0012B45E /* pragma.c */; }; - 23121BD01E6FF93D0012B45E /* pragma.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B471E6FF93D0012B45E /* pragma.h */; }; - 23121BD11E6FF93D0012B45E /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B481E6FF93D0012B45E /* select.c */; }; - 23121BD21E6FF93D0012B45E /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B491E6FF93D0012B45E /* trigger.c */; }; - 23121BD31E6FF93D0012B45E /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4A1E6FF93D0012B45E /* update.c */; }; - 23121BD41E6FF93D0012B45E /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4B1E6FF93D0012B45E /* vacuum.c */; }; - 23121BD51E6FF93D0012B45E /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4C1E6FF93D0012B45E /* walker.c */; }; - 23121BD61E6FF93D0012B45E /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4D1E6FF93D0012B45E /* where.c */; }; - 23121BD71E6FF93D0012B45E /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B4E1E6FF93D0012B45E /* opcodes.c */; }; - 23121BD81E6FF93D0012B45E /* opcodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B4F1E6FF93D0012B45E /* opcodes.h */; }; - 23121BD91E6FF93D0012B45E /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B521E6FF93D0012B45E /* sqlite3.h */; }; - 23121BDA1E6FF93D0012B45E /* sqlite3userauth.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B531E6FF93D0012B45E /* sqlite3userauth.h */; }; - 23121BDB1E6FF93D0012B45E /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B541E6FF93D0012B45E /* sqlite3rbu.c */; }; - 23121BDC1E6FF93D0012B45E /* sqlite3rbu.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B551E6FF93D0012B45E /* sqlite3rbu.h */; }; - 23121BDD1E6FF93D0012B45E /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B561E6FF93D0012B45E /* json1.c */; }; - 23121BDE1E6FF93D0012B45E /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B571E6FF93D0012B45E /* icu.c */; }; - 23121BDF1E6FF93D0012B45E /* sqliteicu.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B581E6FF93D0012B45E /* sqliteicu.h */; }; - 23121BE01E6FF93D0012B45E /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B591E6FF93D0012B45E /* global.c */; }; - 23121BE11E6FF93D0012B45E /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5A1E6FF93D0012B45E /* ctime.c */; }; - 23121BE21E6FF93D0012B45E /* hwtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B5B1E6FF93D0012B45E /* hwtime.h */; }; - 23121BE31E6FF93D0012B45E /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5C1E6FF93D0012B45E /* date.c */; }; - 23121BE41E6FF93D0012B45E /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5D1E6FF93D0012B45E /* dbstat.c */; }; - 23121BE51E6FF93D0012B45E /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5E1E6FF93D0012B45E /* fault.c */; }; - 23121BE61E6FF93D0012B45E /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B5F1E6FF93D0012B45E /* fkey.c */; }; - 23121BE71E6FF93D0012B45E /* sqliteInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B601E6FF93D0012B45E /* sqliteInt.h */; }; - 23121BE81E6FF93D0012B45E /* sqliteLimit.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B611E6FF93D0012B45E /* sqliteLimit.h */; }; - 23121BE91E6FF93D0012B45E /* sqlite3ext.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B621E6FF93D0012B45E /* sqlite3ext.h */; }; - 23121BEA1E6FF93D0012B45E /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B631E6FF93D0012B45E /* hash.c */; }; - 23121BEB1E6FF93D0012B45E /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B641E6FF93D0012B45E /* hash.h */; }; - 23121BEC1E6FF93D0012B45E /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B651E6FF93D0012B45E /* printf.c */; }; - 23121BED1E6FF93D0012B45E /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B661E6FF93D0012B45E /* random.c */; }; - 23121BEE1E6FF93D0012B45E /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B671E6FF93D0012B45E /* utf.c */; }; - 23121BEF1E6FF93D0012B45E /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B681E6FF93D0012B45E /* util.c */; }; - 23121BF01E6FF93D0012B45E /* crypto_custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6A1E6FF93D0012B45E /* crypto_custom.c */; }; - 23121BF11E6FF93D0012B45E /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6B1E6FF93D0012B45E /* vdbe.c */; }; - 23121BF21E6FF93D0012B45E /* vdbe.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B6C1E6FF93D0012B45E /* vdbe.h */; }; - 23121BF31E6FF93D0012B45E /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6D1E6FF93D0012B45E /* vdbeaux.c */; }; - 23121BF41E6FF93D0012B45E /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B6E1E6FF93D0012B45E /* vdbeblob.c */; }; - 23121BF51E6FF93D0012B45E /* vdbeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B6F1E6FF93D0012B45E /* vdbeInt.h */; }; - 23121BF61E6FF93D0012B45E /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B701E6FF93D0012B45E /* vdbemem.c */; }; - 23121BF71E6FF93D0012B45E /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B711E6FF93D0012B45E /* vdbesort.c */; }; - 23121BF81E6FF93D0012B45E /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B721E6FF93D0012B45E /* vdbetrace.c */; }; - 23121BF91E6FF93D0012B45E /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B741E6FF93D0012B45E /* crypto.c */; }; - 23121BFA1E6FF93D0012B45E /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B751E6FF93D0012B45E /* crypto.h */; }; - 23121BFB1E6FF93D0012B45E /* sqlcipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 23121B761E6FF93D0012B45E /* sqlcipher.h */; }; - 23121BFC1E6FF93D0012B45E /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B771E6FF93D0012B45E /* crypto_cc.c */; }; - 23121BFD1E6FF93D0012B45E /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B781E6FF93D0012B45E /* crypto_impl.c */; }; - 23121BFE1E6FF93D0012B45E /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B791E6FF93D0012B45E /* crypto_libtomcrypt.c */; }; - 23121BFF1E6FF93D0012B45E /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 23121B7A1E6FF93D0012B45E /* crypto_openssl.c */; }; 23121C081E6FFA890012B45E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; + 239528931E700BBC0054D75E /* keywordhash.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528921E700BBC0054D75E /* keywordhash.h */; }; + 239528951E700BCB0054D75E /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; + 239528971E700BEB0054D75E /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; + 239528991E700BFE0054D75E /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; + 2395289B1E700C100054D75E /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289A1E700C100054D75E /* treeview.c */; }; + 2395289D1E700C1B0054D75E /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289C1E700C1B0054D75E /* userauth.c */; }; + 2395289F1E700C250054D75E /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289E1E700C250054D75E /* vtab.c */; }; + 239528A11E700C370054D75E /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A01E700C370054D75E /* btmutex.c */; }; + 239528A31E700C4A0054D75E /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A21E700C4A0054D75E /* btree.c */; }; + 239528A51E700C550054D75E /* btreeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528A41E700C550054D75E /* btreeInt.h */; }; + 239528A71E700C670054D75E /* btree.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528A61E700C670054D75E /* btree.h */; }; + 239528AA1E700C820054D75E /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A81E700C820054D75E /* fts5.c */; }; + 239528AB1E700C820054D75E /* fts5.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528A91E700C820054D75E /* fts5.h */; }; + 239528BD1E700CB60054D75E /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AC1E700CB60054D75E /* fts3_aux.c */; }; + 239528BE1E700CB60054D75E /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AD1E700CB60054D75E /* fts3_expr.c */; }; + 239528BF1E700CB60054D75E /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AE1E700CB60054D75E /* fts3_hash.c */; }; + 239528C01E700CB60054D75E /* fts3_hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528AF1E700CB60054D75E /* fts3_hash.h */; }; + 239528C11E700CB60054D75E /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B01E700CB60054D75E /* fts3_icu.c */; }; + 239528C21E700CB60054D75E /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B11E700CB60054D75E /* fts3_porter.c */; }; + 239528C31E700CB60054D75E /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B21E700CB60054D75E /* fts3_snippet.c */; }; + 239528C41E700CB60054D75E /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */; }; + 239528C51E700CB60054D75E /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B41E700CB60054D75E /* fts3_tokenizer.c */; }; + 239528C61E700CB60054D75E /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528B51E700CB60054D75E /* fts3_tokenizer.h */; }; + 239528C71E700CB60054D75E /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B61E700CB60054D75E /* fts3_tokenizer1.c */; }; + 239528C81E700CB60054D75E /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B71E700CB60054D75E /* fts3_unicode.c */; }; + 239528C91E700CB60054D75E /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B81E700CB60054D75E /* fts3_unicode2.c */; }; + 239528CA1E700CB60054D75E /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B91E700CB60054D75E /* fts3_write.c */; }; + 239528CB1E700CB60054D75E /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528BA1E700CB60054D75E /* fts3.c */; }; + 239528CC1E700CB60054D75E /* fts3.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528BB1E700CB60054D75E /* fts3.h */; }; + 239528CD1E700CB60054D75E /* fts3Int.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528BC1E700CB60054D75E /* fts3Int.h */; }; + 239528CF1E700CC30054D75E /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528CE1E700CC30054D75E /* backup.c */; }; + 239528D11E700CCD0054D75E /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D01E700CCD0054D75E /* legacy.c */; }; + 239528D31E700CD70054D75E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D21E700CD70054D75E /* main.c */; }; + 239528D51E700CE10054D75E /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D41E700CE10054D75E /* notify.c */; }; + 239528D71E700CED0054D75E /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D61E700CED0054D75E /* vdbeapi.c */; }; + 239528D91E700CFB0054D75E /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D81E700CFB0054D75E /* table.c */; }; + 239528DC1E700D0A0054D75E /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DA1E700D0A0054D75E /* wal.c */; }; + 239528DD1E700D0A0054D75E /* wal.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528DB1E700D0A0054D75E /* wal.h */; }; + 239528DF1E700D170054D75E /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DE1E700D170054D75E /* status.c */; }; + 239528E11E700D220054D75E /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E01E700D220054D75E /* prepare.c */; }; + 239528E31E700D320054D75E /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E21E700D320054D75E /* malloc.c */; }; + 239528E91E700D460054D75E /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E41E700D460054D75E /* mem0.c */; }; + 239528EA1E700D460054D75E /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E51E700D460054D75E /* mem1.c */; }; + 239528EB1E700D460054D75E /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E61E700D460054D75E /* mem2.c */; }; + 239528EC1E700D460054D75E /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E71E700D460054D75E /* mem3.c */; }; + 239528ED1E700D460054D75E /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E81E700D460054D75E /* mem5.c */; }; + 239528EF1E700D4A0054D75E /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528EE1E700D4A0054D75E /* memjournal.c */; }; + 239528F11E700D570054D75E /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F01E700D570054D75E /* mutex_unix.c */; }; + 239528F31E700D600054D75E /* mutex_noop.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F21E700D600054D75E /* mutex_noop.c */; }; + 239528F61E700D6C0054D75E /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F41E700D6C0054D75E /* mutex.c */; }; + 239528F71E700D6C0054D75E /* mutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528F51E700D6C0054D75E /* mutex.h */; }; + 239528FB1E700D790054D75E /* os_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528F81E700D790054D75E /* os_common.h */; }; + 239528FC1E700D790054D75E /* os_setup.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528F91E700D790054D75E /* os_setup.h */; }; + 239528FD1E700D790054D75E /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FA1E700D790054D75E /* os_unix.c */; }; + 239529001E700D880054D75E /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FE1E700D880054D75E /* os.c */; }; + 239529011E700D880054D75E /* os.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528FF1E700D880054D75E /* os.h */; }; + 239529031E700D920054D75E /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529021E700D920054D75E /* threads.c */; }; + 239529051E700D9D0054D75E /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529041E700D9D0054D75E /* bitvec.c */; }; + 239529081E700DA70054D75E /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529061E700DA70054D75E /* pager.c */; }; + 239529091E700DA70054D75E /* pager.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529071E700DA70054D75E /* pager.h */; }; + 2395290D1E700DB90054D75E /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290A1E700DB90054D75E /* pcache.c */; }; + 2395290E1E700DB90054D75E /* pcache.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395290B1E700DB90054D75E /* pcache.h */; }; + 2395290F1E700DB90054D75E /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290C1E700DB90054D75E /* pcache1.c */; }; + 239529131E700DD10054D75E /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529101E700DD10054D75E /* rtree.c */; }; + 239529141E700DD10054D75E /* rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529111E700DD10054D75E /* rtree.h */; }; + 239529151E700DD10054D75E /* sqlite3rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529121E700DD10054D75E /* sqlite3rtree.h */; }; + 239529171E700DDF0054D75E /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529161E700DDF0054D75E /* complete.c */; }; + 239529191E700DED0054D75E /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529181E700DED0054D75E /* tokenize.c */; }; + 2395291B1E700DFD0054D75E /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291A1E700DFD0054D75E /* resolve.c */; }; + 2395291E1E700E080054D75E /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291C1E700E080054D75E /* parse.c */; }; + 2395291F1E700E080054D75E /* parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395291D1E700E080054D75E /* parse.h */; }; + 239529211E700E170054D75E /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529201E700E170054D75E /* analyze.c */; }; + 239529231E700E1E0054D75E /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529221E700E1E0054D75E /* func.c */; }; + 239529251E700E280054D75E /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529241E700E280054D75E /* wherecode.c */; }; + 239529271E700E2F0054D75E /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529261E700E2F0054D75E /* whereexpr.c */; }; + 239529291E700E340054D75E /* whereInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529281E700E340054D75E /* whereInt.h */; }; + 2395292B1E700E3C0054D75E /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292A1E700E3C0054D75E /* alter.c */; }; + 2395292D1E700E450054D75E /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292C1E700E450054D75E /* attach.c */; }; + 2395292F1E700E4C0054D75E /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292E1E700E4C0054D75E /* auth.c */; }; + 239529311E700E590054D75E /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529301E700E590054D75E /* build.c */; }; + 239529331E700E5F0054D75E /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529321E700E5F0054D75E /* delete.c */; }; + 239529351E700E660054D75E /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529341E700E660054D75E /* expr.c */; }; + 239529371E700E6E0054D75E /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529361E700E6D0054D75E /* insert.c */; }; + 2395293A1E700E780054D75E /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529381E700E780054D75E /* pragma.c */; }; + 2395293B1E700E780054D75E /* pragma.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529391E700E780054D75E /* pragma.h */; }; + 2395293D1E700E810054D75E /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293C1E700E810054D75E /* select.c */; }; + 2395293F1E700E8A0054D75E /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293E1E700E8A0054D75E /* trigger.c */; }; + 239529411E700E910054D75E /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529401E700E910054D75E /* update.c */; }; + 239529431E700E9C0054D75E /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529421E700E9C0054D75E /* vacuum.c */; }; + 239529451E700EA40054D75E /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529441E700EA40054D75E /* walker.c */; }; + 239529471E700EAF0054D75E /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529461E700EAF0054D75E /* where.c */; }; + 2395294A1E700EBC0054D75E /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529481E700EBC0054D75E /* opcodes.c */; }; + 2395294B1E700EBC0054D75E /* opcodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529491E700EBC0054D75E /* opcodes.h */; }; + 239529501E700EE70054D75E /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294C1E700EE70054D75E /* sqlite3.h */; }; + 239529511E700EE70054D75E /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395294D1E700EE70054D75E /* sqlite3rbu.c */; }; + 239529521E700EE70054D75E /* sqlite3rbu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294E1E700EE70054D75E /* sqlite3rbu.h */; }; + 239529531E700EE70054D75E /* sqlite3userauth.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294F1E700EE70054D75E /* sqlite3userauth.h */; }; + 239529551E700EF00054D75E /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529541E700EF00054D75E /* json1.c */; }; + 239529571E700EF90054D75E /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529561E700EF90054D75E /* icu.c */; }; + 239529591E700F060054D75E /* sqliteicu.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529581E700F060054D75E /* sqliteicu.h */; }; + 2395295B1E700F0F0054D75E /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295A1E700F0F0054D75E /* global.c */; }; + 2395295D1E700F170054D75E /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295C1E700F170054D75E /* ctime.c */; }; + 2395295F1E700F200054D75E /* hwtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395295E1E700F200054D75E /* hwtime.h */; }; + 239529611E700F2C0054D75E /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529601E700F2C0054D75E /* date.c */; }; + 239529631E700F360054D75E /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529621E700F360054D75E /* dbstat.c */; }; + 239529651E700F410054D75E /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529641E700F410054D75E /* fault.c */; }; + 239529671E700F490054D75E /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529661E700F490054D75E /* fkey.c */; }; + 239529691E700F570054D75E /* sqliteInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529681E700F570054D75E /* sqliteInt.h */; }; + 2395296B1E700F600054D75E /* sqliteLimit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395296A1E700F600054D75E /* sqliteLimit.h */; }; + 2395296D1E700F6C0054D75E /* sqlite3ext.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395296C1E700F6C0054D75E /* sqlite3ext.h */; }; + 239529701E700F760054D75E /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395296E1E700F760054D75E /* hash.c */; }; + 239529711E700F760054D75E /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395296F1E700F760054D75E /* hash.h */; }; + 239529731E700F7F0054D75E /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529721E700F7F0054D75E /* printf.c */; }; + 239529751E700F870054D75E /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529741E700F870054D75E /* random.c */; }; + 239529781E700F940054D75E /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529761E700F940054D75E /* utf.c */; }; + 239529791E700F940054D75E /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529771E700F940054D75E /* util.c */; }; + 2395297B1E700FA60054D75E /* crypto_custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297A1E700FA60054D75E /* crypto_custom.c */; }; + 239529821E700FC60054D75E /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297C1E700FC60054D75E /* crypto_cc.c */; }; + 239529831E700FC60054D75E /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297D1E700FC60054D75E /* crypto_impl.c */; }; + 239529841E700FC60054D75E /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */; }; + 239529851E700FC60054D75E /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297F1E700FC60054D75E /* crypto_openssl.c */; }; + 239529861E700FC60054D75E /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529801E700FC60054D75E /* crypto.c */; }; + 239529871E700FC60054D75E /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529811E700FC60054D75E /* crypto.h */; }; + 239529891E700FD90054D75E /* sqlcipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529881E700FD90054D75E /* sqlcipher.h */; }; + 239529921E7010030054D75E /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298A1E7010030054D75E /* vdbe.c */; }; + 239529931E7010030054D75E /* vdbe.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395298B1E7010030054D75E /* vdbe.h */; }; + 239529941E7010030054D75E /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298C1E7010030054D75E /* vdbeaux.c */; }; + 239529951E7010030054D75E /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298D1E7010030054D75E /* vdbeblob.c */; }; + 239529961E7010030054D75E /* vdbeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395298E1E7010030054D75E /* vdbeInt.h */; }; + 239529971E7010030054D75E /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298F1E7010030054D75E /* vdbemem.c */; }; + 239529981E7010030054D75E /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529901E7010030054D75E /* vdbesort.c */; }; + 239529991E7010030054D75E /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529911E7010030054D75E /* vdbetrace.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 23121C2C1E6FFFA50012B45E /* PBXContainerItemProxy */ = { + 2395299F1E702D1E0054D75E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; proxyType = 1; - remoteGlobalIDString = 23121C271E6FFEFA0012B45E; - remoteInfo = configure; + remoteGlobalIDString = 2395299B1E702CF90054D75E; + remoteInfo = preprocess; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libsqlcipher-preprocessed.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 23121AEB1E6FF93D0012B45E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = keywordhash.h; path = ../keywordhash.h; sourceTree = ""; }; - 23121AEC1E6FF93D0012B45E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = ../src/callback.c; sourceTree = ""; }; - 23121AED1E6FF93D0012B45E /* loadext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loadext.c; path = ../src/loadext.c; sourceTree = ""; }; - 23121AEE1E6FF93D0012B45E /* rowset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rowset.c; path = ../src/rowset.c; sourceTree = ""; }; - 23121AEF1E6FF93D0012B45E /* treeview.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = treeview.c; path = ../src/treeview.c; sourceTree = ""; }; - 23121AF01E6FF93D0012B45E /* userauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = userauth.c; path = ../ext/userauth/userauth.c; sourceTree = ""; }; - 23121AF11E6FF93D0012B45E /* vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vtab.c; path = ../src/vtab.c; sourceTree = ""; }; - 23121AF21E6FF93D0012B45E /* btmutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btmutex.c; path = ../src/btmutex.c; sourceTree = ""; }; - 23121AF31E6FF93D0012B45E /* btree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btree.c; path = ../src/btree.c; sourceTree = ""; }; - 23121AF41E6FF93D0012B45E /* btree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btree.h; path = ../src/btree.h; sourceTree = ""; }; - 23121AF51E6FF93D0012B45E /* btreeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btreeInt.h; path = ../src/btreeInt.h; sourceTree = ""; }; - 23121AF71E6FF93D0012B45E /* fts5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts5.c; path = ../fts5.c; sourceTree = ""; }; - 23121AF81E6FF93D0012B45E /* fts5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts5.h; path = ../fts5.h; sourceTree = ""; }; - 23121AF91E6FF93D0012B45E /* fts3_aux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_aux.c; path = ../ext/fts3/fts3_aux.c; sourceTree = ""; }; - 23121AFA1E6FF93D0012B45E /* fts3_expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_expr.c; path = ../ext/fts3/fts3_expr.c; sourceTree = ""; }; - 23121AFB1E6FF93D0012B45E /* fts3_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_hash.c; path = ../ext/fts3/fts3_hash.c; sourceTree = ""; }; - 23121AFC1E6FF93D0012B45E /* fts3_hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_hash.h; path = ../ext/fts3/fts3_hash.h; sourceTree = ""; }; - 23121AFD1E6FF93D0012B45E /* fts3_icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_icu.c; path = ../ext/fts3/fts3_icu.c; sourceTree = ""; }; - 23121AFE1E6FF93D0012B45E /* fts3_porter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_porter.c; path = ../ext/fts3/fts3_porter.c; sourceTree = ""; }; - 23121AFF1E6FF93D0012B45E /* fts3_snippet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_snippet.c; path = ../ext/fts3/fts3_snippet.c; sourceTree = ""; }; - 23121B001E6FF93D0012B45E /* fts3_tokenize_vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenize_vtab.c; path = ../ext/fts3/fts3_tokenize_vtab.c; sourceTree = ""; }; - 23121B011E6FF93D0012B45E /* fts3_tokenizer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer.c; path = ../ext/fts3/fts3_tokenizer.c; sourceTree = ""; }; - 23121B021E6FF93D0012B45E /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ../ext/fts3/fts3_tokenizer.h; sourceTree = ""; }; - 23121B031E6FF93D0012B45E /* fts3_tokenizer1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer1.c; path = ../ext/fts3/fts3_tokenizer1.c; sourceTree = ""; }; - 23121B041E6FF93D0012B45E /* fts3_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode.c; path = ../ext/fts3/fts3_unicode.c; sourceTree = ""; }; - 23121B051E6FF93D0012B45E /* fts3_unicode2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode2.c; path = ../ext/fts3/fts3_unicode2.c; sourceTree = ""; }; - 23121B061E6FF93D0012B45E /* fts3_write.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_write.c; path = ../ext/fts3/fts3_write.c; sourceTree = ""; }; - 23121B071E6FF93D0012B45E /* fts3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3.c; path = ../ext/fts3/fts3.c; sourceTree = ""; }; - 23121B081E6FF93D0012B45E /* fts3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3.h; path = ../ext/fts3/fts3.h; sourceTree = ""; }; - 23121B091E6FF93D0012B45E /* fts3Int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3Int.h; path = ../ext/fts3/fts3Int.h; sourceTree = ""; }; - 23121B0B1E6FF93D0012B45E /* backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = backup.c; path = ../src/backup.c; sourceTree = ""; }; - 23121B0C1E6FF93D0012B45E /* legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = legacy.c; path = ../src/legacy.c; sourceTree = ""; }; - 23121B0D1E6FF93D0012B45E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../src/main.c; sourceTree = ""; }; - 23121B0E1E6FF93D0012B45E /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = ../src/notify.c; sourceTree = ""; }; - 23121B0F1E6FF93D0012B45E /* vdbeapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeapi.c; path = ../src/vdbeapi.c; sourceTree = ""; }; - 23121B101E6FF93D0012B45E /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = table.c; path = ../src/table.c; sourceTree = ""; }; - 23121B111E6FF93D0012B45E /* wal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wal.c; path = ../src/wal.c; sourceTree = ""; }; - 23121B121E6FF93D0012B45E /* wal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wal.h; path = ../src/wal.h; sourceTree = ""; }; - 23121B131E6FF93D0012B45E /* status.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = status.c; path = ../src/status.c; sourceTree = ""; }; - 23121B141E6FF93D0012B45E /* prepare.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prepare.c; path = ../src/prepare.c; sourceTree = ""; }; - 23121B161E6FF93D0012B45E /* malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = malloc.c; path = ../src/malloc.c; sourceTree = ""; }; - 23121B171E6FF93D0012B45E /* mem0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem0.c; path = ../src/mem0.c; sourceTree = ""; }; - 23121B181E6FF93D0012B45E /* mem1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem1.c; path = ../src/mem1.c; sourceTree = ""; }; - 23121B191E6FF93D0012B45E /* mem2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem2.c; path = ../src/mem2.c; sourceTree = ""; }; - 23121B1A1E6FF93D0012B45E /* mem3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem3.c; path = ../src/mem3.c; sourceTree = ""; }; - 23121B1B1E6FF93D0012B45E /* mem5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem5.c; path = ../src/mem5.c; sourceTree = ""; }; - 23121B1C1E6FF93D0012B45E /* memjournal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memjournal.c; path = ../src/memjournal.c; sourceTree = ""; }; - 23121B1E1E6FF93D0012B45E /* mutex_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_unix.c; path = ../src/mutex_unix.c; sourceTree = ""; }; - 23121B1F1E6FF93D0012B45E /* mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex.c; path = ../src/mutex.c; sourceTree = ""; }; - 23121B201E6FF93D0012B45E /* mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex.h; path = ../src/mutex.h; sourceTree = ""; }; - 23121B211E6FF93D0012B45E /* os_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_common.h; path = ../src/os_common.h; sourceTree = ""; }; - 23121B221E6FF93D0012B45E /* os_setup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_setup.h; path = ../src/os_setup.h; sourceTree = ""; }; - 23121B231E6FF93D0012B45E /* os_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_unix.c; path = ../src/os_unix.c; sourceTree = ""; }; - 23121B241E6FF93D0012B45E /* os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os.c; path = ../src/os.c; sourceTree = ""; }; - 23121B251E6FF93D0012B45E /* os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os.h; path = ../src/os.h; sourceTree = ""; }; - 23121B261E6FF93D0012B45E /* threads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threads.c; path = ../src/threads.c; sourceTree = ""; }; - 23121B281E6FF93D0012B45E /* bitvec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitvec.c; path = ../src/bitvec.c; sourceTree = ""; }; - 23121B291E6FF93D0012B45E /* pager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pager.c; path = ../src/pager.c; sourceTree = ""; }; - 23121B2A1E6FF93D0012B45E /* pager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pager.h; path = ../src/pager.h; sourceTree = ""; }; - 23121B2B1E6FF93D0012B45E /* pcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache.c; path = ../src/pcache.c; sourceTree = ""; }; - 23121B2C1E6FF93D0012B45E /* pcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pcache.h; path = ../src/pcache.h; sourceTree = ""; }; - 23121B2D1E6FF93D0012B45E /* pcache1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache1.c; path = ../src/pcache1.c; sourceTree = ""; }; - 23121B2F1E6FF93D0012B45E /* rtree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rtree.c; path = ../ext/rtree/rtree.c; sourceTree = ""; }; - 23121B301E6FF93D0012B45E /* rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rtree.h; path = ../ext/rtree/rtree.h; sourceTree = ""; }; - 23121B311E6FF93D0012B45E /* sqlite3rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rtree.h; path = ../ext/rtree/sqlite3rtree.h; sourceTree = ""; }; - 23121B331E6FF93D0012B45E /* complete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = complete.c; path = ../src/complete.c; sourceTree = ""; }; - 23121B341E6FF93D0012B45E /* tokenize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tokenize.c; path = ../src/tokenize.c; sourceTree = ""; }; - 23121B361E6FF93D0012B45E /* resolve.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = resolve.c; path = ../src/resolve.c; sourceTree = ""; }; - 23121B371E6FF93D0012B45E /* parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parse.c; path = ../parse.c; sourceTree = ""; }; - 23121B381E6FF93D0012B45E /* parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parse.h; path = ../parse.h; sourceTree = ""; }; - 23121B3A1E6FF93D0012B45E /* analyze.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = analyze.c; path = ../src/analyze.c; sourceTree = ""; }; - 23121B3B1E6FF93D0012B45E /* func.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = func.c; path = ../src/func.c; sourceTree = ""; }; - 23121B3C1E6FF93D0012B45E /* wherecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wherecode.c; path = ../src/wherecode.c; sourceTree = ""; }; - 23121B3D1E6FF93D0012B45E /* whereexpr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = whereexpr.c; path = ../src/whereexpr.c; sourceTree = ""; }; - 23121B3E1E6FF93D0012B45E /* whereInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = whereInt.h; path = ../src/whereInt.h; sourceTree = ""; }; - 23121B3F1E6FF93D0012B45E /* alter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alter.c; path = ../src/alter.c; sourceTree = ""; }; - 23121B401E6FF93D0012B45E /* attach.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = attach.c; path = ../src/attach.c; sourceTree = ""; }; - 23121B411E6FF93D0012B45E /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = ../src/auth.c; sourceTree = ""; }; - 23121B421E6FF93D0012B45E /* build.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = build.c; path = ../src/build.c; sourceTree = ""; }; - 23121B431E6FF93D0012B45E /* delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = delete.c; path = ../src/delete.c; sourceTree = ""; }; - 23121B441E6FF93D0012B45E /* expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = expr.c; path = ../src/expr.c; sourceTree = ""; }; - 23121B451E6FF93D0012B45E /* insert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = insert.c; path = ../src/insert.c; sourceTree = ""; }; - 23121B461E6FF93D0012B45E /* pragma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pragma.c; path = ../src/pragma.c; sourceTree = ""; }; - 23121B471E6FF93D0012B45E /* pragma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pragma.h; path = ../src/pragma.h; sourceTree = ""; }; - 23121B481E6FF93D0012B45E /* select.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = select.c; path = ../src/select.c; sourceTree = ""; }; - 23121B491E6FF93D0012B45E /* trigger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trigger.c; path = ../src/trigger.c; sourceTree = ""; }; - 23121B4A1E6FF93D0012B45E /* update.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = update.c; path = ../src/update.c; sourceTree = ""; }; - 23121B4B1E6FF93D0012B45E /* vacuum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vacuum.c; path = ../src/vacuum.c; sourceTree = ""; }; - 23121B4C1E6FF93D0012B45E /* walker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = walker.c; path = ../src/walker.c; sourceTree = ""; }; - 23121B4D1E6FF93D0012B45E /* where.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = where.c; path = ../src/where.c; sourceTree = ""; }; - 23121B4E1E6FF93D0012B45E /* opcodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = opcodes.c; path = ../opcodes.c; sourceTree = ""; }; - 23121B4F1E6FF93D0012B45E /* opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = opcodes.h; path = ../opcodes.h; sourceTree = ""; }; - 23121B521E6FF93D0012B45E /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3.h; path = ../sqlite3.h; sourceTree = ""; }; - 23121B531E6FF93D0012B45E /* sqlite3userauth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3userauth.h; path = ../ext/userauth/sqlite3userauth.h; sourceTree = ""; }; - 23121B541E6FF93D0012B45E /* sqlite3rbu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sqlite3rbu.c; path = ../ext/rbu/sqlite3rbu.c; sourceTree = ""; }; - 23121B551E6FF93D0012B45E /* sqlite3rbu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rbu.h; path = ../ext/rbu/sqlite3rbu.h; sourceTree = ""; }; - 23121B561E6FF93D0012B45E /* json1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = json1.c; path = ../ext/misc/json1.c; sourceTree = ""; }; - 23121B571E6FF93D0012B45E /* icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = icu.c; path = ../ext/icu/icu.c; sourceTree = ""; }; - 23121B581E6FF93D0012B45E /* sqliteicu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteicu.h; path = ../ext/icu/sqliteicu.h; sourceTree = ""; }; - 23121B591E6FF93D0012B45E /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = global.c; path = ../src/global.c; sourceTree = ""; }; - 23121B5A1E6FF93D0012B45E /* ctime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctime.c; path = ../src/ctime.c; sourceTree = ""; }; - 23121B5B1E6FF93D0012B45E /* hwtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwtime.h; path = ../src/hwtime.h; sourceTree = ""; }; - 23121B5C1E6FF93D0012B45E /* date.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = date.c; path = ../src/date.c; sourceTree = ""; }; - 23121B5D1E6FF93D0012B45E /* dbstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dbstat.c; path = ../src/dbstat.c; sourceTree = ""; }; - 23121B5E1E6FF93D0012B45E /* fault.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fault.c; path = ../src/fault.c; sourceTree = ""; }; - 23121B5F1E6FF93D0012B45E /* fkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fkey.c; path = ../src/fkey.c; sourceTree = ""; }; - 23121B601E6FF93D0012B45E /* sqliteInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteInt.h; path = ../src/sqliteInt.h; sourceTree = ""; }; - 23121B611E6FF93D0012B45E /* sqliteLimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteLimit.h; path = ../src/sqliteLimit.h; sourceTree = ""; }; - 23121B621E6FF93D0012B45E /* sqlite3ext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3ext.h; path = ../src/sqlite3ext.h; sourceTree = ""; }; - 23121B631E6FF93D0012B45E /* hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hash.c; path = ../src/hash.c; sourceTree = ""; }; - 23121B641E6FF93D0012B45E /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hash.h; path = ../src/hash.h; sourceTree = ""; }; - 23121B651E6FF93D0012B45E /* printf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = printf.c; path = ../src/printf.c; sourceTree = ""; }; - 23121B661E6FF93D0012B45E /* random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = random.c; path = ../src/random.c; sourceTree = ""; }; - 23121B671E6FF93D0012B45E /* utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf.c; path = ../src/utf.c; sourceTree = ""; }; - 23121B681E6FF93D0012B45E /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = ../src/util.c; sourceTree = ""; }; - 23121B6A1E6FF93D0012B45E /* crypto_custom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_custom.c; path = ../src/crypto_custom.c; sourceTree = ""; }; - 23121B6B1E6FF93D0012B45E /* vdbe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbe.c; path = ../src/vdbe.c; sourceTree = ""; }; - 23121B6C1E6FF93D0012B45E /* vdbe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbe.h; path = ../src/vdbe.h; sourceTree = ""; }; - 23121B6D1E6FF93D0012B45E /* vdbeaux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeaux.c; path = ../src/vdbeaux.c; sourceTree = ""; }; - 23121B6E1E6FF93D0012B45E /* vdbeblob.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeblob.c; path = ../src/vdbeblob.c; sourceTree = ""; }; - 23121B6F1E6FF93D0012B45E /* vdbeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbeInt.h; path = ../src/vdbeInt.h; sourceTree = ""; }; - 23121B701E6FF93D0012B45E /* vdbemem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbemem.c; path = ../src/vdbemem.c; sourceTree = ""; }; - 23121B711E6FF93D0012B45E /* vdbesort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbesort.c; path = ../src/vdbesort.c; sourceTree = ""; }; - 23121B721E6FF93D0012B45E /* vdbetrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbetrace.c; path = ../src/vdbetrace.c; sourceTree = ""; }; - 23121B741E6FF93D0012B45E /* crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto.c; path = ../src/crypto.c; sourceTree = ""; }; - 23121B751E6FF93D0012B45E /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = ../src/crypto.h; sourceTree = ""; }; - 23121B761E6FF93D0012B45E /* sqlcipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlcipher.h; path = ../src/sqlcipher.h; sourceTree = ""; }; - 23121B771E6FF93D0012B45E /* crypto_cc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_cc.c; path = ../src/crypto_cc.c; sourceTree = ""; }; - 23121B781E6FF93D0012B45E /* crypto_impl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_impl.c; path = ../src/crypto_impl.c; sourceTree = ""; }; - 23121B791E6FF93D0012B45E /* crypto_libtomcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_libtomcrypt.c; path = ../src/crypto_libtomcrypt.c; sourceTree = ""; }; - 23121B7A1E6FF93D0012B45E /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_openssl.c; path = ../src/crypto_openssl.c; sourceTree = ""; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; + 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; + 239528961E700BEB0054D75E /* loadext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loadext.c; path = src/loadext.c; sourceTree = SOURCE_ROOT; }; + 239528981E700BFE0054D75E /* rowset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rowset.c; path = src/rowset.c; sourceTree = SOURCE_ROOT; }; + 2395289A1E700C100054D75E /* treeview.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = treeview.c; path = src/treeview.c; sourceTree = SOURCE_ROOT; }; + 2395289C1E700C1B0054D75E /* userauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = userauth.c; path = ext/userauth/userauth.c; sourceTree = SOURCE_ROOT; }; + 2395289E1E700C250054D75E /* vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vtab.c; path = src/vtab.c; sourceTree = SOURCE_ROOT; }; + 239528A01E700C370054D75E /* btmutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btmutex.c; path = src/btmutex.c; sourceTree = SOURCE_ROOT; }; + 239528A21E700C4A0054D75E /* btree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btree.c; path = src/btree.c; sourceTree = SOURCE_ROOT; }; + 239528A41E700C550054D75E /* btreeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btreeInt.h; path = src/btreeInt.h; sourceTree = SOURCE_ROOT; }; + 239528A61E700C670054D75E /* btree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btree.h; path = src/btree.h; sourceTree = SOURCE_ROOT; }; + 239528A81E700C820054D75E /* fts5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fts5.c; sourceTree = SOURCE_ROOT; }; + 239528A91E700C820054D75E /* fts5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fts5.h; sourceTree = SOURCE_ROOT; }; + 239528AC1E700CB60054D75E /* fts3_aux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_aux.c; path = ext/fts3/fts3_aux.c; sourceTree = SOURCE_ROOT; }; + 239528AD1E700CB60054D75E /* fts3_expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_expr.c; path = ext/fts3/fts3_expr.c; sourceTree = SOURCE_ROOT; }; + 239528AE1E700CB60054D75E /* fts3_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_hash.c; path = ext/fts3/fts3_hash.c; sourceTree = SOURCE_ROOT; }; + 239528AF1E700CB60054D75E /* fts3_hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_hash.h; path = ext/fts3/fts3_hash.h; sourceTree = SOURCE_ROOT; }; + 239528B01E700CB60054D75E /* fts3_icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_icu.c; path = ext/fts3/fts3_icu.c; sourceTree = SOURCE_ROOT; }; + 239528B11E700CB60054D75E /* fts3_porter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_porter.c; path = ext/fts3/fts3_porter.c; sourceTree = SOURCE_ROOT; }; + 239528B21E700CB60054D75E /* fts3_snippet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_snippet.c; path = ext/fts3/fts3_snippet.c; sourceTree = SOURCE_ROOT; }; + 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenize_vtab.c; path = ext/fts3/fts3_tokenize_vtab.c; sourceTree = SOURCE_ROOT; }; + 239528B41E700CB60054D75E /* fts3_tokenizer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer.c; path = ext/fts3/fts3_tokenizer.c; sourceTree = SOURCE_ROOT; }; + 239528B51E700CB60054D75E /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ext/fts3/fts3_tokenizer.h; sourceTree = SOURCE_ROOT; }; + 239528B61E700CB60054D75E /* fts3_tokenizer1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer1.c; path = ext/fts3/fts3_tokenizer1.c; sourceTree = SOURCE_ROOT; }; + 239528B71E700CB60054D75E /* fts3_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode.c; path = ext/fts3/fts3_unicode.c; sourceTree = SOURCE_ROOT; }; + 239528B81E700CB60054D75E /* fts3_unicode2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode2.c; path = ext/fts3/fts3_unicode2.c; sourceTree = SOURCE_ROOT; }; + 239528B91E700CB60054D75E /* fts3_write.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_write.c; path = ext/fts3/fts3_write.c; sourceTree = SOURCE_ROOT; }; + 239528BA1E700CB60054D75E /* fts3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3.c; path = ext/fts3/fts3.c; sourceTree = SOURCE_ROOT; }; + 239528BB1E700CB60054D75E /* fts3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3.h; path = ext/fts3/fts3.h; sourceTree = SOURCE_ROOT; }; + 239528BC1E700CB60054D75E /* fts3Int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3Int.h; path = ext/fts3/fts3Int.h; sourceTree = SOURCE_ROOT; }; + 239528CE1E700CC30054D75E /* backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = backup.c; path = src/backup.c; sourceTree = SOURCE_ROOT; }; + 239528D01E700CCD0054D75E /* legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = legacy.c; path = src/legacy.c; sourceTree = SOURCE_ROOT; }; + 239528D21E700CD70054D75E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = SOURCE_ROOT; }; + 239528D41E700CE10054D75E /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = src/notify.c; sourceTree = SOURCE_ROOT; }; + 239528D61E700CED0054D75E /* vdbeapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeapi.c; path = src/vdbeapi.c; sourceTree = SOURCE_ROOT; }; + 239528D81E700CFB0054D75E /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = table.c; path = src/table.c; sourceTree = SOURCE_ROOT; }; + 239528DA1E700D0A0054D75E /* wal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wal.c; path = src/wal.c; sourceTree = SOURCE_ROOT; }; + 239528DB1E700D0A0054D75E /* wal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wal.h; path = src/wal.h; sourceTree = SOURCE_ROOT; }; + 239528DE1E700D170054D75E /* status.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = status.c; path = src/status.c; sourceTree = SOURCE_ROOT; }; + 239528E01E700D220054D75E /* prepare.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prepare.c; path = src/prepare.c; sourceTree = SOURCE_ROOT; }; + 239528E21E700D320054D75E /* malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = malloc.c; path = src/malloc.c; sourceTree = SOURCE_ROOT; }; + 239528E41E700D460054D75E /* mem0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem0.c; path = src/mem0.c; sourceTree = SOURCE_ROOT; }; + 239528E51E700D460054D75E /* mem1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem1.c; path = src/mem1.c; sourceTree = SOURCE_ROOT; }; + 239528E61E700D460054D75E /* mem2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem2.c; path = src/mem2.c; sourceTree = SOURCE_ROOT; }; + 239528E71E700D460054D75E /* mem3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem3.c; path = src/mem3.c; sourceTree = SOURCE_ROOT; }; + 239528E81E700D460054D75E /* mem5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem5.c; path = src/mem5.c; sourceTree = SOURCE_ROOT; }; + 239528EE1E700D4A0054D75E /* memjournal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memjournal.c; path = src/memjournal.c; sourceTree = SOURCE_ROOT; }; + 239528F01E700D570054D75E /* mutex_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_unix.c; path = src/mutex_unix.c; sourceTree = SOURCE_ROOT; }; + 239528F21E700D600054D75E /* mutex_noop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_noop.c; path = src/mutex_noop.c; sourceTree = SOURCE_ROOT; }; + 239528F41E700D6C0054D75E /* mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex.c; path = src/mutex.c; sourceTree = SOURCE_ROOT; }; + 239528F51E700D6C0054D75E /* mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex.h; path = src/mutex.h; sourceTree = SOURCE_ROOT; }; + 239528F81E700D790054D75E /* os_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_common.h; path = src/os_common.h; sourceTree = SOURCE_ROOT; }; + 239528F91E700D790054D75E /* os_setup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_setup.h; path = src/os_setup.h; sourceTree = SOURCE_ROOT; }; + 239528FA1E700D790054D75E /* os_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_unix.c; path = src/os_unix.c; sourceTree = SOURCE_ROOT; }; + 239528FE1E700D880054D75E /* os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os.c; path = src/os.c; sourceTree = SOURCE_ROOT; }; + 239528FF1E700D880054D75E /* os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os.h; path = src/os.h; sourceTree = SOURCE_ROOT; }; + 239529021E700D920054D75E /* threads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threads.c; path = src/threads.c; sourceTree = SOURCE_ROOT; }; + 239529041E700D9D0054D75E /* bitvec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitvec.c; path = src/bitvec.c; sourceTree = SOURCE_ROOT; }; + 239529061E700DA70054D75E /* pager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pager.c; path = src/pager.c; sourceTree = SOURCE_ROOT; }; + 239529071E700DA70054D75E /* pager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pager.h; path = src/pager.h; sourceTree = SOURCE_ROOT; }; + 2395290A1E700DB90054D75E /* pcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache.c; path = src/pcache.c; sourceTree = SOURCE_ROOT; }; + 2395290B1E700DB90054D75E /* pcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pcache.h; path = src/pcache.h; sourceTree = SOURCE_ROOT; }; + 2395290C1E700DB90054D75E /* pcache1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache1.c; path = src/pcache1.c; sourceTree = SOURCE_ROOT; }; + 239529101E700DD10054D75E /* rtree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rtree.c; path = ext/rtree/rtree.c; sourceTree = SOURCE_ROOT; }; + 239529111E700DD10054D75E /* rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rtree.h; path = ext/rtree/rtree.h; sourceTree = SOURCE_ROOT; }; + 239529121E700DD10054D75E /* sqlite3rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rtree.h; path = ext/rtree/sqlite3rtree.h; sourceTree = SOURCE_ROOT; }; + 239529161E700DDF0054D75E /* complete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = complete.c; path = src/complete.c; sourceTree = SOURCE_ROOT; }; + 239529181E700DED0054D75E /* tokenize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tokenize.c; path = src/tokenize.c; sourceTree = SOURCE_ROOT; }; + 2395291A1E700DFD0054D75E /* resolve.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = resolve.c; path = src/resolve.c; sourceTree = SOURCE_ROOT; }; + 2395291C1E700E080054D75E /* parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parse.c; sourceTree = SOURCE_ROOT; }; + 2395291D1E700E080054D75E /* parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parse.h; sourceTree = SOURCE_ROOT; }; + 239529201E700E170054D75E /* analyze.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = analyze.c; path = src/analyze.c; sourceTree = SOURCE_ROOT; }; + 239529221E700E1E0054D75E /* func.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = func.c; path = src/func.c; sourceTree = SOURCE_ROOT; }; + 239529241E700E280054D75E /* wherecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wherecode.c; path = src/wherecode.c; sourceTree = SOURCE_ROOT; }; + 239529261E700E2F0054D75E /* whereexpr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = whereexpr.c; path = src/whereexpr.c; sourceTree = SOURCE_ROOT; }; + 239529281E700E340054D75E /* whereInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = whereInt.h; path = src/whereInt.h; sourceTree = SOURCE_ROOT; }; + 2395292A1E700E3C0054D75E /* alter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alter.c; path = src/alter.c; sourceTree = SOURCE_ROOT; }; + 2395292C1E700E450054D75E /* attach.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = attach.c; path = src/attach.c; sourceTree = SOURCE_ROOT; }; + 2395292E1E700E4C0054D75E /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = src/auth.c; sourceTree = SOURCE_ROOT; }; + 239529301E700E590054D75E /* build.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = build.c; path = src/build.c; sourceTree = SOURCE_ROOT; }; + 239529321E700E5F0054D75E /* delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = delete.c; path = src/delete.c; sourceTree = SOURCE_ROOT; }; + 239529341E700E660054D75E /* expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = expr.c; path = src/expr.c; sourceTree = SOURCE_ROOT; }; + 239529361E700E6D0054D75E /* insert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = insert.c; path = src/insert.c; sourceTree = SOURCE_ROOT; }; + 239529381E700E780054D75E /* pragma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pragma.c; path = src/pragma.c; sourceTree = SOURCE_ROOT; }; + 239529391E700E780054D75E /* pragma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pragma.h; path = src/pragma.h; sourceTree = SOURCE_ROOT; }; + 2395293C1E700E810054D75E /* select.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = select.c; path = src/select.c; sourceTree = SOURCE_ROOT; }; + 2395293E1E700E8A0054D75E /* trigger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trigger.c; path = src/trigger.c; sourceTree = SOURCE_ROOT; }; + 239529401E700E910054D75E /* update.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = update.c; path = src/update.c; sourceTree = SOURCE_ROOT; }; + 239529421E700E9C0054D75E /* vacuum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vacuum.c; path = src/vacuum.c; sourceTree = SOURCE_ROOT; }; + 239529441E700EA40054D75E /* walker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = walker.c; path = src/walker.c; sourceTree = SOURCE_ROOT; }; + 239529461E700EAF0054D75E /* where.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = where.c; path = src/where.c; sourceTree = SOURCE_ROOT; }; + 239529481E700EBC0054D75E /* opcodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opcodes.c; sourceTree = SOURCE_ROOT; }; + 239529491E700EBC0054D75E /* opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcodes.h; sourceTree = SOURCE_ROOT; }; + 2395294C1E700EE70054D75E /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = SOURCE_ROOT; }; + 2395294D1E700EE70054D75E /* sqlite3rbu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sqlite3rbu.c; path = ext/rbu/sqlite3rbu.c; sourceTree = SOURCE_ROOT; }; + 2395294E1E700EE70054D75E /* sqlite3rbu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rbu.h; path = ext/rbu/sqlite3rbu.h; sourceTree = SOURCE_ROOT; }; + 2395294F1E700EE70054D75E /* sqlite3userauth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3userauth.h; path = ext/userauth/sqlite3userauth.h; sourceTree = SOURCE_ROOT; }; + 239529541E700EF00054D75E /* json1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = json1.c; path = ext/misc/json1.c; sourceTree = SOURCE_ROOT; }; + 239529561E700EF90054D75E /* icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = icu.c; path = ext/icu/icu.c; sourceTree = SOURCE_ROOT; }; + 239529581E700F060054D75E /* sqliteicu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteicu.h; path = ext/icu/sqliteicu.h; sourceTree = SOURCE_ROOT; }; + 2395295A1E700F0F0054D75E /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = global.c; path = src/global.c; sourceTree = SOURCE_ROOT; }; + 2395295C1E700F170054D75E /* ctime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctime.c; path = src/ctime.c; sourceTree = SOURCE_ROOT; }; + 2395295E1E700F200054D75E /* hwtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwtime.h; path = src/hwtime.h; sourceTree = SOURCE_ROOT; }; + 239529601E700F2C0054D75E /* date.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = date.c; path = src/date.c; sourceTree = SOURCE_ROOT; }; + 239529621E700F360054D75E /* dbstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dbstat.c; path = src/dbstat.c; sourceTree = SOURCE_ROOT; }; + 239529641E700F410054D75E /* fault.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fault.c; path = src/fault.c; sourceTree = SOURCE_ROOT; }; + 239529661E700F490054D75E /* fkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fkey.c; path = src/fkey.c; sourceTree = SOURCE_ROOT; }; + 239529681E700F570054D75E /* sqliteInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteInt.h; path = src/sqliteInt.h; sourceTree = SOURCE_ROOT; }; + 2395296A1E700F600054D75E /* sqliteLimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteLimit.h; path = src/sqliteLimit.h; sourceTree = SOURCE_ROOT; }; + 2395296C1E700F6C0054D75E /* sqlite3ext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3ext.h; path = src/sqlite3ext.h; sourceTree = SOURCE_ROOT; }; + 2395296E1E700F760054D75E /* hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hash.c; path = src/hash.c; sourceTree = SOURCE_ROOT; }; + 2395296F1E700F760054D75E /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hash.h; path = src/hash.h; sourceTree = SOURCE_ROOT; }; + 239529721E700F7F0054D75E /* printf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = printf.c; path = src/printf.c; sourceTree = SOURCE_ROOT; }; + 239529741E700F870054D75E /* random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = random.c; path = src/random.c; sourceTree = SOURCE_ROOT; }; + 239529761E700F940054D75E /* utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf.c; path = src/utf.c; sourceTree = SOURCE_ROOT; }; + 239529771E700F940054D75E /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = src/util.c; sourceTree = SOURCE_ROOT; }; + 2395297A1E700FA60054D75E /* crypto_custom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_custom.c; path = src/crypto_custom.c; sourceTree = SOURCE_ROOT; }; + 2395297C1E700FC60054D75E /* crypto_cc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_cc.c; path = src/crypto_cc.c; sourceTree = SOURCE_ROOT; }; + 2395297D1E700FC60054D75E /* crypto_impl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_impl.c; path = src/crypto_impl.c; sourceTree = SOURCE_ROOT; }; + 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_libtomcrypt.c; path = src/crypto_libtomcrypt.c; sourceTree = SOURCE_ROOT; }; + 2395297F1E700FC60054D75E /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_openssl.c; path = src/crypto_openssl.c; sourceTree = SOURCE_ROOT; }; + 239529801E700FC60054D75E /* crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto.c; path = src/crypto.c; sourceTree = SOURCE_ROOT; }; + 239529811E700FC60054D75E /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = src/crypto.h; sourceTree = SOURCE_ROOT; }; + 239529881E700FD90054D75E /* sqlcipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlcipher.h; path = src/sqlcipher.h; sourceTree = SOURCE_ROOT; }; + 2395298A1E7010030054D75E /* vdbe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbe.c; path = src/vdbe.c; sourceTree = SOURCE_ROOT; }; + 2395298B1E7010030054D75E /* vdbe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbe.h; path = src/vdbe.h; sourceTree = SOURCE_ROOT; }; + 2395298C1E7010030054D75E /* vdbeaux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeaux.c; path = src/vdbeaux.c; sourceTree = SOURCE_ROOT; }; + 2395298D1E7010030054D75E /* vdbeblob.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeblob.c; path = src/vdbeblob.c; sourceTree = SOURCE_ROOT; }; + 2395298E1E7010030054D75E /* vdbeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbeInt.h; path = src/vdbeInt.h; sourceTree = SOURCE_ROOT; }; + 2395298F1E7010030054D75E /* vdbemem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbemem.c; path = src/vdbemem.c; sourceTree = SOURCE_ROOT; }; + 239529901E7010030054D75E /* vdbesort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbesort.c; path = src/vdbesort.c; sourceTree = SOURCE_ROOT; }; + 239529911E7010030054D75E /* vdbetrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbetrace.c; path = src/vdbetrace.c; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -330,252 +318,141 @@ name = Products; sourceTree = ""; }; - 23121AF61E6FF93D0012B45E /* btree */ = { - isa = PBXGroup; - children = ( - 23121AF21E6FF93D0012B45E /* btmutex.c */, - 23121AF31E6FF93D0012B45E /* btree.c */, - 23121AF41E6FF93D0012B45E /* btree.h */, - 23121AF51E6FF93D0012B45E /* btreeInt.h */, - ); - name = btree; - sourceTree = ""; - }; - 23121B0A1E6FF93D0012B45E /* fts */ = { - isa = PBXGroup; - children = ( - 23121AF71E6FF93D0012B45E /* fts5.c */, - 23121AF81E6FF93D0012B45E /* fts5.h */, - 23121AF91E6FF93D0012B45E /* fts3_aux.c */, - 23121AFA1E6FF93D0012B45E /* fts3_expr.c */, - 23121AFB1E6FF93D0012B45E /* fts3_hash.c */, - 23121AFC1E6FF93D0012B45E /* fts3_hash.h */, - 23121AFD1E6FF93D0012B45E /* fts3_icu.c */, - 23121AFE1E6FF93D0012B45E /* fts3_porter.c */, - 23121AFF1E6FF93D0012B45E /* fts3_snippet.c */, - 23121B001E6FF93D0012B45E /* fts3_tokenize_vtab.c */, - 23121B011E6FF93D0012B45E /* fts3_tokenizer.c */, - 23121B021E6FF93D0012B45E /* fts3_tokenizer.h */, - 23121B031E6FF93D0012B45E /* fts3_tokenizer1.c */, - 23121B041E6FF93D0012B45E /* fts3_unicode.c */, - 23121B051E6FF93D0012B45E /* fts3_unicode2.c */, - 23121B061E6FF93D0012B45E /* fts3_write.c */, - 23121B071E6FF93D0012B45E /* fts3.c */, - 23121B081E6FF93D0012B45E /* fts3.h */, - 23121B091E6FF93D0012B45E /* fts3Int.h */, - ); - name = fts; - sourceTree = ""; - }; - 23121B151E6FF93D0012B45E /* interface */ = { - isa = PBXGroup; - children = ( - 23121B0B1E6FF93D0012B45E /* backup.c */, - 23121B0C1E6FF93D0012B45E /* legacy.c */, - 23121B0D1E6FF93D0012B45E /* main.c */, - 23121B0E1E6FF93D0012B45E /* notify.c */, - 23121B0F1E6FF93D0012B45E /* vdbeapi.c */, - 23121B101E6FF93D0012B45E /* table.c */, - 23121B111E6FF93D0012B45E /* wal.c */, - 23121B121E6FF93D0012B45E /* wal.h */, - 23121B131E6FF93D0012B45E /* status.c */, - 23121B141E6FF93D0012B45E /* prepare.c */, - ); - name = interface; - sourceTree = ""; - }; - 23121B1D1E6FF93D0012B45E /* memory */ = { - isa = PBXGroup; - children = ( - 23121B161E6FF93D0012B45E /* malloc.c */, - 23121B171E6FF93D0012B45E /* mem0.c */, - 23121B181E6FF93D0012B45E /* mem1.c */, - 23121B191E6FF93D0012B45E /* mem2.c */, - 23121B1A1E6FF93D0012B45E /* mem3.c */, - 23121B1B1E6FF93D0012B45E /* mem5.c */, - 23121B1C1E6FF93D0012B45E /* memjournal.c */, - ); - name = memory; - sourceTree = ""; - }; - 23121B271E6FF93D0012B45E /* os interface */ = { - isa = PBXGroup; - children = ( - 23121B1E1E6FF93D0012B45E /* mutex_unix.c */, - 23121B1F1E6FF93D0012B45E /* mutex.c */, - 23121B201E6FF93D0012B45E /* mutex.h */, - 23121B211E6FF93D0012B45E /* os_common.h */, - 23121B221E6FF93D0012B45E /* os_setup.h */, - 23121B231E6FF93D0012B45E /* os_unix.c */, - 23121B241E6FF93D0012B45E /* os.c */, - 23121B251E6FF93D0012B45E /* os.h */, - 23121B261E6FF93D0012B45E /* threads.c */, - ); - name = "os interface"; - sourceTree = ""; - }; - 23121B2E1E6FF93D0012B45E /* page */ = { - isa = PBXGroup; - children = ( - 23121B281E6FF93D0012B45E /* bitvec.c */, - 23121B291E6FF93D0012B45E /* pager.c */, - 23121B2A1E6FF93D0012B45E /* pager.h */, - 23121B2B1E6FF93D0012B45E /* pcache.c */, - 23121B2C1E6FF93D0012B45E /* pcache.h */, - 23121B2D1E6FF93D0012B45E /* pcache1.c */, - ); - name = page; - sourceTree = ""; - }; - 23121B321E6FF93D0012B45E /* rtree */ = { - isa = PBXGroup; - children = ( - 23121B2F1E6FF93D0012B45E /* rtree.c */, - 23121B301E6FF93D0012B45E /* rtree.h */, - 23121B311E6FF93D0012B45E /* sqlite3rtree.h */, - ); - name = rtree; - sourceTree = ""; - }; - 23121B351E6FF93D0012B45E /* tokenizer */ = { - isa = PBXGroup; - children = ( - 23121B331E6FF93D0012B45E /* complete.c */, - 23121B341E6FF93D0012B45E /* tokenize.c */, - ); - name = tokenizer; - sourceTree = ""; - }; - 23121B391E6FF93D0012B45E /* parser */ = { - isa = PBXGroup; - children = ( - 23121B361E6FF93D0012B45E /* resolve.c */, - 23121B371E6FF93D0012B45E /* parse.c */, - 23121B381E6FF93D0012B45E /* parse.h */, - ); - name = parser; - sourceTree = ""; - }; - 23121B501E6FF93D0012B45E /* code generator */ = { - isa = PBXGroup; - children = ( - 23121B3A1E6FF93D0012B45E /* analyze.c */, - 23121B3B1E6FF93D0012B45E /* func.c */, - 23121B3C1E6FF93D0012B45E /* wherecode.c */, - 23121B3D1E6FF93D0012B45E /* whereexpr.c */, - 23121B3E1E6FF93D0012B45E /* whereInt.h */, - 23121B3F1E6FF93D0012B45E /* alter.c */, - 23121B401E6FF93D0012B45E /* attach.c */, - 23121B411E6FF93D0012B45E /* auth.c */, - 23121B421E6FF93D0012B45E /* build.c */, - 23121B431E6FF93D0012B45E /* delete.c */, - 23121B441E6FF93D0012B45E /* expr.c */, - 23121B451E6FF93D0012B45E /* insert.c */, - 23121B461E6FF93D0012B45E /* pragma.c */, - 23121B471E6FF93D0012B45E /* pragma.h */, - 23121B481E6FF93D0012B45E /* select.c */, - 23121B491E6FF93D0012B45E /* trigger.c */, - 23121B4A1E6FF93D0012B45E /* update.c */, - 23121B4B1E6FF93D0012B45E /* vacuum.c */, - 23121B4C1E6FF93D0012B45E /* walker.c */, - 23121B4D1E6FF93D0012B45E /* where.c */, - 23121B4E1E6FF93D0012B45E /* opcodes.c */, - 23121B4F1E6FF93D0012B45E /* opcodes.h */, - ); - name = "code generator"; - sourceTree = ""; - }; - 23121B511E6FF93D0012B45E /* sql compiler */ = { - isa = PBXGroup; - children = ( - 23121B351E6FF93D0012B45E /* tokenizer */, - 23121B391E6FF93D0012B45E /* parser */, - 23121B501E6FF93D0012B45E /* code generator */, - ); - name = "sql compiler"; - sourceTree = ""; - }; - 23121B691E6FF93D0012B45E /* utilities */ = { - isa = PBXGroup; - children = ( - 23121B521E6FF93D0012B45E /* sqlite3.h */, - 23121B531E6FF93D0012B45E /* sqlite3userauth.h */, - 23121B541E6FF93D0012B45E /* sqlite3rbu.c */, - 23121B551E6FF93D0012B45E /* sqlite3rbu.h */, - 23121B561E6FF93D0012B45E /* json1.c */, - 23121B571E6FF93D0012B45E /* icu.c */, - 23121B581E6FF93D0012B45E /* sqliteicu.h */, - 23121B591E6FF93D0012B45E /* global.c */, - 23121B5A1E6FF93D0012B45E /* ctime.c */, - 23121B5B1E6FF93D0012B45E /* hwtime.h */, - 23121B5C1E6FF93D0012B45E /* date.c */, - 23121B5D1E6FF93D0012B45E /* dbstat.c */, - 23121B5E1E6FF93D0012B45E /* fault.c */, - 23121B5F1E6FF93D0012B45E /* fkey.c */, - 23121B601E6FF93D0012B45E /* sqliteInt.h */, - 23121B611E6FF93D0012B45E /* sqliteLimit.h */, - 23121B621E6FF93D0012B45E /* sqlite3ext.h */, - 23121B631E6FF93D0012B45E /* hash.c */, - 23121B641E6FF93D0012B45E /* hash.h */, - 23121B651E6FF93D0012B45E /* printf.c */, - 23121B661E6FF93D0012B45E /* random.c */, - 23121B671E6FF93D0012B45E /* utf.c */, - 23121B681E6FF93D0012B45E /* util.c */, - ); - name = utilities; - sourceTree = ""; - }; - 23121B731E6FF93D0012B45E /* vm */ = { - isa = PBXGroup; - children = ( - 23121B6B1E6FF93D0012B45E /* vdbe.c */, - 23121B6C1E6FF93D0012B45E /* vdbe.h */, - 23121B6D1E6FF93D0012B45E /* vdbeaux.c */, - 23121B6E1E6FF93D0012B45E /* vdbeblob.c */, - 23121B6F1E6FF93D0012B45E /* vdbeInt.h */, - 23121B701E6FF93D0012B45E /* vdbemem.c */, - 23121B711E6FF93D0012B45E /* vdbesort.c */, - 23121B721E6FF93D0012B45E /* vdbetrace.c */, - ); - name = vm; - sourceTree = ""; - }; - 23121B7B1E6FF93D0012B45E /* cipher */ = { - isa = PBXGroup; - children = ( - 23121B741E6FF93D0012B45E /* crypto.c */, - 23121B751E6FF93D0012B45E /* crypto.h */, - 23121B761E6FF93D0012B45E /* sqlcipher.h */, - 23121B771E6FF93D0012B45E /* crypto_cc.c */, - 23121B781E6FF93D0012B45E /* crypto_impl.c */, - 23121B791E6FF93D0012B45E /* crypto_libtomcrypt.c */, - 23121B7A1E6FF93D0012B45E /* crypto_openssl.c */, - ); - name = cipher; - sourceTree = ""; - }; 23121B7C1E6FF93D0012B45E /* src */ = { isa = PBXGroup; children = ( - 23121AEB1E6FF93D0012B45E /* keywordhash.h */, - 23121AEC1E6FF93D0012B45E /* callback.c */, - 23121AED1E6FF93D0012B45E /* loadext.c */, - 23121AEE1E6FF93D0012B45E /* rowset.c */, - 23121AEF1E6FF93D0012B45E /* treeview.c */, - 23121AF01E6FF93D0012B45E /* userauth.c */, - 23121AF11E6FF93D0012B45E /* vtab.c */, - 23121AF61E6FF93D0012B45E /* btree */, - 23121B0A1E6FF93D0012B45E /* fts */, - 23121B151E6FF93D0012B45E /* interface */, - 23121B1D1E6FF93D0012B45E /* memory */, - 23121B271E6FF93D0012B45E /* os interface */, - 23121B2E1E6FF93D0012B45E /* page */, - 23121B321E6FF93D0012B45E /* rtree */, - 23121B511E6FF93D0012B45E /* sql compiler */, - 23121B691E6FF93D0012B45E /* utilities */, - 23121B6A1E6FF93D0012B45E /* crypto_custom.c */, - 23121B731E6FF93D0012B45E /* vm */, - 23121B7B1E6FF93D0012B45E /* cipher */, + 239528921E700BBC0054D75E /* keywordhash.h */, + 239528941E700BCB0054D75E /* callback.c */, + 239528961E700BEB0054D75E /* loadext.c */, + 239528981E700BFE0054D75E /* rowset.c */, + 2395289A1E700C100054D75E /* treeview.c */, + 2395289C1E700C1B0054D75E /* userauth.c */, + 2395289E1E700C250054D75E /* vtab.c */, + 239528A01E700C370054D75E /* btmutex.c */, + 239528A21E700C4A0054D75E /* btree.c */, + 239528A41E700C550054D75E /* btreeInt.h */, + 239528A61E700C670054D75E /* btree.h */, + 239528A81E700C820054D75E /* fts5.c */, + 239528A91E700C820054D75E /* fts5.h */, + 239528AC1E700CB60054D75E /* fts3_aux.c */, + 239528AD1E700CB60054D75E /* fts3_expr.c */, + 239528AE1E700CB60054D75E /* fts3_hash.c */, + 239528AF1E700CB60054D75E /* fts3_hash.h */, + 239528B01E700CB60054D75E /* fts3_icu.c */, + 239528B11E700CB60054D75E /* fts3_porter.c */, + 239528B21E700CB60054D75E /* fts3_snippet.c */, + 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */, + 239528B41E700CB60054D75E /* fts3_tokenizer.c */, + 239528B51E700CB60054D75E /* fts3_tokenizer.h */, + 239528B61E700CB60054D75E /* fts3_tokenizer1.c */, + 239528B71E700CB60054D75E /* fts3_unicode.c */, + 239528B81E700CB60054D75E /* fts3_unicode2.c */, + 239528B91E700CB60054D75E /* fts3_write.c */, + 239528BA1E700CB60054D75E /* fts3.c */, + 239528BB1E700CB60054D75E /* fts3.h */, + 239528BC1E700CB60054D75E /* fts3Int.h */, + 239528CE1E700CC30054D75E /* backup.c */, + 239528D01E700CCD0054D75E /* legacy.c */, + 239528D21E700CD70054D75E /* main.c */, + 239528D41E700CE10054D75E /* notify.c */, + 239528D61E700CED0054D75E /* vdbeapi.c */, + 239528D81E700CFB0054D75E /* table.c */, + 239528DA1E700D0A0054D75E /* wal.c */, + 239528DB1E700D0A0054D75E /* wal.h */, + 239528DE1E700D170054D75E /* status.c */, + 239528E01E700D220054D75E /* prepare.c */, + 239528E21E700D320054D75E /* malloc.c */, + 239528E41E700D460054D75E /* mem0.c */, + 239528E51E700D460054D75E /* mem1.c */, + 239528E61E700D460054D75E /* mem2.c */, + 239528E71E700D460054D75E /* mem3.c */, + 239528E81E700D460054D75E /* mem5.c */, + 239528EE1E700D4A0054D75E /* memjournal.c */, + 239528F01E700D570054D75E /* mutex_unix.c */, + 239528F21E700D600054D75E /* mutex_noop.c */, + 239528F41E700D6C0054D75E /* mutex.c */, + 239528F51E700D6C0054D75E /* mutex.h */, + 239528F81E700D790054D75E /* os_common.h */, + 239528F91E700D790054D75E /* os_setup.h */, + 239528FA1E700D790054D75E /* os_unix.c */, + 239528FE1E700D880054D75E /* os.c */, + 239528FF1E700D880054D75E /* os.h */, + 239529021E700D920054D75E /* threads.c */, + 239529041E700D9D0054D75E /* bitvec.c */, + 239529061E700DA70054D75E /* pager.c */, + 239529071E700DA70054D75E /* pager.h */, + 2395290A1E700DB90054D75E /* pcache.c */, + 2395290B1E700DB90054D75E /* pcache.h */, + 2395290C1E700DB90054D75E /* pcache1.c */, + 239529101E700DD10054D75E /* rtree.c */, + 239529111E700DD10054D75E /* rtree.h */, + 239529121E700DD10054D75E /* sqlite3rtree.h */, + 239529161E700DDF0054D75E /* complete.c */, + 239529181E700DED0054D75E /* tokenize.c */, + 2395291A1E700DFD0054D75E /* resolve.c */, + 2395291C1E700E080054D75E /* parse.c */, + 2395291D1E700E080054D75E /* parse.h */, + 239529201E700E170054D75E /* analyze.c */, + 239529221E700E1E0054D75E /* func.c */, + 239529241E700E280054D75E /* wherecode.c */, + 239529261E700E2F0054D75E /* whereexpr.c */, + 239529281E700E340054D75E /* whereInt.h */, + 2395292A1E700E3C0054D75E /* alter.c */, + 2395292C1E700E450054D75E /* attach.c */, + 2395292E1E700E4C0054D75E /* auth.c */, + 239529301E700E590054D75E /* build.c */, + 239529321E700E5F0054D75E /* delete.c */, + 239529341E700E660054D75E /* expr.c */, + 239529361E700E6D0054D75E /* insert.c */, + 239529381E700E780054D75E /* pragma.c */, + 239529391E700E780054D75E /* pragma.h */, + 2395293C1E700E810054D75E /* select.c */, + 2395293E1E700E8A0054D75E /* trigger.c */, + 239529401E700E910054D75E /* update.c */, + 239529421E700E9C0054D75E /* vacuum.c */, + 239529441E700EA40054D75E /* walker.c */, + 239529461E700EAF0054D75E /* where.c */, + 239529481E700EBC0054D75E /* opcodes.c */, + 239529491E700EBC0054D75E /* opcodes.h */, + 239529881E700FD90054D75E /* sqlcipher.h */, + 2395294C1E700EE70054D75E /* sqlite3.h */, + 2395294D1E700EE70054D75E /* sqlite3rbu.c */, + 2395294E1E700EE70054D75E /* sqlite3rbu.h */, + 2395294F1E700EE70054D75E /* sqlite3userauth.h */, + 239529541E700EF00054D75E /* json1.c */, + 239529561E700EF90054D75E /* icu.c */, + 239529581E700F060054D75E /* sqliteicu.h */, + 2395295A1E700F0F0054D75E /* global.c */, + 2395295C1E700F170054D75E /* ctime.c */, + 2395295E1E700F200054D75E /* hwtime.h */, + 239529601E700F2C0054D75E /* date.c */, + 239529621E700F360054D75E /* dbstat.c */, + 239529641E700F410054D75E /* fault.c */, + 239529661E700F490054D75E /* fkey.c */, + 239529681E700F570054D75E /* sqliteInt.h */, + 2395296A1E700F600054D75E /* sqliteLimit.h */, + 2395296C1E700F6C0054D75E /* sqlite3ext.h */, + 2395296E1E700F760054D75E /* hash.c */, + 2395296F1E700F760054D75E /* hash.h */, + 239529721E700F7F0054D75E /* printf.c */, + 239529741E700F870054D75E /* random.c */, + 239529761E700F940054D75E /* utf.c */, + 239529771E700F940054D75E /* util.c */, + 2395297A1E700FA60054D75E /* crypto_custom.c */, + 2395297C1E700FC60054D75E /* crypto_cc.c */, + 2395297D1E700FC60054D75E /* crypto_impl.c */, + 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */, + 2395297F1E700FC60054D75E /* crypto_openssl.c */, + 239529801E700FC60054D75E /* crypto.c */, + 239529811E700FC60054D75E /* crypto.h */, + 2395298A1E7010030054D75E /* vdbe.c */, + 2395298B1E7010030054D75E /* vdbe.h */, + 2395298C1E7010030054D75E /* vdbeaux.c */, + 2395298D1E7010030054D75E /* vdbeblob.c */, + 2395298E1E7010030054D75E /* vdbeInt.h */, + 2395298F1E7010030054D75E /* vdbemem.c */, + 239529901E7010030054D75E /* vdbesort.c */, + 239529911E7010030054D75E /* vdbetrace.c */, ); name = src; path = "sqlcipher-preprocessed"; @@ -596,45 +473,62 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 23121BDC1E6FF93D0012B45E /* sqlite3rbu.h in Headers */, - 23121BE71E6FF93D0012B45E /* sqliteInt.h in Headers */, - 23121BFA1E6FF93D0012B45E /* crypto.h in Headers */, - 23121BD91E6FF93D0012B45E /* sqlite3.h in Headers */, - 23121BAE1E6FF93D0012B45E /* mutex.h in Headers */, - 23121BF21E6FF93D0012B45E /* vdbe.h in Headers */, - 23121BDF1E6FF93D0012B45E /* sqliteicu.h in Headers */, - 23121B931E6FF93D0012B45E /* fts3_tokenizer.h in Headers */, - 23121BBD1E6FF93D0012B45E /* sqlite3rtree.h in Headers */, - 23121BB71E6FF93D0012B45E /* pager.h in Headers */, - 23121BDA1E6FF93D0012B45E /* sqlite3userauth.h in Headers */, - 23121BB01E6FF93D0012B45E /* os_setup.h in Headers */, - 23121BF51E6FF93D0012B45E /* vdbeInt.h in Headers */, - 23121B8D1E6FF93D0012B45E /* fts3_hash.h in Headers */, - 23121BE21E6FF93D0012B45E /* hwtime.h in Headers */, - 23121BC21E6FF93D0012B45E /* parse.h in Headers */, - 23121BD81E6FF93D0012B45E /* opcodes.h in Headers */, - 23121B9A1E6FF93D0012B45E /* fts3Int.h in Headers */, - 23121BA21E6FF93D0012B45E /* wal.h in Headers */, - 23121BE81E6FF93D0012B45E /* sqliteLimit.h in Headers */, - 23121BB31E6FF93D0012B45E /* os.h in Headers */, - 23121BE91E6FF93D0012B45E /* sqlite3ext.h in Headers */, - 23121BD01E6FF93D0012B45E /* pragma.h in Headers */, - 23121BEB1E6FF93D0012B45E /* hash.h in Headers */, - 23121B7D1E6FF93D0012B45E /* keywordhash.h in Headers */, - 23121BAF1E6FF93D0012B45E /* os_common.h in Headers */, - 23121BFB1E6FF93D0012B45E /* sqlcipher.h in Headers */, - 23121B871E6FF93D0012B45E /* btreeInt.h in Headers */, - 23121B891E6FF93D0012B45E /* fts5.h in Headers */, - 23121BB91E6FF93D0012B45E /* pcache.h in Headers */, - 23121B861E6FF93D0012B45E /* btree.h in Headers */, - 23121B991E6FF93D0012B45E /* fts3.h in Headers */, - 23121BC71E6FF93D0012B45E /* whereInt.h in Headers */, - 23121BBC1E6FF93D0012B45E /* rtree.h in Headers */, + 239528FC1E700D790054D75E /* os_setup.h in Headers */, + 239528C01E700CB60054D75E /* fts3_hash.h in Headers */, + 2395296D1E700F6C0054D75E /* sqlite3ext.h in Headers */, + 239528C61E700CB60054D75E /* fts3_tokenizer.h in Headers */, + 239529141E700DD10054D75E /* rtree.h in Headers */, + 239529691E700F570054D75E /* sqliteInt.h in Headers */, + 2395293B1E700E780054D75E /* pragma.h in Headers */, + 239528A71E700C670054D75E /* btree.h in Headers */, + 239528A51E700C550054D75E /* btreeInt.h in Headers */, + 2395296B1E700F600054D75E /* sqliteLimit.h in Headers */, + 239529931E7010030054D75E /* vdbe.h in Headers */, + 239529891E700FD90054D75E /* sqlcipher.h in Headers */, + 239529531E700EE70054D75E /* sqlite3userauth.h in Headers */, + 239529521E700EE70054D75E /* sqlite3rbu.h in Headers */, + 239529711E700F760054D75E /* hash.h in Headers */, + 239528F71E700D6C0054D75E /* mutex.h in Headers */, + 239528AB1E700C820054D75E /* fts5.h in Headers */, + 239528931E700BBC0054D75E /* keywordhash.h in Headers */, + 2395290E1E700DB90054D75E /* pcache.h in Headers */, + 2395294B1E700EBC0054D75E /* opcodes.h in Headers */, + 239529151E700DD10054D75E /* sqlite3rtree.h in Headers */, + 2395295F1E700F200054D75E /* hwtime.h in Headers */, + 239528CD1E700CB60054D75E /* fts3Int.h in Headers */, + 2395291F1E700E080054D75E /* parse.h in Headers */, + 239528DD1E700D0A0054D75E /* wal.h in Headers */, + 239529591E700F060054D75E /* sqliteicu.h in Headers */, + 239529501E700EE70054D75E /* sqlite3.h in Headers */, + 239528CC1E700CB60054D75E /* fts3.h in Headers */, + 239529091E700DA70054D75E /* pager.h in Headers */, + 239529961E7010030054D75E /* vdbeInt.h in Headers */, + 239529011E700D880054D75E /* os.h in Headers */, + 239528FB1E700D790054D75E /* os_common.h in Headers */, + 239529291E700E340054D75E /* whereInt.h in Headers */, + 239529871E700FC60054D75E /* crypto.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ +/* Begin PBXLegacyTarget section */ + 2395299B1E702CF90054D75E /* preprocess */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION) -f Makefile.preprocessed"; + buildConfigurationList = 2395299C1E702CF90054D75E /* Build configuration list for PBXLegacyTarget "preprocess" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ""; + dependencies = ( + ); + name = preprocess; + passBuildSettingsInEnvironment = 1; + productName = preprocess; + }; +/* End PBXLegacyTarget section */ + /* Begin PBXNativeTarget section */ 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */ = { isa = PBXNativeTarget; @@ -647,7 +541,7 @@ buildRules = ( ); dependencies = ( - 23121C2D1E6FFFA50012B45E /* PBXTargetDependency */, + 239529A01E702D1E0054D75E /* PBXTargetDependency */, ); name = "sqlcipher-preprocessed"; productName = "sqlcipher-preprocessed"; @@ -667,7 +561,7 @@ CreatedOnToolsVersion = 8.2; ProvisioningStyle = Automatic; }; - 23121C271E6FFEFA0012B45E = { + 2395299B1E702CF90054D75E = { CreatedOnToolsVersion = 8.2; ProvisioningStyle = Automatic; }; @@ -686,139 +580,124 @@ projectRoot = ""; targets = ( 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */, - 23121C271E6FFEFA0012B45E /* configure */, + 2395299B1E702CF90054D75E /* preprocess */, ); }; /* End PBXProject section */ -/* Begin PBXShellScriptBuildPhase section */ - 23121C2B1E6FFF020012B45E /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS=\"-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2\" --disable-amalgamation\nmake opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 23121AE01E6FF9110012B45E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 23121BCE1E6FF93D0012B45E /* insert.c in Sources */, - 23121BD71E6FF93D0012B45E /* opcodes.c in Sources */, - 23121B821E6FF93D0012B45E /* userauth.c in Sources */, - 23121B7E1E6FF93D0012B45E /* callback.c in Sources */, - 23121BB51E6FF93D0012B45E /* bitvec.c in Sources */, - 23121BF01E6FF93D0012B45E /* crypto_custom.c in Sources */, - 23121B8E1E6FF93D0012B45E /* fts3_icu.c in Sources */, - 23121BDD1E6FF93D0012B45E /* json1.c in Sources */, - 23121BEA1E6FF93D0012B45E /* hash.c in Sources */, - 23121B8F1E6FF93D0012B45E /* fts3_porter.c in Sources */, - 23121B851E6FF93D0012B45E /* btree.c in Sources */, - 23121BCC1E6FF93D0012B45E /* delete.c in Sources */, - 23121BC31E6FF93D0012B45E /* analyze.c in Sources */, - 23121BAB1E6FF93D0012B45E /* memjournal.c in Sources */, - 23121BFC1E6FF93D0012B45E /* crypto_cc.c in Sources */, - 23121BDB1E6FF93D0012B45E /* sqlite3rbu.c in Sources */, - 23121B8C1E6FF93D0012B45E /* fts3_hash.c in Sources */, - 23121BFF1E6FF93D0012B45E /* crypto_openssl.c in Sources */, - 23121BF71E6FF93D0012B45E /* vdbesort.c in Sources */, - 23121BC51E6FF93D0012B45E /* wherecode.c in Sources */, - 23121BF31E6FF93D0012B45E /* vdbeaux.c in Sources */, - 23121BA11E6FF93D0012B45E /* wal.c in Sources */, - 23121BA31E6FF93D0012B45E /* status.c in Sources */, - 23121BBF1E6FF93D0012B45E /* tokenize.c in Sources */, - 23121B901E6FF93D0012B45E /* fts3_snippet.c in Sources */, - 23121B831E6FF93D0012B45E /* vtab.c in Sources */, - 23121BEE1E6FF93D0012B45E /* utf.c in Sources */, - 23121BF91E6FF93D0012B45E /* crypto.c in Sources */, - 23121BCF1E6FF93D0012B45E /* pragma.c in Sources */, - 23121BC81E6FF93D0012B45E /* alter.c in Sources */, - 23121BA81E6FF93D0012B45E /* mem2.c in Sources */, - 23121BD21E6FF93D0012B45E /* trigger.c in Sources */, - 23121B881E6FF93D0012B45E /* fts5.c in Sources */, - 23121BF11E6FF93D0012B45E /* vdbe.c in Sources */, - 23121B981E6FF93D0012B45E /* fts3.c in Sources */, - 23121BA91E6FF93D0012B45E /* mem3.c in Sources */, - 23121BB21E6FF93D0012B45E /* os.c in Sources */, - 23121B9E1E6FF93D0012B45E /* notify.c in Sources */, - 23121BAC1E6FF93D0012B45E /* mutex_unix.c in Sources */, - 23121BBA1E6FF93D0012B45E /* pcache1.c in Sources */, - 23121BD51E6FF93D0012B45E /* walker.c in Sources */, - 23121BCB1E6FF93D0012B45E /* build.c in Sources */, - 23121BEF1E6FF93D0012B45E /* util.c in Sources */, - 23121B911E6FF93D0012B45E /* fts3_tokenize_vtab.c in Sources */, - 23121BF61E6FF93D0012B45E /* vdbemem.c in Sources */, - 23121BF41E6FF93D0012B45E /* vdbeblob.c in Sources */, - 23121BC01E6FF93D0012B45E /* resolve.c in Sources */, - 23121B7F1E6FF93D0012B45E /* loadext.c in Sources */, - 23121BA41E6FF93D0012B45E /* prepare.c in Sources */, - 23121B9F1E6FF93D0012B45E /* vdbeapi.c in Sources */, - 23121BD41E6FF93D0012B45E /* vacuum.c in Sources */, - 23121BA51E6FF93D0012B45E /* malloc.c in Sources */, - 23121BFD1E6FF93D0012B45E /* crypto_impl.c in Sources */, - 23121BE31E6FF93D0012B45E /* date.c in Sources */, - 23121BC91E6FF93D0012B45E /* attach.c in Sources */, - 23121B8B1E6FF93D0012B45E /* fts3_expr.c in Sources */, - 23121B921E6FF93D0012B45E /* fts3_tokenizer.c in Sources */, - 23121BA01E6FF93D0012B45E /* table.c in Sources */, - 23121B8A1E6FF93D0012B45E /* fts3_aux.c in Sources */, - 23121BAA1E6FF93D0012B45E /* mem5.c in Sources */, - 23121B9D1E6FF93D0012B45E /* main.c in Sources */, - 23121BE51E6FF93D0012B45E /* fault.c in Sources */, - 23121BB61E6FF93D0012B45E /* pager.c in Sources */, - 23121BFE1E6FF93D0012B45E /* crypto_libtomcrypt.c in Sources */, - 23121BB11E6FF93D0012B45E /* os_unix.c in Sources */, - 23121BBE1E6FF93D0012B45E /* complete.c in Sources */, - 23121BC61E6FF93D0012B45E /* whereexpr.c in Sources */, - 23121BDE1E6FF93D0012B45E /* icu.c in Sources */, - 23121BED1E6FF93D0012B45E /* random.c in Sources */, - 23121B951E6FF93D0012B45E /* fts3_unicode.c in Sources */, - 23121B811E6FF93D0012B45E /* treeview.c in Sources */, - 23121BE41E6FF93D0012B45E /* dbstat.c in Sources */, - 23121BD11E6FF93D0012B45E /* select.c in Sources */, - 23121B9B1E6FF93D0012B45E /* backup.c in Sources */, - 23121B971E6FF93D0012B45E /* fts3_write.c in Sources */, - 23121BD61E6FF93D0012B45E /* where.c in Sources */, - 23121BA71E6FF93D0012B45E /* mem1.c in Sources */, - 23121B961E6FF93D0012B45E /* fts3_unicode2.c in Sources */, - 23121BA61E6FF93D0012B45E /* mem0.c in Sources */, - 23121BAD1E6FF93D0012B45E /* mutex.c in Sources */, - 23121BCA1E6FF93D0012B45E /* auth.c in Sources */, - 23121BC41E6FF93D0012B45E /* func.c in Sources */, - 23121BEC1E6FF93D0012B45E /* printf.c in Sources */, - 23121BB41E6FF93D0012B45E /* threads.c in Sources */, - 23121BBB1E6FF93D0012B45E /* rtree.c in Sources */, - 23121BF81E6FF93D0012B45E /* vdbetrace.c in Sources */, - 23121BE11E6FF93D0012B45E /* ctime.c in Sources */, - 23121BE61E6FF93D0012B45E /* fkey.c in Sources */, - 23121BE01E6FF93D0012B45E /* global.c in Sources */, - 23121B801E6FF93D0012B45E /* rowset.c in Sources */, - 23121BD31E6FF93D0012B45E /* update.c in Sources */, - 23121BCD1E6FF93D0012B45E /* expr.c in Sources */, - 23121B841E6FF93D0012B45E /* btmutex.c in Sources */, - 23121B9C1E6FF93D0012B45E /* legacy.c in Sources */, - 23121B941E6FF93D0012B45E /* fts3_tokenizer1.c in Sources */, - 23121BB81E6FF93D0012B45E /* pcache.c in Sources */, - 23121BC11E6FF93D0012B45E /* parse.c in Sources */, + 239528E11E700D220054D75E /* prepare.c in Sources */, + 2395289B1E700C100054D75E /* treeview.c in Sources */, + 239529431E700E9C0054D75E /* vacuum.c in Sources */, + 239528AA1E700C820054D75E /* fts5.c in Sources */, + 239528A31E700C4A0054D75E /* btree.c in Sources */, + 239528C91E700CB60054D75E /* fts3_unicode2.c in Sources */, + 239529701E700F760054D75E /* hash.c in Sources */, + 239529841E700FC60054D75E /* crypto_libtomcrypt.c in Sources */, + 239529651E700F410054D75E /* fault.c in Sources */, + 239528ED1E700D460054D75E /* mem5.c in Sources */, + 239529031E700D920054D75E /* threads.c in Sources */, + 239529171E700DDF0054D75E /* complete.c in Sources */, + 239529471E700EAF0054D75E /* where.c in Sources */, + 239529611E700F2C0054D75E /* date.c in Sources */, + 2395293F1E700E8A0054D75E /* trigger.c in Sources */, + 239528F11E700D570054D75E /* mutex_unix.c in Sources */, + 239528C71E700CB60054D75E /* fts3_tokenizer1.c in Sources */, + 239528CB1E700CB60054D75E /* fts3.c in Sources */, + 239528D51E700CE10054D75E /* notify.c in Sources */, + 2395293D1E700E810054D75E /* select.c in Sources */, + 239529981E7010030054D75E /* vdbesort.c in Sources */, + 2395295B1E700F0F0054D75E /* global.c in Sources */, + 239529751E700F870054D75E /* random.c in Sources */, + 239529451E700EA40054D75E /* walker.c in Sources */, + 239529781E700F940054D75E /* utf.c in Sources */, + 239528DF1E700D170054D75E /* status.c in Sources */, + 2395297B1E700FA60054D75E /* crypto_custom.c in Sources */, + 239528E31E700D320054D75E /* malloc.c in Sources */, + 239528F31E700D600054D75E /* mutex_noop.c in Sources */, + 2395294A1E700EBC0054D75E /* opcodes.c in Sources */, + 239529791E700F940054D75E /* util.c in Sources */, + 239528C51E700CB60054D75E /* fts3_tokenizer.c in Sources */, + 239528FD1E700D790054D75E /* os_unix.c in Sources */, + 239528A11E700C370054D75E /* btmutex.c in Sources */, + 239529991E7010030054D75E /* vdbetrace.c in Sources */, + 239529851E700FC60054D75E /* crypto_openssl.c in Sources */, + 2395290F1E700DB90054D75E /* pcache1.c in Sources */, + 2395292F1E700E4C0054D75E /* auth.c in Sources */, + 239528951E700BCB0054D75E /* callback.c in Sources */, + 2395289F1E700C250054D75E /* vtab.c in Sources */, + 239528EC1E700D460054D75E /* mem3.c in Sources */, + 239528C11E700CB60054D75E /* fts3_icu.c in Sources */, + 239529921E7010030054D75E /* vdbe.c in Sources */, + 239528D31E700CD70054D75E /* main.c in Sources */, + 2395289D1E700C1B0054D75E /* userauth.c in Sources */, + 239529551E700EF00054D75E /* json1.c in Sources */, + 239529271E700E2F0054D75E /* whereexpr.c in Sources */, + 239529351E700E660054D75E /* expr.c in Sources */, + 239529671E700F490054D75E /* fkey.c in Sources */, + 239528C41E700CB60054D75E /* fts3_tokenize_vtab.c in Sources */, + 239529131E700DD10054D75E /* rtree.c in Sources */, + 2395291B1E700DFD0054D75E /* resolve.c in Sources */, + 239529051E700D9D0054D75E /* bitvec.c in Sources */, + 239529331E700E5F0054D75E /* delete.c in Sources */, + 239529001E700D880054D75E /* os.c in Sources */, + 239528C31E700CB60054D75E /* fts3_snippet.c in Sources */, + 239528DC1E700D0A0054D75E /* wal.c in Sources */, + 239529831E700FC60054D75E /* crypto_impl.c in Sources */, + 239528D11E700CCD0054D75E /* legacy.c in Sources */, + 2395292B1E700E3C0054D75E /* alter.c in Sources */, + 239528BF1E700CB60054D75E /* fts3_hash.c in Sources */, + 239529191E700DED0054D75E /* tokenize.c in Sources */, + 239529941E7010030054D75E /* vdbeaux.c in Sources */, + 239529571E700EF90054D75E /* icu.c in Sources */, + 239528C81E700CB60054D75E /* fts3_unicode.c in Sources */, + 239528BD1E700CB60054D75E /* fts3_aux.c in Sources */, + 239528EB1E700D460054D75E /* mem2.c in Sources */, + 239529971E7010030054D75E /* vdbemem.c in Sources */, + 239529211E700E170054D75E /* analyze.c in Sources */, + 239529951E7010030054D75E /* vdbeblob.c in Sources */, + 239528E91E700D460054D75E /* mem0.c in Sources */, + 239528971E700BEB0054D75E /* loadext.c in Sources */, + 239529411E700E910054D75E /* update.c in Sources */, + 2395295D1E700F170054D75E /* ctime.c in Sources */, + 239528BE1E700CB60054D75E /* fts3_expr.c in Sources */, + 239529251E700E280054D75E /* wherecode.c in Sources */, + 239528CA1E700CB60054D75E /* fts3_write.c in Sources */, + 239528D71E700CED0054D75E /* vdbeapi.c in Sources */, + 239529861E700FC60054D75E /* crypto.c in Sources */, + 239529081E700DA70054D75E /* pager.c in Sources */, + 239528F61E700D6C0054D75E /* mutex.c in Sources */, + 239528CF1E700CC30054D75E /* backup.c in Sources */, + 2395291E1E700E080054D75E /* parse.c in Sources */, + 239529631E700F360054D75E /* dbstat.c in Sources */, + 2395292D1E700E450054D75E /* attach.c in Sources */, + 239529511E700EE70054D75E /* sqlite3rbu.c in Sources */, + 239528D91E700CFB0054D75E /* table.c in Sources */, + 239528EF1E700D4A0054D75E /* memjournal.c in Sources */, + 239529311E700E590054D75E /* build.c in Sources */, + 2395293A1E700E780054D75E /* pragma.c in Sources */, + 239529371E700E6E0054D75E /* insert.c in Sources */, + 239529231E700E1E0054D75E /* func.c in Sources */, + 2395290D1E700DB90054D75E /* pcache.c in Sources */, + 239528EA1E700D460054D75E /* mem1.c in Sources */, + 239529731E700F7F0054D75E /* printf.c in Sources */, + 239528991E700BFE0054D75E /* rowset.c in Sources */, + 239529821E700FC60054D75E /* crypto_cc.c in Sources */, + 239528C21E700CB60054D75E /* fts3_porter.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 23121C2D1E6FFFA50012B45E /* PBXTargetDependency */ = { + 239529A01E702D1E0054D75E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 23121C271E6FFEFA0012B45E /* configure */; - targetProxy = 23121C2C1E6FFFA50012B45E /* PBXContainerItemProxy */; + target = 2395299B1E702CF90054D75E /* preprocess */; + targetProxy = 2395299F1E702D1E0054D75E /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -1011,16 +890,29 @@ }; name = Release; }; - 23121C291E6FFEFA0012B45E /* Debug */ = { + 2395299D1E702CF90054D75E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + DEBUGGING_SYMBOLS = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; - 23121C2A1E6FFEFA0012B45E /* Release */ = { + 2395299E1E702CF90054D75E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -1046,11 +938,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 23121C281E6FFEFA0012B45E /* Build configuration list for PBXAggregateTarget "configure" */ = { + 2395299C1E702CF90054D75E /* Build configuration list for PBXLegacyTarget "preprocess" */ = { isa = XCConfigurationList; buildConfigurations = ( - 23121C291E6FFEFA0012B45E /* Debug */, - 23121C2A1E6FFEFA0012B45E /* Release */, + 2395299D1E702CF90054D75E /* Debug */, + 2395299E1E702CF90054D75E /* Release */, ); defaultConfigurationIsVisible = 0; }; From 00da1447fcaf055de031c2d20c353103dff6b972 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 10 Mar 2017 12:07:38 +0800 Subject: [PATCH 29/94] change product name to "sqlcipher" --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index abf9293684..0be81ccbd8 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -153,7 +153,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libsqlcipher-preprocessed.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 23121AE41E6FF9110012B45E /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; @@ -313,7 +313,7 @@ 23121AE51E6FF9110012B45E /* Products */ = { isa = PBXGroup; children = ( - 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */, + 23121AE41E6FF9110012B45E /* libsqlcipher.a */, ); name = Products; sourceTree = ""; @@ -545,7 +545,7 @@ ); name = "sqlcipher-preprocessed"; productName = "sqlcipher-preprocessed"; - productReference = 23121AE41E6FF9110012B45E /* libsqlcipher-preprocessed.a */; + productReference = 23121AE41E6FF9110012B45E /* libsqlcipher.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ @@ -877,7 +877,7 @@ buildSettings = { EXECUTABLE_PREFIX = lib; GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = sqlcipher; }; name = Debug; }; @@ -886,7 +886,7 @@ buildSettings = { EXECUTABLE_PREFIX = lib; GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = sqlcipher; }; name = Release; }; @@ -945,6 +945,7 @@ 2395299E1E702CF90054D75E /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; From 9f5f2faf61c4ce1d86175c3e3001f9c811967137 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 23 Mar 2017 10:32:38 +0800 Subject: [PATCH 30/94] [sqlcipher]add framework --- .../project.pbxproj | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 0be81ccbd8..dfca6e40c7 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -8,6 +8,105 @@ /* Begin PBXBuildFile section */ 23121C081E6FFA890012B45E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; + 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; + 239325D31E836A9C00D677CC /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; + 239325D41E836A9C00D677CC /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; + 239325D51E836A9C00D677CC /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289A1E700C100054D75E /* treeview.c */; }; + 239325D61E836A9C00D677CC /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289C1E700C1B0054D75E /* userauth.c */; }; + 239325D71E836A9C00D677CC /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289E1E700C250054D75E /* vtab.c */; }; + 239325D81E836A9C00D677CC /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A01E700C370054D75E /* btmutex.c */; }; + 239325D91E836A9C00D677CC /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A21E700C4A0054D75E /* btree.c */; }; + 239325DA1E836A9C00D677CC /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A81E700C820054D75E /* fts5.c */; }; + 239325DB1E836A9C00D677CC /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AC1E700CB60054D75E /* fts3_aux.c */; }; + 239325DC1E836A9C00D677CC /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AD1E700CB60054D75E /* fts3_expr.c */; }; + 239325DD1E836A9C00D677CC /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AE1E700CB60054D75E /* fts3_hash.c */; }; + 239325DE1E836A9C00D677CC /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B01E700CB60054D75E /* fts3_icu.c */; }; + 239325DF1E836A9C00D677CC /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B11E700CB60054D75E /* fts3_porter.c */; }; + 239325E01E836A9C00D677CC /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B21E700CB60054D75E /* fts3_snippet.c */; }; + 239325E11E836A9C00D677CC /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */; }; + 239325E21E836A9C00D677CC /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B41E700CB60054D75E /* fts3_tokenizer.c */; }; + 239325E31E836A9C00D677CC /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B61E700CB60054D75E /* fts3_tokenizer1.c */; }; + 239325E41E836A9C00D677CC /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B71E700CB60054D75E /* fts3_unicode.c */; }; + 239325E51E836A9C00D677CC /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B81E700CB60054D75E /* fts3_unicode2.c */; }; + 239325E61E836A9C00D677CC /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B91E700CB60054D75E /* fts3_write.c */; }; + 239325E71E836A9C00D677CC /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528BA1E700CB60054D75E /* fts3.c */; }; + 239325E81E836A9C00D677CC /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528CE1E700CC30054D75E /* backup.c */; }; + 239325E91E836A9C00D677CC /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D01E700CCD0054D75E /* legacy.c */; }; + 239325EA1E836A9C00D677CC /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D21E700CD70054D75E /* main.c */; }; + 239325EB1E836A9C00D677CC /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D41E700CE10054D75E /* notify.c */; }; + 239325EC1E836A9C00D677CC /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D61E700CED0054D75E /* vdbeapi.c */; }; + 239325ED1E836A9C00D677CC /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D81E700CFB0054D75E /* table.c */; }; + 239325EE1E836A9C00D677CC /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DA1E700D0A0054D75E /* wal.c */; }; + 239325EF1E836A9C00D677CC /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DE1E700D170054D75E /* status.c */; }; + 239325F01E836A9C00D677CC /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E01E700D220054D75E /* prepare.c */; }; + 239325F11E836A9C00D677CC /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E21E700D320054D75E /* malloc.c */; }; + 239325F21E836A9C00D677CC /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E41E700D460054D75E /* mem0.c */; }; + 239325F31E836A9C00D677CC /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E51E700D460054D75E /* mem1.c */; }; + 239325F41E836A9C00D677CC /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E61E700D460054D75E /* mem2.c */; }; + 239325F51E836A9C00D677CC /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E71E700D460054D75E /* mem3.c */; }; + 239325F61E836A9C00D677CC /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E81E700D460054D75E /* mem5.c */; }; + 239325F71E836A9C00D677CC /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528EE1E700D4A0054D75E /* memjournal.c */; }; + 239325F81E836A9C00D677CC /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F01E700D570054D75E /* mutex_unix.c */; }; + 239325F91E836A9C00D677CC /* mutex_noop.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F21E700D600054D75E /* mutex_noop.c */; }; + 239325FA1E836A9C00D677CC /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F41E700D6C0054D75E /* mutex.c */; }; + 239325FB1E836A9C00D677CC /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FA1E700D790054D75E /* os_unix.c */; }; + 239325FC1E836A9C00D677CC /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FE1E700D880054D75E /* os.c */; }; + 239325FD1E836A9C00D677CC /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529021E700D920054D75E /* threads.c */; }; + 239325FE1E836A9C00D677CC /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529041E700D9D0054D75E /* bitvec.c */; }; + 239325FF1E836A9C00D677CC /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529061E700DA70054D75E /* pager.c */; }; + 239326001E836A9C00D677CC /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290A1E700DB90054D75E /* pcache.c */; }; + 239326011E836A9C00D677CC /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290C1E700DB90054D75E /* pcache1.c */; }; + 239326021E836A9C00D677CC /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529101E700DD10054D75E /* rtree.c */; }; + 239326031E836A9C00D677CC /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529161E700DDF0054D75E /* complete.c */; }; + 239326041E836A9C00D677CC /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529181E700DED0054D75E /* tokenize.c */; }; + 239326051E836A9C00D677CC /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291A1E700DFD0054D75E /* resolve.c */; }; + 239326061E836A9C00D677CC /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291C1E700E080054D75E /* parse.c */; }; + 239326071E836A9C00D677CC /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529201E700E170054D75E /* analyze.c */; }; + 239326081E836A9C00D677CC /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529221E700E1E0054D75E /* func.c */; }; + 239326091E836A9C00D677CC /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529241E700E280054D75E /* wherecode.c */; }; + 2393260A1E836A9C00D677CC /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529261E700E2F0054D75E /* whereexpr.c */; }; + 2393260B1E836A9C00D677CC /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292A1E700E3C0054D75E /* alter.c */; }; + 2393260C1E836A9C00D677CC /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292C1E700E450054D75E /* attach.c */; }; + 2393260D1E836A9C00D677CC /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292E1E700E4C0054D75E /* auth.c */; }; + 2393260E1E836A9C00D677CC /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529301E700E590054D75E /* build.c */; }; + 2393260F1E836A9C00D677CC /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529321E700E5F0054D75E /* delete.c */; }; + 239326101E836A9C00D677CC /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529341E700E660054D75E /* expr.c */; }; + 239326111E836A9C00D677CC /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529361E700E6D0054D75E /* insert.c */; }; + 239326121E836A9C00D677CC /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529381E700E780054D75E /* pragma.c */; }; + 239326131E836A9C00D677CC /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293C1E700E810054D75E /* select.c */; }; + 239326141E836A9C00D677CC /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293E1E700E8A0054D75E /* trigger.c */; }; + 239326151E836A9C00D677CC /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529401E700E910054D75E /* update.c */; }; + 239326161E836A9C00D677CC /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529421E700E9C0054D75E /* vacuum.c */; }; + 239326171E836A9C00D677CC /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529441E700EA40054D75E /* walker.c */; }; + 239326181E836A9C00D677CC /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529461E700EAF0054D75E /* where.c */; }; + 239326191E836A9C00D677CC /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529481E700EBC0054D75E /* opcodes.c */; }; + 2393261A1E836A9C00D677CC /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395294D1E700EE70054D75E /* sqlite3rbu.c */; }; + 2393261B1E836A9C00D677CC /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529541E700EF00054D75E /* json1.c */; }; + 2393261C1E836A9C00D677CC /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529561E700EF90054D75E /* icu.c */; }; + 2393261D1E836A9C00D677CC /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295A1E700F0F0054D75E /* global.c */; }; + 2393261E1E836A9C00D677CC /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295C1E700F170054D75E /* ctime.c */; }; + 2393261F1E836A9C00D677CC /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529601E700F2C0054D75E /* date.c */; }; + 239326201E836A9C00D677CC /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529621E700F360054D75E /* dbstat.c */; }; + 239326211E836A9C00D677CC /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529641E700F410054D75E /* fault.c */; }; + 239326221E836A9C00D677CC /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529661E700F490054D75E /* fkey.c */; }; + 239326231E836A9C00D677CC /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395296E1E700F760054D75E /* hash.c */; }; + 239326241E836A9C00D677CC /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529721E700F7F0054D75E /* printf.c */; }; + 239326251E836A9C00D677CC /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529741E700F870054D75E /* random.c */; }; + 239326261E836A9C00D677CC /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529761E700F940054D75E /* utf.c */; }; + 239326271E836A9C00D677CC /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529771E700F940054D75E /* util.c */; }; + 239326281E836A9C00D677CC /* crypto_custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297A1E700FA60054D75E /* crypto_custom.c */; }; + 239326291E836A9C00D677CC /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297C1E700FC60054D75E /* crypto_cc.c */; }; + 2393262A1E836A9C00D677CC /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297D1E700FC60054D75E /* crypto_impl.c */; }; + 2393262B1E836A9C00D677CC /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */; }; + 2393262C1E836A9C00D677CC /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297F1E700FC60054D75E /* crypto_openssl.c */; }; + 2393262D1E836A9C00D677CC /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529801E700FC60054D75E /* crypto.c */; }; + 2393262E1E836A9C00D677CC /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298A1E7010030054D75E /* vdbe.c */; }; + 2393262F1E836A9C00D677CC /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298C1E7010030054D75E /* vdbeaux.c */; }; + 239326301E836A9C00D677CC /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298D1E7010030054D75E /* vdbeblob.c */; }; + 239326311E836A9C00D677CC /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298F1E7010030054D75E /* vdbemem.c */; }; + 239326321E836A9C00D677CC /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529901E7010030054D75E /* vdbesort.c */; }; + 239326331E836A9C00D677CC /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529911E7010030054D75E /* vdbetrace.c */; }; + 239326341E836AAA00D677CC /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294C1E700EE70054D75E /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; 239528931E700BBC0054D75E /* keywordhash.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528921E700BBC0054D75E /* keywordhash.h */; }; 239528951E700BCB0054D75E /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; 239528971E700BEB0054D75E /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; @@ -143,6 +242,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 239325D01E836A9000D677CC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2395299B1E702CF90054D75E; + remoteInfo = preprocess; + }; 2395299F1E702D1E0054D75E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; @@ -155,6 +261,8 @@ /* Begin PBXFileReference section */ 23121AE41E6FF9110012B45E /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 239325CB1E836A7700D677CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; 239528961E700BEB0054D75E /* loadext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loadext.c; path = src/loadext.c; sourceTree = SOURCE_ROOT; }; @@ -298,6 +406,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 239325C41E836A7700D677CC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -305,6 +420,7 @@ isa = PBXGroup; children = ( 23121B7C1E6FF93D0012B45E /* src */, + 239325C91E836A7700D677CC /* sqlcipher */, 23121C061E6FFA890012B45E /* Frameworks */, 23121AE51E6FF9110012B45E /* Products */, ); @@ -314,6 +430,7 @@ isa = PBXGroup; children = ( 23121AE41E6FF9110012B45E /* libsqlcipher.a */, + 239325C81E836A7700D677CC /* sqlcipher.framework */, ); name = Products; sourceTree = ""; @@ -466,6 +583,14 @@ name = Frameworks; sourceTree = ""; }; + 239325C91E836A7700D677CC /* sqlcipher */ = { + isa = PBXGroup; + children = ( + 239325CB1E836A7700D677CC /* Info.plist */, + ); + path = sqlcipher; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -510,6 +635,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 239325C51E836A7700D677CC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 239326341E836AAA00D677CC /* sqlite3.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXLegacyTarget section */ @@ -548,6 +681,25 @@ productReference = 23121AE41E6FF9110012B45E /* libsqlcipher.a */; productType = "com.apple.product-type.library.static"; }; + 239325C71E836A7700D677CC /* sqlcipher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; + buildPhases = ( + 239325C31E836A7700D677CC /* Sources */, + 239325C41E836A7700D677CC /* Frameworks */, + 239325C51E836A7700D677CC /* Headers */, + 239325C61E836A7700D677CC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 239325D11E836A9000D677CC /* PBXTargetDependency */, + ); + name = sqlcipher; + productName = sqlcipher; + productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -561,6 +713,10 @@ CreatedOnToolsVersion = 8.2; ProvisioningStyle = Automatic; }; + 239325C71E836A7700D677CC = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; 2395299B1E702CF90054D75E = { CreatedOnToolsVersion = 8.2; ProvisioningStyle = Automatic; @@ -580,11 +736,22 @@ projectRoot = ""; targets = ( 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */, + 239325C71E836A7700D677CC /* sqlcipher */, 2395299B1E702CF90054D75E /* preprocess */, ); }; /* End PBXProject section */ +/* Begin PBXResourcesBuildPhase section */ + 239325C61E836A7700D677CC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 23121AE01E6FF9110012B45E /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -691,9 +858,119 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 239325C31E836A7700D677CC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 239325D21E836A9C00D677CC /* callback.c in Sources */, + 239325D31E836A9C00D677CC /* loadext.c in Sources */, + 239325D41E836A9C00D677CC /* rowset.c in Sources */, + 239325D51E836A9C00D677CC /* treeview.c in Sources */, + 239325D61E836A9C00D677CC /* userauth.c in Sources */, + 239325D71E836A9C00D677CC /* vtab.c in Sources */, + 239325D81E836A9C00D677CC /* btmutex.c in Sources */, + 239325D91E836A9C00D677CC /* btree.c in Sources */, + 239325DA1E836A9C00D677CC /* fts5.c in Sources */, + 239325DB1E836A9C00D677CC /* fts3_aux.c in Sources */, + 239325DC1E836A9C00D677CC /* fts3_expr.c in Sources */, + 239325DD1E836A9C00D677CC /* fts3_hash.c in Sources */, + 239325DE1E836A9C00D677CC /* fts3_icu.c in Sources */, + 239325DF1E836A9C00D677CC /* fts3_porter.c in Sources */, + 239325E01E836A9C00D677CC /* fts3_snippet.c in Sources */, + 239325E11E836A9C00D677CC /* fts3_tokenize_vtab.c in Sources */, + 239325E21E836A9C00D677CC /* fts3_tokenizer.c in Sources */, + 239325E31E836A9C00D677CC /* fts3_tokenizer1.c in Sources */, + 239325E41E836A9C00D677CC /* fts3_unicode.c in Sources */, + 239325E51E836A9C00D677CC /* fts3_unicode2.c in Sources */, + 239325E61E836A9C00D677CC /* fts3_write.c in Sources */, + 239325E71E836A9C00D677CC /* fts3.c in Sources */, + 239325E81E836A9C00D677CC /* backup.c in Sources */, + 239325E91E836A9C00D677CC /* legacy.c in Sources */, + 239325EA1E836A9C00D677CC /* main.c in Sources */, + 239325EB1E836A9C00D677CC /* notify.c in Sources */, + 239325EC1E836A9C00D677CC /* vdbeapi.c in Sources */, + 239325ED1E836A9C00D677CC /* table.c in Sources */, + 239325EE1E836A9C00D677CC /* wal.c in Sources */, + 239325EF1E836A9C00D677CC /* status.c in Sources */, + 239325F01E836A9C00D677CC /* prepare.c in Sources */, + 239325F11E836A9C00D677CC /* malloc.c in Sources */, + 239325F21E836A9C00D677CC /* mem0.c in Sources */, + 239325F31E836A9C00D677CC /* mem1.c in Sources */, + 239325F41E836A9C00D677CC /* mem2.c in Sources */, + 239325F51E836A9C00D677CC /* mem3.c in Sources */, + 239325F61E836A9C00D677CC /* mem5.c in Sources */, + 239325F71E836A9C00D677CC /* memjournal.c in Sources */, + 239325F81E836A9C00D677CC /* mutex_unix.c in Sources */, + 239325F91E836A9C00D677CC /* mutex_noop.c in Sources */, + 239325FA1E836A9C00D677CC /* mutex.c in Sources */, + 239325FB1E836A9C00D677CC /* os_unix.c in Sources */, + 239325FC1E836A9C00D677CC /* os.c in Sources */, + 239325FD1E836A9C00D677CC /* threads.c in Sources */, + 239325FE1E836A9C00D677CC /* bitvec.c in Sources */, + 239325FF1E836A9C00D677CC /* pager.c in Sources */, + 239326001E836A9C00D677CC /* pcache.c in Sources */, + 239326011E836A9C00D677CC /* pcache1.c in Sources */, + 239326021E836A9C00D677CC /* rtree.c in Sources */, + 239326031E836A9C00D677CC /* complete.c in Sources */, + 239326041E836A9C00D677CC /* tokenize.c in Sources */, + 239326051E836A9C00D677CC /* resolve.c in Sources */, + 239326061E836A9C00D677CC /* parse.c in Sources */, + 239326071E836A9C00D677CC /* analyze.c in Sources */, + 239326081E836A9C00D677CC /* func.c in Sources */, + 239326091E836A9C00D677CC /* wherecode.c in Sources */, + 2393260A1E836A9C00D677CC /* whereexpr.c in Sources */, + 2393260B1E836A9C00D677CC /* alter.c in Sources */, + 2393260C1E836A9C00D677CC /* attach.c in Sources */, + 2393260D1E836A9C00D677CC /* auth.c in Sources */, + 2393260E1E836A9C00D677CC /* build.c in Sources */, + 2393260F1E836A9C00D677CC /* delete.c in Sources */, + 239326101E836A9C00D677CC /* expr.c in Sources */, + 239326111E836A9C00D677CC /* insert.c in Sources */, + 239326121E836A9C00D677CC /* pragma.c in Sources */, + 239326131E836A9C00D677CC /* select.c in Sources */, + 239326141E836A9C00D677CC /* trigger.c in Sources */, + 239326151E836A9C00D677CC /* update.c in Sources */, + 239326161E836A9C00D677CC /* vacuum.c in Sources */, + 239326171E836A9C00D677CC /* walker.c in Sources */, + 239326181E836A9C00D677CC /* where.c in Sources */, + 239326191E836A9C00D677CC /* opcodes.c in Sources */, + 2393261A1E836A9C00D677CC /* sqlite3rbu.c in Sources */, + 2393261B1E836A9C00D677CC /* json1.c in Sources */, + 2393261C1E836A9C00D677CC /* icu.c in Sources */, + 2393261D1E836A9C00D677CC /* global.c in Sources */, + 2393261E1E836A9C00D677CC /* ctime.c in Sources */, + 2393261F1E836A9C00D677CC /* date.c in Sources */, + 239326201E836A9C00D677CC /* dbstat.c in Sources */, + 239326211E836A9C00D677CC /* fault.c in Sources */, + 239326221E836A9C00D677CC /* fkey.c in Sources */, + 239326231E836A9C00D677CC /* hash.c in Sources */, + 239326241E836A9C00D677CC /* printf.c in Sources */, + 239326251E836A9C00D677CC /* random.c in Sources */, + 239326261E836A9C00D677CC /* utf.c in Sources */, + 239326271E836A9C00D677CC /* util.c in Sources */, + 239326281E836A9C00D677CC /* crypto_custom.c in Sources */, + 239326291E836A9C00D677CC /* crypto_cc.c in Sources */, + 2393262A1E836A9C00D677CC /* crypto_impl.c in Sources */, + 2393262B1E836A9C00D677CC /* crypto_libtomcrypt.c in Sources */, + 2393262C1E836A9C00D677CC /* crypto_openssl.c in Sources */, + 2393262D1E836A9C00D677CC /* crypto.c in Sources */, + 2393262E1E836A9C00D677CC /* vdbe.c in Sources */, + 2393262F1E836A9C00D677CC /* vdbeaux.c in Sources */, + 239326301E836A9C00D677CC /* vdbeblob.c in Sources */, + 239326311E836A9C00D677CC /* vdbemem.c in Sources */, + 239326321E836A9C00D677CC /* vdbesort.c in Sources */, + 239326331E836A9C00D677CC /* vdbetrace.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 239325D11E836A9000D677CC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2395299B1E702CF90054D75E /* preprocess */; + targetProxy = 239325D01E836A9000D677CC /* PBXContainerItemProxy */; + }; 239529A01E702D1E0054D75E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2395299B1E702CF90054D75E /* preprocess */; @@ -890,6 +1167,56 @@ }; name = Release; }; + 239325CD1E836A7700D677CC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = sqlcipher/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 239325CE1E836A7700D677CC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = sqlcipher/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 2395299D1E702CF90054D75E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -938,6 +1265,14 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 239325CD1E836A7700D677CC /* Debug */, + 239325CE1E836A7700D677CC /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 2395299C1E702CF90054D75E /* Build configuration list for PBXLegacyTarget "preprocess" */ = { isa = XCConfigurationList; buildConfigurations = ( From e3f53fae41545afb8bfe3e60752c9313b6d51834 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 23 Mar 2017 10:52:26 +0800 Subject: [PATCH 31/94] [sqlcipher]rename target --- .../project.pbxproj | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index dfca6e40c7..fad2ff660c 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -663,9 +663,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */ = { + 23121AE31E6FF9110012B45E /* sqlcipher lib */ = { isa = PBXNativeTarget; - buildConfigurationList = 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher-preprocessed" */; + buildConfigurationList = 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher lib" */; buildPhases = ( 23121AE01E6FF9110012B45E /* Sources */, 23121AE11E6FF9110012B45E /* Frameworks */, @@ -676,14 +676,14 @@ dependencies = ( 239529A01E702D1E0054D75E /* PBXTargetDependency */, ); - name = "sqlcipher-preprocessed"; + name = "sqlcipher lib"; productName = "sqlcipher-preprocessed"; productReference = 23121AE41E6FF9110012B45E /* libsqlcipher.a */; productType = "com.apple.product-type.library.static"; }; - 239325C71E836A7700D677CC /* sqlcipher */ = { + 239325C71E836A7700D677CC /* sqlcipher framework */ = { isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */; buildPhases = ( 239325C31E836A7700D677CC /* Sources */, 239325C41E836A7700D677CC /* Frameworks */, @@ -695,7 +695,7 @@ dependencies = ( 239325D11E836A9000D677CC /* PBXTargetDependency */, ); - name = sqlcipher; + name = "sqlcipher framework"; productName = sqlcipher; productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; @@ -735,8 +735,8 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 23121AE31E6FF9110012B45E /* sqlcipher-preprocessed */, - 239325C71E836A7700D677CC /* sqlcipher */, + 23121AE31E6FF9110012B45E /* sqlcipher lib */, + 239325C71E836A7700D677CC /* sqlcipher framework */, 2395299B1E702CF90054D75E /* preprocess */, ); }; @@ -1187,7 +1187,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -1210,7 +1210,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -1256,7 +1256,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher-preprocessed" */ = { + 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher lib" */ = { isa = XCConfigurationList; buildConfigurations = ( 23121AE91E6FF9110012B45E /* Debug */, @@ -1265,13 +1265,14 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, 239325CE1E836A7700D677CC /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 2395299C1E702CF90054D75E /* Build configuration list for PBXLegacyTarget "preprocess" */ = { isa = XCConfigurationList; From dc4bf272b06244ba71aeed418f8ce8d9569479bc Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 23 Mar 2017 11:09:36 +0800 Subject: [PATCH 32/94] [sqlcipher]add info plist --- sqlcipher framework/Info.plist | 26 +++++++++++++++++ sqlcipher framework/sqcliphertest.h | 19 +++++++++++++ .../project.pbxproj | 28 +++++++++++-------- 3 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 sqlcipher framework/Info.plist create mode 100644 sqlcipher framework/sqcliphertest.h diff --git a/sqlcipher framework/Info.plist b/sqlcipher framework/Info.plist new file mode 100644 index 0000000000..b38c994e86 --- /dev/null +++ b/sqlcipher framework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2017年 sanhuazhang. All rights reserved. + NSPrincipalClass + + + diff --git a/sqlcipher framework/sqcliphertest.h b/sqlcipher framework/sqcliphertest.h new file mode 100644 index 0000000000..79b4ba2374 --- /dev/null +++ b/sqlcipher framework/sqcliphertest.h @@ -0,0 +1,19 @@ +// +// sqcliphertest.h +// sqcliphertest +// +// Created by sanhuazhang on 2017/3/23. +// Copyright © 2017年 sanhuazhang. All rights reserved. +// + +#import + +//! Project version number for sqcliphertest. +FOUNDATION_EXPORT double sqcliphertestVersionNumber; + +//! Project version string for sqcliphertest. +FOUNDATION_EXPORT const unsigned char sqcliphertestVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index fad2ff660c..67868efbd6 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2311206E1E8373A6008A94C3 /* sqcliphertest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2311206D1E8373A6008A94C3 /* sqcliphertest.h */; }; 23121C081E6FFA890012B45E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; 239325D31E836A9C00D677CC /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; @@ -259,10 +260,11 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 2311206C1E8373A6008A94C3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2311206D1E8373A6008A94C3 /* sqcliphertest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqcliphertest.h; sourceTree = ""; }; 23121AE41E6FF9110012B45E /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 239325CB1E836A7700D677CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; 239528961E700BEB0054D75E /* loadext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loadext.c; path = src/loadext.c; sourceTree = SOURCE_ROOT; }; @@ -416,11 +418,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2311206B1E8373A6008A94C3 /* sqlcipher framework */ = { + isa = PBXGroup; + children = ( + 2311206C1E8373A6008A94C3 /* Info.plist */, + 2311206D1E8373A6008A94C3 /* sqcliphertest.h */, + ); + path = "sqlcipher framework"; + sourceTree = ""; + }; 23121ADB1E6FF9110012B45E = { isa = PBXGroup; children = ( + 2311206B1E8373A6008A94C3 /* sqlcipher framework */, 23121B7C1E6FF93D0012B45E /* src */, - 239325C91E836A7700D677CC /* sqlcipher */, 23121C061E6FFA890012B45E /* Frameworks */, 23121AE51E6FF9110012B45E /* Products */, ); @@ -583,14 +594,6 @@ name = Frameworks; sourceTree = ""; }; - 239325C91E836A7700D677CC /* sqlcipher */ = { - isa = PBXGroup; - children = ( - 239325CB1E836A7700D677CC /* Info.plist */, - ); - path = sqlcipher; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -598,6 +601,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 2311206E1E8373A6008A94C3 /* sqcliphertest.h in Headers */, 239528FC1E700D790054D75E /* os_setup.h in Headers */, 239528C01E700CB60054D75E /* fts3_hash.h in Headers */, 2395296D1E700F6C0054D75E /* sqlite3ext.h in Headers */, @@ -1182,7 +1186,7 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = sqlcipher/Info.plist; + INFOPLIST_FILE = "sqlcipher framework/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; @@ -1205,7 +1209,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = sqlcipher/Info.plist; + INFOPLIST_FILE = "sqlcipher framework/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; From ff2a20caa142179e77409aae007a79e958846410 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 23 Mar 2017 16:15:09 +0800 Subject: [PATCH 33/94] [sqlcipher]remove lib --- .../project.pbxproj | 353 ------------------ 1 file changed, 353 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 67868efbd6..6123066315 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -7,8 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 2311206E1E8373A6008A94C3 /* sqcliphertest.h in Headers */ = {isa = PBXBuildFile; fileRef = 2311206D1E8373A6008A94C3 /* sqcliphertest.h */; }; - 23121C081E6FFA890012B45E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; 239325D31E836A9C00D677CC /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; 239325D41E836A9C00D677CC /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; @@ -108,138 +106,6 @@ 239326321E836A9C00D677CC /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529901E7010030054D75E /* vdbesort.c */; }; 239326331E836A9C00D677CC /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529911E7010030054D75E /* vdbetrace.c */; }; 239326341E836AAA00D677CC /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294C1E700EE70054D75E /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 239528931E700BBC0054D75E /* keywordhash.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528921E700BBC0054D75E /* keywordhash.h */; }; - 239528951E700BCB0054D75E /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; - 239528971E700BEB0054D75E /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; - 239528991E700BFE0054D75E /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; - 2395289B1E700C100054D75E /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289A1E700C100054D75E /* treeview.c */; }; - 2395289D1E700C1B0054D75E /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289C1E700C1B0054D75E /* userauth.c */; }; - 2395289F1E700C250054D75E /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289E1E700C250054D75E /* vtab.c */; }; - 239528A11E700C370054D75E /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A01E700C370054D75E /* btmutex.c */; }; - 239528A31E700C4A0054D75E /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A21E700C4A0054D75E /* btree.c */; }; - 239528A51E700C550054D75E /* btreeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528A41E700C550054D75E /* btreeInt.h */; }; - 239528A71E700C670054D75E /* btree.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528A61E700C670054D75E /* btree.h */; }; - 239528AA1E700C820054D75E /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A81E700C820054D75E /* fts5.c */; }; - 239528AB1E700C820054D75E /* fts5.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528A91E700C820054D75E /* fts5.h */; }; - 239528BD1E700CB60054D75E /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AC1E700CB60054D75E /* fts3_aux.c */; }; - 239528BE1E700CB60054D75E /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AD1E700CB60054D75E /* fts3_expr.c */; }; - 239528BF1E700CB60054D75E /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AE1E700CB60054D75E /* fts3_hash.c */; }; - 239528C01E700CB60054D75E /* fts3_hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528AF1E700CB60054D75E /* fts3_hash.h */; }; - 239528C11E700CB60054D75E /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B01E700CB60054D75E /* fts3_icu.c */; }; - 239528C21E700CB60054D75E /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B11E700CB60054D75E /* fts3_porter.c */; }; - 239528C31E700CB60054D75E /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B21E700CB60054D75E /* fts3_snippet.c */; }; - 239528C41E700CB60054D75E /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */; }; - 239528C51E700CB60054D75E /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B41E700CB60054D75E /* fts3_tokenizer.c */; }; - 239528C61E700CB60054D75E /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528B51E700CB60054D75E /* fts3_tokenizer.h */; }; - 239528C71E700CB60054D75E /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B61E700CB60054D75E /* fts3_tokenizer1.c */; }; - 239528C81E700CB60054D75E /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B71E700CB60054D75E /* fts3_unicode.c */; }; - 239528C91E700CB60054D75E /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B81E700CB60054D75E /* fts3_unicode2.c */; }; - 239528CA1E700CB60054D75E /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B91E700CB60054D75E /* fts3_write.c */; }; - 239528CB1E700CB60054D75E /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528BA1E700CB60054D75E /* fts3.c */; }; - 239528CC1E700CB60054D75E /* fts3.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528BB1E700CB60054D75E /* fts3.h */; }; - 239528CD1E700CB60054D75E /* fts3Int.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528BC1E700CB60054D75E /* fts3Int.h */; }; - 239528CF1E700CC30054D75E /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528CE1E700CC30054D75E /* backup.c */; }; - 239528D11E700CCD0054D75E /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D01E700CCD0054D75E /* legacy.c */; }; - 239528D31E700CD70054D75E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D21E700CD70054D75E /* main.c */; }; - 239528D51E700CE10054D75E /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D41E700CE10054D75E /* notify.c */; }; - 239528D71E700CED0054D75E /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D61E700CED0054D75E /* vdbeapi.c */; }; - 239528D91E700CFB0054D75E /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D81E700CFB0054D75E /* table.c */; }; - 239528DC1E700D0A0054D75E /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DA1E700D0A0054D75E /* wal.c */; }; - 239528DD1E700D0A0054D75E /* wal.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528DB1E700D0A0054D75E /* wal.h */; }; - 239528DF1E700D170054D75E /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DE1E700D170054D75E /* status.c */; }; - 239528E11E700D220054D75E /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E01E700D220054D75E /* prepare.c */; }; - 239528E31E700D320054D75E /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E21E700D320054D75E /* malloc.c */; }; - 239528E91E700D460054D75E /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E41E700D460054D75E /* mem0.c */; }; - 239528EA1E700D460054D75E /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E51E700D460054D75E /* mem1.c */; }; - 239528EB1E700D460054D75E /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E61E700D460054D75E /* mem2.c */; }; - 239528EC1E700D460054D75E /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E71E700D460054D75E /* mem3.c */; }; - 239528ED1E700D460054D75E /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E81E700D460054D75E /* mem5.c */; }; - 239528EF1E700D4A0054D75E /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528EE1E700D4A0054D75E /* memjournal.c */; }; - 239528F11E700D570054D75E /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F01E700D570054D75E /* mutex_unix.c */; }; - 239528F31E700D600054D75E /* mutex_noop.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F21E700D600054D75E /* mutex_noop.c */; }; - 239528F61E700D6C0054D75E /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F41E700D6C0054D75E /* mutex.c */; }; - 239528F71E700D6C0054D75E /* mutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528F51E700D6C0054D75E /* mutex.h */; }; - 239528FB1E700D790054D75E /* os_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528F81E700D790054D75E /* os_common.h */; }; - 239528FC1E700D790054D75E /* os_setup.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528F91E700D790054D75E /* os_setup.h */; }; - 239528FD1E700D790054D75E /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FA1E700D790054D75E /* os_unix.c */; }; - 239529001E700D880054D75E /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FE1E700D880054D75E /* os.c */; }; - 239529011E700D880054D75E /* os.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528FF1E700D880054D75E /* os.h */; }; - 239529031E700D920054D75E /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529021E700D920054D75E /* threads.c */; }; - 239529051E700D9D0054D75E /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529041E700D9D0054D75E /* bitvec.c */; }; - 239529081E700DA70054D75E /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529061E700DA70054D75E /* pager.c */; }; - 239529091E700DA70054D75E /* pager.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529071E700DA70054D75E /* pager.h */; }; - 2395290D1E700DB90054D75E /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290A1E700DB90054D75E /* pcache.c */; }; - 2395290E1E700DB90054D75E /* pcache.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395290B1E700DB90054D75E /* pcache.h */; }; - 2395290F1E700DB90054D75E /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290C1E700DB90054D75E /* pcache1.c */; }; - 239529131E700DD10054D75E /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529101E700DD10054D75E /* rtree.c */; }; - 239529141E700DD10054D75E /* rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529111E700DD10054D75E /* rtree.h */; }; - 239529151E700DD10054D75E /* sqlite3rtree.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529121E700DD10054D75E /* sqlite3rtree.h */; }; - 239529171E700DDF0054D75E /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529161E700DDF0054D75E /* complete.c */; }; - 239529191E700DED0054D75E /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529181E700DED0054D75E /* tokenize.c */; }; - 2395291B1E700DFD0054D75E /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291A1E700DFD0054D75E /* resolve.c */; }; - 2395291E1E700E080054D75E /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291C1E700E080054D75E /* parse.c */; }; - 2395291F1E700E080054D75E /* parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395291D1E700E080054D75E /* parse.h */; }; - 239529211E700E170054D75E /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529201E700E170054D75E /* analyze.c */; }; - 239529231E700E1E0054D75E /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529221E700E1E0054D75E /* func.c */; }; - 239529251E700E280054D75E /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529241E700E280054D75E /* wherecode.c */; }; - 239529271E700E2F0054D75E /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529261E700E2F0054D75E /* whereexpr.c */; }; - 239529291E700E340054D75E /* whereInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529281E700E340054D75E /* whereInt.h */; }; - 2395292B1E700E3C0054D75E /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292A1E700E3C0054D75E /* alter.c */; }; - 2395292D1E700E450054D75E /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292C1E700E450054D75E /* attach.c */; }; - 2395292F1E700E4C0054D75E /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292E1E700E4C0054D75E /* auth.c */; }; - 239529311E700E590054D75E /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529301E700E590054D75E /* build.c */; }; - 239529331E700E5F0054D75E /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529321E700E5F0054D75E /* delete.c */; }; - 239529351E700E660054D75E /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529341E700E660054D75E /* expr.c */; }; - 239529371E700E6E0054D75E /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529361E700E6D0054D75E /* insert.c */; }; - 2395293A1E700E780054D75E /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529381E700E780054D75E /* pragma.c */; }; - 2395293B1E700E780054D75E /* pragma.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529391E700E780054D75E /* pragma.h */; }; - 2395293D1E700E810054D75E /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293C1E700E810054D75E /* select.c */; }; - 2395293F1E700E8A0054D75E /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293E1E700E8A0054D75E /* trigger.c */; }; - 239529411E700E910054D75E /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529401E700E910054D75E /* update.c */; }; - 239529431E700E9C0054D75E /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529421E700E9C0054D75E /* vacuum.c */; }; - 239529451E700EA40054D75E /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529441E700EA40054D75E /* walker.c */; }; - 239529471E700EAF0054D75E /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529461E700EAF0054D75E /* where.c */; }; - 2395294A1E700EBC0054D75E /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529481E700EBC0054D75E /* opcodes.c */; }; - 2395294B1E700EBC0054D75E /* opcodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529491E700EBC0054D75E /* opcodes.h */; }; - 239529501E700EE70054D75E /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294C1E700EE70054D75E /* sqlite3.h */; }; - 239529511E700EE70054D75E /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395294D1E700EE70054D75E /* sqlite3rbu.c */; }; - 239529521E700EE70054D75E /* sqlite3rbu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294E1E700EE70054D75E /* sqlite3rbu.h */; }; - 239529531E700EE70054D75E /* sqlite3userauth.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294F1E700EE70054D75E /* sqlite3userauth.h */; }; - 239529551E700EF00054D75E /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529541E700EF00054D75E /* json1.c */; }; - 239529571E700EF90054D75E /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529561E700EF90054D75E /* icu.c */; }; - 239529591E700F060054D75E /* sqliteicu.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529581E700F060054D75E /* sqliteicu.h */; }; - 2395295B1E700F0F0054D75E /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295A1E700F0F0054D75E /* global.c */; }; - 2395295D1E700F170054D75E /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295C1E700F170054D75E /* ctime.c */; }; - 2395295F1E700F200054D75E /* hwtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395295E1E700F200054D75E /* hwtime.h */; }; - 239529611E700F2C0054D75E /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529601E700F2C0054D75E /* date.c */; }; - 239529631E700F360054D75E /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529621E700F360054D75E /* dbstat.c */; }; - 239529651E700F410054D75E /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529641E700F410054D75E /* fault.c */; }; - 239529671E700F490054D75E /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529661E700F490054D75E /* fkey.c */; }; - 239529691E700F570054D75E /* sqliteInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529681E700F570054D75E /* sqliteInt.h */; }; - 2395296B1E700F600054D75E /* sqliteLimit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395296A1E700F600054D75E /* sqliteLimit.h */; }; - 2395296D1E700F6C0054D75E /* sqlite3ext.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395296C1E700F6C0054D75E /* sqlite3ext.h */; }; - 239529701E700F760054D75E /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395296E1E700F760054D75E /* hash.c */; }; - 239529711E700F760054D75E /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395296F1E700F760054D75E /* hash.h */; }; - 239529731E700F7F0054D75E /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529721E700F7F0054D75E /* printf.c */; }; - 239529751E700F870054D75E /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529741E700F870054D75E /* random.c */; }; - 239529781E700F940054D75E /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529761E700F940054D75E /* utf.c */; }; - 239529791E700F940054D75E /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529771E700F940054D75E /* util.c */; }; - 2395297B1E700FA60054D75E /* crypto_custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297A1E700FA60054D75E /* crypto_custom.c */; }; - 239529821E700FC60054D75E /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297C1E700FC60054D75E /* crypto_cc.c */; }; - 239529831E700FC60054D75E /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297D1E700FC60054D75E /* crypto_impl.c */; }; - 239529841E700FC60054D75E /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */; }; - 239529851E700FC60054D75E /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297F1E700FC60054D75E /* crypto_openssl.c */; }; - 239529861E700FC60054D75E /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529801E700FC60054D75E /* crypto.c */; }; - 239529871E700FC60054D75E /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529811E700FC60054D75E /* crypto.h */; }; - 239529891E700FD90054D75E /* sqlcipher.h in Headers */ = {isa = PBXBuildFile; fileRef = 239529881E700FD90054D75E /* sqlcipher.h */; }; - 239529921E7010030054D75E /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298A1E7010030054D75E /* vdbe.c */; }; - 239529931E7010030054D75E /* vdbe.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395298B1E7010030054D75E /* vdbe.h */; }; - 239529941E7010030054D75E /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298C1E7010030054D75E /* vdbeaux.c */; }; - 239529951E7010030054D75E /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298D1E7010030054D75E /* vdbeblob.c */; }; - 239529961E7010030054D75E /* vdbeInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395298E1E7010030054D75E /* vdbeInt.h */; }; - 239529971E7010030054D75E /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298F1E7010030054D75E /* vdbemem.c */; }; - 239529981E7010030054D75E /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529901E7010030054D75E /* vdbesort.c */; }; - 239529991E7010030054D75E /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529911E7010030054D75E /* vdbetrace.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -250,19 +116,11 @@ remoteGlobalIDString = 2395299B1E702CF90054D75E; remoteInfo = preprocess; }; - 2395299F1E702D1E0054D75E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 2395299B1E702CF90054D75E; - remoteInfo = preprocess; - }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 2311206C1E8373A6008A94C3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2311206D1E8373A6008A94C3 /* sqcliphertest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqcliphertest.h; sourceTree = ""; }; - 23121AE41E6FF9110012B45E /* libsqlcipher.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsqlcipher.a; sourceTree = BUILT_PRODUCTS_DIR; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; @@ -400,14 +258,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 23121AE11E6FF9110012B45E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 23121C081E6FFA890012B45E /* Security.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 239325C41E836A7700D677CC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -440,7 +290,6 @@ 23121AE51E6FF9110012B45E /* Products */ = { isa = PBXGroup; children = ( - 23121AE41E6FF9110012B45E /* libsqlcipher.a */, 239325C81E836A7700D677CC /* sqlcipher.framework */, ); name = Products; @@ -597,48 +446,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 23121AE21E6FF9110012B45E /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 2311206E1E8373A6008A94C3 /* sqcliphertest.h in Headers */, - 239528FC1E700D790054D75E /* os_setup.h in Headers */, - 239528C01E700CB60054D75E /* fts3_hash.h in Headers */, - 2395296D1E700F6C0054D75E /* sqlite3ext.h in Headers */, - 239528C61E700CB60054D75E /* fts3_tokenizer.h in Headers */, - 239529141E700DD10054D75E /* rtree.h in Headers */, - 239529691E700F570054D75E /* sqliteInt.h in Headers */, - 2395293B1E700E780054D75E /* pragma.h in Headers */, - 239528A71E700C670054D75E /* btree.h in Headers */, - 239528A51E700C550054D75E /* btreeInt.h in Headers */, - 2395296B1E700F600054D75E /* sqliteLimit.h in Headers */, - 239529931E7010030054D75E /* vdbe.h in Headers */, - 239529891E700FD90054D75E /* sqlcipher.h in Headers */, - 239529531E700EE70054D75E /* sqlite3userauth.h in Headers */, - 239529521E700EE70054D75E /* sqlite3rbu.h in Headers */, - 239529711E700F760054D75E /* hash.h in Headers */, - 239528F71E700D6C0054D75E /* mutex.h in Headers */, - 239528AB1E700C820054D75E /* fts5.h in Headers */, - 239528931E700BBC0054D75E /* keywordhash.h in Headers */, - 2395290E1E700DB90054D75E /* pcache.h in Headers */, - 2395294B1E700EBC0054D75E /* opcodes.h in Headers */, - 239529151E700DD10054D75E /* sqlite3rtree.h in Headers */, - 2395295F1E700F200054D75E /* hwtime.h in Headers */, - 239528CD1E700CB60054D75E /* fts3Int.h in Headers */, - 2395291F1E700E080054D75E /* parse.h in Headers */, - 239528DD1E700D0A0054D75E /* wal.h in Headers */, - 239529591E700F060054D75E /* sqliteicu.h in Headers */, - 239529501E700EE70054D75E /* sqlite3.h in Headers */, - 239528CC1E700CB60054D75E /* fts3.h in Headers */, - 239529091E700DA70054D75E /* pager.h in Headers */, - 239529961E7010030054D75E /* vdbeInt.h in Headers */, - 239529011E700D880054D75E /* os.h in Headers */, - 239528FB1E700D790054D75E /* os_common.h in Headers */, - 239529291E700E340054D75E /* whereInt.h in Headers */, - 239529871E700FC60054D75E /* crypto.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 239325C51E836A7700D677CC /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -667,24 +474,6 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 23121AE31E6FF9110012B45E /* sqlcipher lib */ = { - isa = PBXNativeTarget; - buildConfigurationList = 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher lib" */; - buildPhases = ( - 23121AE01E6FF9110012B45E /* Sources */, - 23121AE11E6FF9110012B45E /* Frameworks */, - 23121AE21E6FF9110012B45E /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - 239529A01E702D1E0054D75E /* PBXTargetDependency */, - ); - name = "sqlcipher lib"; - productName = "sqlcipher-preprocessed"; - productReference = 23121AE41E6FF9110012B45E /* libsqlcipher.a */; - productType = "com.apple.product-type.library.static"; - }; 239325C71E836A7700D677CC /* sqlcipher framework */ = { isa = PBXNativeTarget; buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */; @@ -713,10 +502,6 @@ LastUpgradeCheck = 0820; ORGANIZATIONNAME = sanhuazhang; TargetAttributes = { - 23121AE31E6FF9110012B45E = { - CreatedOnToolsVersion = 8.2; - ProvisioningStyle = Automatic; - }; 239325C71E836A7700D677CC = { CreatedOnToolsVersion = 8.2; ProvisioningStyle = Automatic; @@ -739,7 +524,6 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 23121AE31E6FF9110012B45E /* sqlcipher lib */, 239325C71E836A7700D677CC /* sqlcipher framework */, 2395299B1E702CF90054D75E /* preprocess */, ); @@ -757,111 +541,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 23121AE01E6FF9110012B45E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 239528E11E700D220054D75E /* prepare.c in Sources */, - 2395289B1E700C100054D75E /* treeview.c in Sources */, - 239529431E700E9C0054D75E /* vacuum.c in Sources */, - 239528AA1E700C820054D75E /* fts5.c in Sources */, - 239528A31E700C4A0054D75E /* btree.c in Sources */, - 239528C91E700CB60054D75E /* fts3_unicode2.c in Sources */, - 239529701E700F760054D75E /* hash.c in Sources */, - 239529841E700FC60054D75E /* crypto_libtomcrypt.c in Sources */, - 239529651E700F410054D75E /* fault.c in Sources */, - 239528ED1E700D460054D75E /* mem5.c in Sources */, - 239529031E700D920054D75E /* threads.c in Sources */, - 239529171E700DDF0054D75E /* complete.c in Sources */, - 239529471E700EAF0054D75E /* where.c in Sources */, - 239529611E700F2C0054D75E /* date.c in Sources */, - 2395293F1E700E8A0054D75E /* trigger.c in Sources */, - 239528F11E700D570054D75E /* mutex_unix.c in Sources */, - 239528C71E700CB60054D75E /* fts3_tokenizer1.c in Sources */, - 239528CB1E700CB60054D75E /* fts3.c in Sources */, - 239528D51E700CE10054D75E /* notify.c in Sources */, - 2395293D1E700E810054D75E /* select.c in Sources */, - 239529981E7010030054D75E /* vdbesort.c in Sources */, - 2395295B1E700F0F0054D75E /* global.c in Sources */, - 239529751E700F870054D75E /* random.c in Sources */, - 239529451E700EA40054D75E /* walker.c in Sources */, - 239529781E700F940054D75E /* utf.c in Sources */, - 239528DF1E700D170054D75E /* status.c in Sources */, - 2395297B1E700FA60054D75E /* crypto_custom.c in Sources */, - 239528E31E700D320054D75E /* malloc.c in Sources */, - 239528F31E700D600054D75E /* mutex_noop.c in Sources */, - 2395294A1E700EBC0054D75E /* opcodes.c in Sources */, - 239529791E700F940054D75E /* util.c in Sources */, - 239528C51E700CB60054D75E /* fts3_tokenizer.c in Sources */, - 239528FD1E700D790054D75E /* os_unix.c in Sources */, - 239528A11E700C370054D75E /* btmutex.c in Sources */, - 239529991E7010030054D75E /* vdbetrace.c in Sources */, - 239529851E700FC60054D75E /* crypto_openssl.c in Sources */, - 2395290F1E700DB90054D75E /* pcache1.c in Sources */, - 2395292F1E700E4C0054D75E /* auth.c in Sources */, - 239528951E700BCB0054D75E /* callback.c in Sources */, - 2395289F1E700C250054D75E /* vtab.c in Sources */, - 239528EC1E700D460054D75E /* mem3.c in Sources */, - 239528C11E700CB60054D75E /* fts3_icu.c in Sources */, - 239529921E7010030054D75E /* vdbe.c in Sources */, - 239528D31E700CD70054D75E /* main.c in Sources */, - 2395289D1E700C1B0054D75E /* userauth.c in Sources */, - 239529551E700EF00054D75E /* json1.c in Sources */, - 239529271E700E2F0054D75E /* whereexpr.c in Sources */, - 239529351E700E660054D75E /* expr.c in Sources */, - 239529671E700F490054D75E /* fkey.c in Sources */, - 239528C41E700CB60054D75E /* fts3_tokenize_vtab.c in Sources */, - 239529131E700DD10054D75E /* rtree.c in Sources */, - 2395291B1E700DFD0054D75E /* resolve.c in Sources */, - 239529051E700D9D0054D75E /* bitvec.c in Sources */, - 239529331E700E5F0054D75E /* delete.c in Sources */, - 239529001E700D880054D75E /* os.c in Sources */, - 239528C31E700CB60054D75E /* fts3_snippet.c in Sources */, - 239528DC1E700D0A0054D75E /* wal.c in Sources */, - 239529831E700FC60054D75E /* crypto_impl.c in Sources */, - 239528D11E700CCD0054D75E /* legacy.c in Sources */, - 2395292B1E700E3C0054D75E /* alter.c in Sources */, - 239528BF1E700CB60054D75E /* fts3_hash.c in Sources */, - 239529191E700DED0054D75E /* tokenize.c in Sources */, - 239529941E7010030054D75E /* vdbeaux.c in Sources */, - 239529571E700EF90054D75E /* icu.c in Sources */, - 239528C81E700CB60054D75E /* fts3_unicode.c in Sources */, - 239528BD1E700CB60054D75E /* fts3_aux.c in Sources */, - 239528EB1E700D460054D75E /* mem2.c in Sources */, - 239529971E7010030054D75E /* vdbemem.c in Sources */, - 239529211E700E170054D75E /* analyze.c in Sources */, - 239529951E7010030054D75E /* vdbeblob.c in Sources */, - 239528E91E700D460054D75E /* mem0.c in Sources */, - 239528971E700BEB0054D75E /* loadext.c in Sources */, - 239529411E700E910054D75E /* update.c in Sources */, - 2395295D1E700F170054D75E /* ctime.c in Sources */, - 239528BE1E700CB60054D75E /* fts3_expr.c in Sources */, - 239529251E700E280054D75E /* wherecode.c in Sources */, - 239528CA1E700CB60054D75E /* fts3_write.c in Sources */, - 239528D71E700CED0054D75E /* vdbeapi.c in Sources */, - 239529861E700FC60054D75E /* crypto.c in Sources */, - 239529081E700DA70054D75E /* pager.c in Sources */, - 239528F61E700D6C0054D75E /* mutex.c in Sources */, - 239528CF1E700CC30054D75E /* backup.c in Sources */, - 2395291E1E700E080054D75E /* parse.c in Sources */, - 239529631E700F360054D75E /* dbstat.c in Sources */, - 2395292D1E700E450054D75E /* attach.c in Sources */, - 239529511E700EE70054D75E /* sqlite3rbu.c in Sources */, - 239528D91E700CFB0054D75E /* table.c in Sources */, - 239528EF1E700D4A0054D75E /* memjournal.c in Sources */, - 239529311E700E590054D75E /* build.c in Sources */, - 2395293A1E700E780054D75E /* pragma.c in Sources */, - 239529371E700E6E0054D75E /* insert.c in Sources */, - 239529231E700E1E0054D75E /* func.c in Sources */, - 2395290D1E700DB90054D75E /* pcache.c in Sources */, - 239528EA1E700D460054D75E /* mem1.c in Sources */, - 239529731E700F7F0054D75E /* printf.c in Sources */, - 239528991E700BFE0054D75E /* rowset.c in Sources */, - 239529821E700FC60054D75E /* crypto_cc.c in Sources */, - 239528C21E700CB60054D75E /* fts3_porter.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 239325C31E836A7700D677CC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -975,11 +654,6 @@ target = 2395299B1E702CF90054D75E /* preprocess */; targetProxy = 239325D01E836A9000D677CC /* PBXContainerItemProxy */; }; - 239529A01E702D1E0054D75E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 2395299B1E702CF90054D75E /* preprocess */; - targetProxy = 2395299F1E702D1E0054D75E /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -1153,24 +827,6 @@ }; name = Release; }; - 23121AE91E6FF9110012B45E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - EXECUTABLE_PREFIX = lib; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - PRODUCT_NAME = sqlcipher; - }; - name = Debug; - }; - 23121AEA1E6FF9110012B45E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - EXECUTABLE_PREFIX = lib; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - PRODUCT_NAME = sqlcipher; - }; - name = Release; - }; 239325CD1E836A7700D677CC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1260,15 +916,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 23121AE81E6FF9110012B45E /* Build configuration list for PBXNativeTarget "sqlcipher lib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 23121AE91E6FF9110012B45E /* Debug */, - 23121AEA1E6FF9110012B45E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */ = { isa = XCConfigurationList; buildConfigurations = ( From 4cdd6bb4750345128d60113184403cc7a07eda44 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 27 Mar 2017 10:28:06 +0800 Subject: [PATCH 34/94] [sqlcipher] code optimize --- Makefile.preprocessed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.preprocessed b/Makefile.preprocessed index 79a2945f08..9d23f5599a 100644 --- a/Makefile.preprocessed +++ b/Makefile.preprocessed @@ -1,7 +1,7 @@ #!/usr/make SRC = \ - opcodes.h \ +opcodes.h \ opcodes.c \ keywordhash.h \ fts5.c \ From d5dadd7cd1d1359d1fc211bea5582a2a858b196b Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 30 Mar 2017 16:54:29 +0800 Subject: [PATCH 35/94] [sqlcipher]add deploy target --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 6123066315..1df510eb78 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -735,7 +735,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -819,7 +820,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; From ac0af0b3b0be76b93712690739582f5aafceb9e8 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 30 Mar 2017 20:49:25 +0800 Subject: [PATCH 36/94] [sqlcipher]do not pass build setting --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 1df510eb78..169fcbd805 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -468,7 +468,7 @@ dependencies = ( ); name = preprocess; - passBuildSettingsInEnvironment = 1; + passBuildSettingsInEnvironment = 0; productName = preprocess; }; /* End PBXLegacyTarget section */ From b7f76ef2353b395ce9a925fea0c71ccc6dbeecc5 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 31 Mar 2017 15:44:12 +0800 Subject: [PATCH 37/94] [sqlcipher]update build setting --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 169fcbd805..636ab28184 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -499,7 +499,7 @@ 23121ADC1E6FF9110012B45E /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0830; ORGANIZATIONNAME = sanhuazhang; TargetAttributes = { 239325C71E836A7700D677CC = { From f0c935fecb39c61b44cb73d90c2d9c3a8bc61dd0 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 12 Apr 2017 20:40:53 +0800 Subject: [PATCH 38/94] [sqlcipher]add HAVE_USLEEP --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 636ab28184..d9d6d3e1bc 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -728,6 +728,7 @@ "USE_PREAD=1", "SQLITE_TEMP_STORE=2", SQLCIPHER_PREPROCESSED, + HAVE_USLEEP, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -813,6 +814,7 @@ SQLCIPHER_CRYPTO_CC, "USE_PREAD=1", SQLCIPHER_PREPROCESSED, + HAVE_USLEEP, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; From b882f2aab48e3d20d9ac0cfab23ace7a09661049 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 25 Apr 2017 10:50:18 +0800 Subject: [PATCH 39/94] add open source statement --- sqlcipher framework/sqcliphertest.h | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sqlcipher framework/sqcliphertest.h b/sqlcipher framework/sqcliphertest.h index 79b4ba2374..97bb95c485 100644 --- a/sqlcipher framework/sqcliphertest.h +++ b/sqlcipher framework/sqcliphertest.h @@ -1,10 +1,22 @@ -// -// sqcliphertest.h -// sqcliphertest -// -// Created by sanhuazhang on 2017/3/23. -// Copyright © 2017年 sanhuazhang. All rights reserved. -// +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #import From 80981c560067e9570849d0f44c93fd2773681756 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 25 Apr 2017 11:00:29 +0800 Subject: [PATCH 40/94] [iOS]remove malloc soft limit --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index d9d6d3e1bc..95c27733b6 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -729,6 +729,7 @@ "SQLITE_TEMP_STORE=2", SQLCIPHER_PREPROCESSED, HAVE_USLEEP, + "SQLITE_MALLOC_SOFT_LIMIT=0", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -815,6 +816,7 @@ "USE_PREAD=1", SQLCIPHER_PREPROCESSED, HAVE_USLEEP, + "SQLITE_MALLOC_SOFT_LIMIT=0", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; From c91986029c0c704320f2455d070a9783c9ce9656 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 25 Apr 2017 16:35:41 +0800 Subject: [PATCH 41/94] [iOS]signal retry feature. use SQLITE_WCDB_SIGNAL_RETRY=1 to open it. Default to 1 for iOS --- .../project.pbxproj | 26 +++ src/mutex_unix.c | 7 + src/mutex_wcdb.c | 103 +++++++++ src/mutex_wcdb.h | 53 +++++ src/os_unix.c | 144 ++++++++++++ src/os_wcdb.c | 208 ++++++++++++++++++ src/os_wcdb.h | 64 ++++++ src/queue.c | 114 ++++++++++ src/queue.h | 48 ++++ 9 files changed, 767 insertions(+) create mode 100644 src/mutex_wcdb.c create mode 100644 src/mutex_wcdb.h create mode 100644 src/os_wcdb.c create mode 100644 src/os_wcdb.h create mode 100644 src/queue.c create mode 100644 src/queue.h diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 95c27733b6..9554f95e1d 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -7,6 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 234E92241EAEF58100C5428D /* os_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E92221EAEF58100C5428D /* os_wcdb.c */; }; + 234E92251EAEF58100C5428D /* os_wcdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E92231EAEF58100C5428D /* os_wcdb.h */; }; + 234E92281EAEFD3B00C5428D /* mutex_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E92261EAEFD3B00C5428D /* mutex_wcdb.c */; }; + 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */; }; + 234E922C1EAEFF8D00C5428D /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E922A1EAEFF8D00C5428D /* queue.c */; }; + 234E922D1EAEFF8D00C5428D /* queue.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E922B1EAEFF8D00C5428D /* queue.h */; }; 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; 239325D31E836A9C00D677CC /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; 239325D41E836A9C00D677CC /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; @@ -122,6 +128,12 @@ 2311206C1E8373A6008A94C3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2311206D1E8373A6008A94C3 /* sqcliphertest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqcliphertest.h; sourceTree = ""; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 234E92221EAEF58100C5428D /* os_wcdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_wcdb.c; path = src/os_wcdb.c; sourceTree = SOURCE_ROOT; }; + 234E92231EAEF58100C5428D /* os_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_wcdb.h; path = src/os_wcdb.h; sourceTree = SOURCE_ROOT; }; + 234E92261EAEFD3B00C5428D /* mutex_wcdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_wcdb.c; path = src/mutex_wcdb.c; sourceTree = SOURCE_ROOT; }; + 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex_wcdb.h; path = src/mutex_wcdb.h; sourceTree = SOURCE_ROOT; }; + 234E922A1EAEFF8D00C5428D /* queue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = queue.c; path = src/queue.c; sourceTree = SOURCE_ROOT; }; + 234E922B1EAEFF8D00C5428D /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = queue.h; path = src/queue.h; sourceTree = SOURCE_ROOT; }; 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; @@ -352,6 +364,12 @@ 239528F81E700D790054D75E /* os_common.h */, 239528F91E700D790054D75E /* os_setup.h */, 239528FA1E700D790054D75E /* os_unix.c */, + 234E922A1EAEFF8D00C5428D /* queue.c */, + 234E922B1EAEFF8D00C5428D /* queue.h */, + 234E92221EAEF58100C5428D /* os_wcdb.c */, + 234E92231EAEF58100C5428D /* os_wcdb.h */, + 234E92261EAEFD3B00C5428D /* mutex_wcdb.c */, + 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */, 239528FE1E700D880054D75E /* os.c */, 239528FF1E700D880054D75E /* os.h */, 239529021E700D920054D75E /* threads.c */, @@ -450,6 +468,9 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 234E92251EAEF58100C5428D /* os_wcdb.h in Headers */, + 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */, + 234E922D1EAEFF8D00C5428D /* queue.h in Headers */, 239326341E836AAA00D677CC /* sqlite3.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -579,6 +600,7 @@ 239325F11E836A9C00D677CC /* malloc.c in Sources */, 239325F21E836A9C00D677CC /* mem0.c in Sources */, 239325F31E836A9C00D677CC /* mem1.c in Sources */, + 234E92241EAEF58100C5428D /* os_wcdb.c in Sources */, 239325F41E836A9C00D677CC /* mem2.c in Sources */, 239325F51E836A9C00D677CC /* mem3.c in Sources */, 239325F61E836A9C00D677CC /* mem5.c in Sources */, @@ -595,6 +617,7 @@ 239326011E836A9C00D677CC /* pcache1.c in Sources */, 239326021E836A9C00D677CC /* rtree.c in Sources */, 239326031E836A9C00D677CC /* complete.c in Sources */, + 234E92281EAEFD3B00C5428D /* mutex_wcdb.c in Sources */, 239326041E836A9C00D677CC /* tokenize.c in Sources */, 239326051E836A9C00D677CC /* resolve.c in Sources */, 239326061E836A9C00D677CC /* parse.c in Sources */, @@ -616,6 +639,7 @@ 239326161E836A9C00D677CC /* vacuum.c in Sources */, 239326171E836A9C00D677CC /* walker.c in Sources */, 239326181E836A9C00D677CC /* where.c in Sources */, + 234E922C1EAEFF8D00C5428D /* queue.c in Sources */, 239326191E836A9C00D677CC /* opcodes.c in Sources */, 2393261A1E836A9C00D677CC /* sqlite3rbu.c in Sources */, 2393261B1E836A9C00D677CC /* json1.c in Sources */, @@ -730,6 +754,7 @@ SQLCIPHER_PREPROCESSED, HAVE_USLEEP, "SQLITE_MALLOC_SOFT_LIMIT=0", + "SQLITE_WCDB_SIGNAL_RETRY=1", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -817,6 +842,7 @@ SQLCIPHER_PREPROCESSED, HAVE_USLEEP, "SQLITE_MALLOC_SOFT_LIMIT=0", + "SQLITE_WCDB_SIGNAL_RETRY=1", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; diff --git a/src/mutex_unix.c b/src/mutex_unix.c index 55d08c8052..7624b5508c 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -384,4 +384,11 @@ sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ return &sMutex; } +#if SQLITE_WCDB_SIGNAL_RETRY +pthread_mutex_t* sqlite3GetPthreadMutex(sqlite3_mutex* p) +{ + return &p->mutex; +} +#endif //SQLITE_WCDB_SIGNAL_RETRY + #endif /* SQLITE_MUTEX_PTHREADS */ diff --git a/src/mutex_wcdb.c b/src/mutex_wcdb.c new file mode 100644 index 0000000000..99241daa84 --- /dev/null +++ b/src/mutex_wcdb.c @@ -0,0 +1,103 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if SQLITE_WCDB_SIGNAL_RETRY + +#include "mutex_wcdb.h" +#include +#include "sqliteInt.h" +#include "sqlite3.h" + +extern pthread_mutex_t* sqlite3GetPthreadMutex(sqlite3_mutex* p); + +struct sqlite3_thread { + pthread_t thread; +}; + +struct sqlite3_condition { + pthread_cond_t cond; +}; + +sqlite3_condition* pthreadCondAlloc() +{ + sqlite3_condition* c = sqlite3MallocZero(sizeof(sqlite3_condition)); + if (c) { + pthread_cond_init(&c->cond, NULL); + } + return c; +} + +void pthreadCondFree(sqlite3_condition* c) +{ + pthread_cond_destroy(&c->cond); + sqlite3_free(c); +} + +int pthreadCondWait(sqlite3_condition* c, sqlite3_mutex* p, int timeout) +{ + if (timeout>0) { + struct timespec relative; + relative.tv_nsec = 0; + relative.tv_sec = timeout; + return pthread_cond_timedwait_relative_np(&c->cond, sqlite3GetPthreadMutex(p), &relative); + } + return pthread_cond_wait(&c->cond, sqlite3GetPthreadMutex(p)); +} + +void pthreadCondSignal(sqlite3_condition* c, sqlite3_thread* t) +{ + if (t&&t->thread) { + pthread_cond_signal_thread_np(&c->cond, t->thread); + }else { + pthread_cond_signal(&c->cond); + } +} + +void pthreadCondBroadcast(sqlite3_condition* c) +{ + pthread_cond_broadcast(&c->cond); +} + +sqlite3_thread* pthreadAlloc() +{ + return (sqlite3_thread*)sqlite3MallocZero(sizeof(sqlite3_thread)); +} + +void pthreadFree(sqlite3_thread* t) +{ + sqlite3_free(t); +} + +void pthreadSelf(sqlite3_thread* t) +{ + t->thread = pthread_self(); +} + +int pthreadIsMain() +{ + return pthread_main_np(); +} + +sqlite3_mutex* unixVFSMutex(void) +{ + return sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +} + +#endif// SQLITE_WCDB_SIGNAL_RETRY diff --git a/src/mutex_wcdb.h b/src/mutex_wcdb.h new file mode 100644 index 0000000000..517297641a --- /dev/null +++ b/src/mutex_wcdb.h @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef mutex_wcdb_h +#define mutex_wcdb_h + +#if SQLITE_WCDB_SIGNAL_RETRY + +#include "sqlite3.h" + +typedef struct sqlite3_thread sqlite3_thread; +typedef struct sqlite3_condition sqlite3_condition; + +sqlite3_condition* pthreadCondAlloc(); + +void pthreadCondFree(sqlite3_condition* c); + +int pthreadCondWait(sqlite3_condition* c, sqlite3_mutex* p, int timeout); + +void pthreadCondSignal(sqlite3_condition* c, sqlite3_thread* t); + +void pthreadCondBroadcast(sqlite3_condition* c); + +sqlite3_thread* pthreadAlloc(); + +void pthreadFree(sqlite3_thread* t); + +void pthreadSelf(sqlite3_thread* t); + +int pthreadIsMain(); + +sqlite3_mutex* unixVFSMutex(void); + +#endif //SQLITE_WCDB_SIGNAL_RETRY + +#endif /* mutex_wcdb_h */ diff --git a/src/os_unix.c b/src/os_unix.c index ccdde04658..94b916f832 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -44,6 +44,13 @@ ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). */ #include "sqliteInt.h" + +#if SQLITE_WCDB_SIGNAL_RETRY +#include "os_wcdb.h" +#include "queue.h" +#include "mutex_wcdb.h" +#endif//SQLITE_WCDB_SIGNAL_RETRY + #if SQLITE_OS_UNIX /* This file is used on unix only */ /* @@ -1098,6 +1105,10 @@ struct unixInodeInfo { sem_t *pSem; /* Named POSIX semaphore */ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ #endif +#if SQLITE_WCDB_SIGNAL_RETRY + Queue qWaitQueue; + sqlite3_condition* pCond; +#endif //SQLITE_WCDB_SIGNAL_RETRY }; /* @@ -1242,6 +1253,16 @@ static void releaseInodeInfo(unixFile *pFile){ assert( pInode->pNext->pPrev==pInode ); pInode->pNext->pPrev = pInode->pPrev; } +#if SQLITE_WCDB_SIGNAL_RETRY + pthreadCondFree(pInode->pCond); + while (!sqlite3QueueEmpty(&pInode->qWaitQueue)) { + WCDBWaitInfo* pInfo = sqlite3QueuePop(&pInode->qWaitQueue); + if (pInfo) { + pthreadFree(pInfo->pThread); + sqlite3_free(pInfo); + } + } +#endif//SQLITE_WCDB_SIGNAL_RETRY sqlite3_free(pInode); } } @@ -1328,6 +1349,13 @@ static int findInodeInfo( pInode->nRef = 1; pInode->pNext = inodeList; pInode->pPrev = 0; +#if SQLITE_WCDB_SIGNAL_RETRY + sqlite3QueueInit(&pInode->qWaitQueue); + pInode->pCond = pthreadCondAlloc(); + if (pInode->pCond==0){ + return SQLITE_NOMEM_BKPT; + } +#endif //SQLITE_WCDB_SIGNAL_RETRY if( inodeList ) inodeList->pPrev = pInode; inodeList = pInode; }else{ @@ -1544,6 +1572,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** database. */ int rc = SQLITE_OK; +#if SQLITE_WCDB_SIGNAL_RETRY + int eBusyWait = SQLITE_WAIT_NONE; +#endif// SQLITE_WCDB_SIGNAL_RETRY unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; struct flock lock; @@ -1586,6 +1617,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; +#if SQLITE_WCDB_SIGNAL_RETRY + eBusyWait = SQLITE_WAIT_SHARED; +#endif //SQLITE_WCDB_SIGNAL_RETRY goto end_lock; } @@ -1667,6 +1701,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; +#if SQLITE_WCDB_SIGNAL_RETRY + eBusyWait = SQLITE_WAIT_EXCLUSIVE; +#endif// SQLITE_WCDB_SIGNAL_RETRY }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file @@ -1720,6 +1757,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){ } end_lock: +#if SQLITE_WCDB_SIGNAL_RETRY + if (eBusyWait!=SQLITE_WAIT_NONE) { + WCDBWait(pInode, pFile, eFileLock, eBusyWait); + } +#endif// SQLITE_WCDB_SIGNAL_RETRY unixLeaveMutex(); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); @@ -1898,6 +1940,10 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ closePendingFds(pFile); } } + +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBTrySignal(pInode); +#endif// SQLITE_WCDB_SIGNAL_RETRY end_unlock: unixLeaveMutex(); @@ -4047,6 +4093,10 @@ struct unixShmNode { u8 sharedMask; /* Mask of shared locks held */ u8 nextShmId; /* Next available unixShm.id value */ #endif +#if SQLITE_WCDB_SIGNAL_RETRY + Queue qWaitQueue; + sqlite3_condition* pCond; +#endif// SQLITE_WCDB_SIGNAL_RETRY }; /* @@ -4184,6 +4234,16 @@ static void unixShmPurge(unixFile *pFd){ int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->mutex); +#if SQLITE_WCDB_SIGNAL_RETRY + pthreadCondFree(p->pCond); + while (!sqlite3QueueEmpty(&p->qWaitQueue)) { + WCDBShmWaitInfo* pInfo = NULL; + if (pInfo) { + pthreadFree(pInfo->pThread); + sqlite3_free(pInfo); + } + } +#endif// SQLITE_WCDB_SIGNAL_RETRY for(i=0; inRegion; i+=nShmPerMap){ if( p->h>=0 ){ osMunmap(p->apRegion[i], p->szRegion); @@ -4301,6 +4361,14 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ goto shm_open_err; } } +#if SQLITE_WCDB_SIGNAL_RETRY + pShmNode->pCond = pthreadCondAlloc(); + if (pShmNode->pCond==0) { + rc = SQLITE_NOMEM_BKPT; + goto shm_open_err; + } + sqlite3QueueInit(&pShmNode->qWaitQueue); +#endif// SQLITE_WCDB_SIGNAL_RETRY if( pInode->bProcessLock==0 ){ int openFlags = O_RDWR | O_CREAT; @@ -4572,6 +4640,9 @@ static int unixShmLock( if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBShmTrySignal(pShmNode); +#endif// SQLITE_WCDB_SIGNAL_RETRY } }else if( flags & SQLITE_SHM_SHARED ){ u16 allShared = 0; /* Union of locks held by connections other than "p" */ @@ -4583,6 +4654,9 @@ static int unixShmLock( for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( (pX->exclMask & mask)!=0 ){ rc = SQLITE_BUSY; +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_SHARED); +#endif// SQLITE_WCDB_SIGNAL_RETRY break; } allShared |= pX->sharedMask; @@ -4608,6 +4682,9 @@ static int unixShmLock( for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ rc = SQLITE_BUSY; +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_EXCLUSIVE); +#endif// SQLITE_WCDB_SIGNAL_RETRY break; } } @@ -7615,5 +7692,72 @@ int sqlite3_os_init(void){ int sqlite3_os_end(void){ return SQLITE_OK; } + +#if SQLITE_WCDB_SIGNAL_RETRY +Queue* WCDBInodeGetWaitQueue(unixInodeInfo* pInode) +{ + return &pInode->qWaitQueue; +} + +sqlite3_condition* WCDBInodeGetCond(unixInodeInfo* pInode) +{ + return pInode->pCond; +} + +int WCDBInodeGetShared(unixInodeInfo* pInode) +{ + return pInode->nShared; +} + +unsigned char WCDBInodeGetFileLock(unixInodeInfo* pInode) +{ + return pInode->eFileLock; +} + +Queue* WCDBShmNodeGetWaitQueue(unixShmNode* pShmNode) +{ + return &pShmNode->qWaitQueue; +} + +sqlite3_condition* WCDBShmNodeGetCond(unixShmNode* pShmNode) +{ + return pShmNode->pCond; +} + +unixShm* WCDBShmNodeGetShm(unixShmNode* pShmNode) +{ + return pShmNode->pFirst; +} + +sqlite3_mutex* WCDBShmNodeGetMutex(unixShmNode* pShmNode) +{ + return pShmNode->mutex; +} + +unixShm* WCDBShmGetNext(unixShm* pShm) +{ + return pShm->pNext; +} + +u16 WCDBShmGetExclMask(unixShm* pShm) +{ + return pShm->exclMask; +} + +u16 WCDBShmGetSharedMask(unixShm* pShm) +{ + return pShm->sharedMask; +} + +unsigned char WCDBFileGetFileLock(unixFile* pFile) +{ + return pFile->eFileLock; +} + +unixShm* WCDBFileGetShm(unixFile* pFile) +{ + return pFile->pShm; +} +#endif// SQLITE_WCDB_SIGNAL_RETRY #endif /* SQLITE_OS_UNIX */ diff --git a/src/os_wcdb.c b/src/os_wcdb.c new file mode 100644 index 0000000000..78368154fb --- /dev/null +++ b/src/os_wcdb.c @@ -0,0 +1,208 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if SQLITE_WCDB_SIGNAL_RETRY + +#include "os_wcdb.h" +#include "queue.h" +#include "sqlite3.h" +#include "sqliteInt.h" +#include "os.h" +#include + +extern Queue* WCDBInodeGetWaitQueue(unixInodeInfo* pInode); +extern sqlite3_condition* WCDBInodeGetCond(unixInodeInfo* pInode); +extern unsigned char WCDBInodeGetShared(unixInodeInfo* pInode); +extern int WCDBInodeGetFileLock(unixInodeInfo* pInode); + +extern Queue* WCDBShmNodeGetWaitQueue(unixShmNode* pShmNode); +extern sqlite3_condition* WCDBShmNodeGetCond(unixShmNode* pShmNode); +extern unixShm* WCDBShmNodeGetShm(unixShmNode* pShmNode); +extern sqlite3_mutex* WCDBShmNodeGetMutex(unixShmNode* pShmNode); + +extern unixShm* WCDBShmGetNext(unixShm* pShm); +extern u16 WCDBShmGetExclMask(unixShm* pShm); +extern u16 WCDBShmGetSharedMask(unixShm* pShm); + +extern unsigned char WCDBFileGetFileLock(unixFile* pFile); +extern unixShm* WCDBFileGetShm(unixFile* pFile); + +void WCDBSignal(unixInodeInfo* pInode) +{ + WCDBWaitInfo* pWaitInfo = (WCDBWaitInfo*)sqlite3QueuePop(WCDBInodeGetWaitQueue(pInode)); + if (pWaitInfo) { + pthreadCondSignal(WCDBInodeGetCond(pInode), pWaitInfo->pThread); + pthreadFree(pWaitInfo->pThread); + sqlite3_free(pWaitInfo); + } +} + +void WCDBTrySignal(unixInodeInfo* pInode) +{ + int rc; + do { + rc = SQLITE_BUSY; + WCDBWaitInfo* pWaitInfo = (WCDBWaitInfo*)sqlite3QueueFront(WCDBInodeGetWaitQueue(pInode)); + if (!pWaitInfo) { + break; + } + int eFlag = pWaitInfo->eFlag; + int eFileLock = pWaitInfo->eFileLock; + unixFile* pFile = pWaitInfo->pFile; + switch (eFlag) { + case SQLITE_WAIT_SHARED: { + rc = SQLITE_OK; + if( (WCDBFileGetFileLock(pFile)!=WCDBInodeGetFileLock(pInode) && + (WCDBInodeGetFileLock(pInode)>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ) { + rc = SQLITE_BUSY; + } + break; + } + case SQLITE_WAIT_EXCLUSIVE: { + rc = SQLITE_OK; + if( eFileLock==EXCLUSIVE_LOCK && WCDBInodeGetShared(pInode)>1 ) { + rc = SQLITE_BUSY; + } + break; + } + default: + break; + } + if (rc==SQLITE_OK) { + WCDBSignal(pInode); + } + } while (rc==SQLITE_OK); +} + +void WCDBWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag) +{ + WCDBWaitInfo* lastInfo = (WCDBWaitInfo*)sqlite3QueueFront(WCDBInodeGetWaitQueue(pInode)); + if (lastInfo) { + if ( (eFileLock==EXCLUSIVE_LOCK&&lastInfo->eFileLock>SHARED_LOCK) + || (lastInfo->eFileLock==EXCLUSIVE_LOCK&&eFileLock>SHARED_LOCK)) { + // force signal to avoid dead load + WCDBSignal(pInode); + return; + } + } + WCDBWaitInfo* info = (WCDBWaitInfo*)sqlite3_malloc(sizeof(WCDBWaitInfo)); + info->eFlag = eFlag; + info->eFileLock = eFileLock; + info->pFile = pFile; + info->pThread = pthreadAlloc(); + pthreadSelf(info->pThread); + if (pthreadIsMain()) { + sqlite3QueuePushFront(WCDBInodeGetWaitQueue(pInode), info); + }else { + sqlite3QueuePush(WCDBInodeGetWaitQueue(pInode), info); + } + if (pthreadCondWait(WCDBInodeGetCond(pInode), unixVFSMutex(), 10)==ETIMEDOUT) { + sqlite3_log(SQLITE_WARNING, "Wait Failed With Timeout"); + } +} + +void WCDBShmSignal(unixShmNode* pShmNode) +{ + WCDBShmWaitInfo* pInfo = (WCDBShmWaitInfo*)sqlite3QueuePop(WCDBShmNodeGetWaitQueue(pShmNode)); + if (pInfo) { + pthreadCondSignal(WCDBShmNodeGetCond(pShmNode), pInfo->pThread); + pthreadFree(pInfo->pThread); + sqlite3_free(pInfo); + } +} + +void WCDBShmTrySignal(unixShmNode* pShmNode){ + int rc; + do { + rc = SQLITE_BUSY; + WCDBShmWaitInfo* pInfo = (WCDBShmWaitInfo*)sqlite3QueueFront(WCDBShmNodeGetWaitQueue(pShmNode)); + if (!pInfo) { + break; + } + int eFlag = pInfo->eFlag; + int oMask = pInfo->oMask; + // The try lock routine below is the same as [unixShmLock] + switch (eFlag) { + case SQLITE_SHM_SHARED: { + unixShm* pX; + rc = SQLITE_OK; + for(pX=WCDBShmNodeGetShm(pShmNode); pX; pX=WCDBShmGetNext(pX)){ + if( (WCDBShmGetExclMask(pX) & oMask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + } + break; + } + case SQLITE_SHM_EXCLUSIVE: { + unixShm* pX; + rc = SQLITE_OK; + for(pX=WCDBShmNodeGetShm(pShmNode); pX; pX=WCDBShmGetNext(pX)){ + if( (WCDBShmGetExclMask(pX) & oMask)!=0 || (WCDBShmGetSharedMask(pX) & oMask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + } + break; + } + default: + break; + } + if (rc==SQLITE_OK) { + WCDBShmSignal(pShmNode); + } + } while (rc==SQLITE_OK); +} + +void WCDBShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag) +{ + WCDBShmWaitInfo* lastInfo = (WCDBShmWaitInfo*)sqlite3QueueFront(WCDBShmNodeGetWaitQueue(pShmNode)); + if (lastInfo) { + if (lastInfo->eFlag==SQLITE_SHM_EXCLUSIVE + &&((WCDBShmGetExclMask(WCDBFileGetShm(pFile))&lastInfo->oMask)!=0 + ||(WCDBShmGetSharedMask(WCDBFileGetShm(pFile))&lastInfo->oMask)!=0)) { + WCDBShmSignal(pShmNode); + return; + } + if (eFlag==SQLITE_SHM_EXCLUSIVE + &&((WCDBShmGetExclMask(WCDBFileGetShm(lastInfo->pFile))&oMask)!=0 + ||(WCDBShmGetSharedMask(WCDBFileGetShm(lastInfo->pFile))&oMask)!=0)) { + WCDBShmSignal(pShmNode); + return; + } + } + + WCDBShmWaitInfo* info = (WCDBShmWaitInfo*)sqlite3_malloc(sizeof(WCDBShmWaitInfo)); + info->eFlag = eFlag; + info->oMask = oMask; + info->pFile = pFile; + info->pThread = pthreadAlloc(); + pthreadSelf(info->pThread); + if (pthreadIsMain()) { + sqlite3QueuePushFront(WCDBShmNodeGetWaitQueue(pShmNode), info); + }else { + sqlite3QueuePush(WCDBShmNodeGetWaitQueue(pShmNode), info); + } + if (pthreadCondWait(WCDBShmNodeGetCond(pShmNode), WCDBShmNodeGetMutex(pShmNode), 10)==ETIMEDOUT) { + sqlite3_log(SQLITE_WARNING, "Wait Failed With Timeout"); + } +} + +#endif// SQLITE_WCDB_SIGNAL_RETRY diff --git a/src/os_wcdb.h b/src/os_wcdb.h new file mode 100644 index 0000000000..74953ccaae --- /dev/null +++ b/src/os_wcdb.h @@ -0,0 +1,64 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef os_wcdb_h +#define os_wcdb_h + +#if SQLITE_WCDB_SIGNAL_RETRY + +#include "mutex_wcdb.h" + +#define SQLITE_WAIT_NONE 0 +#define SQLITE_WAIT_EXCLUSIVE 1 +#define SQLITE_WAIT_SHARED 2 + +typedef struct unixInodeInfo unixInodeInfo; +typedef struct unixFile unixFile; + +typedef struct unixShmNode unixShmNode; +typedef struct unixShm unixShm; + +typedef struct WCDBWaitInfo WCDBWaitInfo; +struct WCDBWaitInfo { + sqlite3_thread* pThread; + int eFileLock; + int eFlag; + unixFile* pFile; +}; + +typedef struct WCDBShmWaitInfo WCDBShmWaitInfo; +struct WCDBShmWaitInfo { + sqlite3_thread* pThread; + int oMask; + int eFlag; + unixFile* pFile; +}; + +void WCDBSignal(unixInodeInfo* pInode); +void WCDBTrySignal(unixInodeInfo* pInode); +void WCDBWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag); + +void WCDBShmSignal(unixShmNode* pShmNode); +void WCDBShmTrySignal(unixShmNode* pShmNode); +void WCDBShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag); + +#endif// SQLITE_WCDB_SIGNAL_RETRY + +#endif /* os_wcdb_h */ diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000000..bac3aa2ced --- /dev/null +++ b/src/queue.c @@ -0,0 +1,114 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if SQLITE_WCDB_SIGNAL_RETRY + +#include "queue.h" +#include +#include "sqliteInt.h" + +struct QueueElem { + QueueElem* pPrev; + QueueElem* pNext; + void* pData; +}; + +void sqlite3QueueInit(Queue* pQueue) +{ + assert(pQueue!=NULL); + pQueue->pHead = NULL; + pQueue->pTail = NULL; +} + +QueueElem* sqlite3QueuePush(Queue* pQueue, void* pData) +{ + assert(pQueue!=NULL); + QueueElem* elem = (QueueElem*)sqlite3_malloc(sizeof(QueueElem)); + elem->pData = pData; + elem->pPrev = pQueue->pTail; + elem->pNext = NULL; + if (pQueue->pTail) { + pQueue->pTail->pNext = elem; + }else { + pQueue->pHead = elem; + } + pQueue->pTail = elem; + return elem; +} + +QueueElem* sqlite3QueuePushFront(Queue* pQueue, void* pData) +{ + assert(pQueue!=NULL); + QueueElem* elem = (QueueElem*)sqlite3_malloc(sizeof(QueueElem)); + elem->pData = pData; + elem->pPrev = NULL; + elem->pNext = pQueue->pHead; + if (pQueue->pHead) { + pQueue->pHead->pPrev = elem; + }else { + pQueue->pTail = elem; + } + pQueue->pHead = elem; + return elem; +} + +void* sqlite3QueuePop(Queue* pQueue) +{ + assert(pQueue!=NULL); + void* pData = NULL; + QueueElem* elem = NULL; + if (pQueue->pHead) { + elem = pQueue->pHead; + if (pQueue->pHead==pQueue->pTail) { + pQueue->pHead = NULL; + pQueue->pTail = NULL; + }else { + pQueue->pHead = pQueue->pHead->pNext; + pQueue->pHead->pPrev = NULL; + } + } + if (elem) { + pData = elem->pData; + sqlite3_free(elem); + } + return pData; +} + +void* sqlite3QueueFront(Queue* pQueue) +{ + assert(pQueue!=NULL); + if (pQueue->pHead) { + return pQueue->pHead->pData; + } + return NULL; +} + +int sqlite3QueueEmpty(Queue* pQueue) +{ + return pQueue->pHead!=NULL?0:1; +} + +void sqlite3QueueFree(Queue* pQueue) +{ + assert(pQueue!=NULL); + sqlite3_free(pQueue); +} + +#endif// SQLITE_WCDB_SIGNAL_RETRY diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 0000000000..64e08128b4 --- /dev/null +++ b/src/queue.h @@ -0,0 +1,48 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SQLITE_QUEUE_H_ +#define _SQLITE_QUEUE_H_ + +#if SQLITE_WCDB_SIGNAL_RETRY + +typedef struct Queue Queue; +typedef struct QueueElem QueueElem; + +struct Queue { + QueueElem* pHead; + QueueElem* pTail; +}; + +void sqlite3QueueInit(Queue*); + +QueueElem* sqlite3QueuePush(Queue*, void*); + +QueueElem* sqlite3QueuePushFront(Queue*, void*); + +void* sqlite3QueuePop(Queue*); + +void* sqlite3QueueFront(Queue*); + +int sqlite3QueueEmpty(Queue*); + +#endif// SQLITE_WCDB_SIGNAL_RETRY + +#endif /* _SQLITE_QUEUE_H_ */ From 42defb148d6b6903e32477f331e05560f794f2c1 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 25 Apr 2017 17:03:23 +0800 Subject: [PATCH 42/94] [iOS]setup default busy handler for SQLITE_WCDB_SIGNAL_RETRY --- src/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.c b/src/main.c index 392a0042e9..0d1afce126 100644 --- a/src/main.c +++ b/src/main.c @@ -1437,6 +1437,9 @@ static int sqliteDefaultBusyCallback( void *ptr, /* Database connection */ int count /* Number of times table has been busy */ ){ +#if SQLITE_WCDB_SIGNAL_RETRY + return 1; +#endif //SQLITE_WCDB_SIGNAL_RETRY #if SQLITE_OS_WIN || HAVE_USLEEP static const u8 delays[] = { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; From 19bfa38a2d47ffcf69b1757815a028e5b6b61df3 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 26 Apr 2017 11:08:42 +0800 Subject: [PATCH 43/94] [iOS]default retry for SQLITE_WCDB_SIGNAL_RETRY --- src/main.c | 3 --- src/os_unix.c | 17 +++++++++++++++++ src/os_wcdb.c | 2 -- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index 0d1afce126..392a0042e9 100644 --- a/src/main.c +++ b/src/main.c @@ -1437,9 +1437,6 @@ static int sqliteDefaultBusyCallback( void *ptr, /* Database connection */ int count /* Number of times table has been busy */ ){ -#if SQLITE_WCDB_SIGNAL_RETRY - return 1; -#endif //SQLITE_WCDB_SIGNAL_RETRY #if SQLITE_OS_WIN || HAVE_USLEEP static const u8 delays[] = { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; diff --git a/src/os_unix.c b/src/os_unix.c index 94b916f832..c27447245c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1574,6 +1574,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ int rc = SQLITE_OK; #if SQLITE_WCDB_SIGNAL_RETRY int eBusyWait = SQLITE_WAIT_NONE; + int retry = 0; #endif// SQLITE_WCDB_SIGNAL_RETRY unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; @@ -1619,6 +1620,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY eBusyWait = SQLITE_WAIT_SHARED; + retry = 1; #endif //SQLITE_WCDB_SIGNAL_RETRY goto end_lock; } @@ -1703,6 +1705,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY eBusyWait = SQLITE_WAIT_EXCLUSIVE; + retry = 1; #endif// SQLITE_WCDB_SIGNAL_RETRY }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is @@ -1765,7 +1768,12 @@ static int unixLock(sqlite3_file *id, int eFileLock){ unixLeaveMutex(); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); +#if SQLITE_WCDB_SIGNAL_RETRY + //tail call can avoid call stack over flow + return retry?unixLock(id, eFileLock):rc; +#else//SQLITE_WCDB_SIGNAL_RETRY return rc; +#endif//SQLITE_WCDB_SIGNAL_RETRY } /* @@ -4603,6 +4611,9 @@ static int unixShmLock( unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ +#if SQLITE_WCDB_SIGNAL_RETRY + int retry = 0; +#endif //SQLITE_WCDB_SIGNAL_RETRY assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); @@ -4656,6 +4667,7 @@ static int unixShmLock( rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY WCDBShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_SHARED); + retry = 1; #endif// SQLITE_WCDB_SIGNAL_RETRY break; } @@ -4684,6 +4696,7 @@ static int unixShmLock( rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY WCDBShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_EXCLUSIVE); + retry = 1; #endif// SQLITE_WCDB_SIGNAL_RETRY break; } @@ -4703,7 +4716,11 @@ static int unixShmLock( sqlite3_mutex_leave(pShmNode->mutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); +#if SQLITE_WCDB_SIGNAL_RETRY + return retry?unixShmLock(fd, ofst, n, flags):rc; +#else//SQLITE_WCDB_SIGNAL_RETRY return rc; +#endif// SQLITE_WCDB_SIGNAL_RETRY } /* diff --git a/src/os_wcdb.c b/src/os_wcdb.c index 78368154fb..1f1c0fded8 100644 --- a/src/os_wcdb.c +++ b/src/os_wcdb.c @@ -97,7 +97,6 @@ void WCDBWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag) if (lastInfo) { if ( (eFileLock==EXCLUSIVE_LOCK&&lastInfo->eFileLock>SHARED_LOCK) || (lastInfo->eFileLock==EXCLUSIVE_LOCK&&eFileLock>SHARED_LOCK)) { - // force signal to avoid dead load WCDBSignal(pInode); return; } @@ -138,7 +137,6 @@ void WCDBShmTrySignal(unixShmNode* pShmNode){ } int eFlag = pInfo->eFlag; int oMask = pInfo->oMask; - // The try lock routine below is the same as [unixShmLock] switch (eFlag) { case SQLITE_SHM_SHARED: { unixShm* pX; From a2ff5bcc2183ddafe2de510e18ceadab0d4f0ae9 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 26 Apr 2017 14:58:47 +0800 Subject: [PATCH 44/94] [iOS]avoid dead lock for SQLITE_WCDB_SIGNAL_RETRY --- src/btree.c | 7 ++ src/main.c | 3 + src/os.h | 5 ++ src/os_unix.c | 44 ++++++------ src/os_wcdb.c | 186 +++++++++++++++++++++++++++----------------------- src/os_wcdb.h | 15 ++-- src/pager.c | 20 ++++++ src/pager.h | 5 ++ src/wal.c | 10 +++ 9 files changed, 183 insertions(+), 112 deletions(-) diff --git a/src/btree.c b/src/btree.c index ebffe6450c..ed6dec247b 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3190,6 +3190,9 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ pBt->btsFlags &= ~BTS_INITIALLY_EMPTY; if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY; +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBPagerSetWait(pBt->pPager, 1); +#endif// SQLITE_WCDB_SIGNAL_RETRY do { /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() @@ -3216,6 +3219,10 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); + +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBPagerSetWait(pBt->pPager, 0); +#endif// SQLITE_WCDB_SIGNAL_RETRY if( rc==SQLITE_OK ){ if( p->inTrans==TRANS_NONE ){ diff --git a/src/main.c b/src/main.c index 392a0042e9..af3407c850 100644 --- a/src/main.c +++ b/src/main.c @@ -1480,6 +1480,9 @@ static int sqliteDefaultBusyCallback( ** returns 0, the operation aborts with an SQLITE_BUSY error. */ int sqlite3InvokeBusyHandler(BusyHandler *p){ +#if SQLITE_WCDB_SIGNAL_RETRY + return 1; +#endif// SQLITE_WCDB_SIGNAL_RETRY int rc; if( NEVER(p==0) || p->xFunc==0 || p->nBusy<0 ) return 0; rc = p->xFunc(p->pArg, p->nBusy); diff --git a/src/os.h b/src/os.h index 947f88b36e..1504a87ed1 100644 --- a/src/os.h +++ b/src/os.h @@ -207,4 +207,9 @@ int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); void sqlite3OsCloseFree(sqlite3_file *); +#if SQLITE_WCDB_SIGNAL_RETRY +void sqlite3OsSetWait(sqlite3_file *, int); +int sqlite3OsGetWait(sqlite3_file *); +#endif// SQLITE_WCDB_SIGNAL_RETRY + #endif /* _SQLITE_OS_H_ */ diff --git a/src/os_unix.c b/src/os_unix.c index c27447245c..98fba3bb8d 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -260,6 +260,9 @@ struct unixFile { */ char aPadding[32]; #endif +#if SQLITE_WCDB_SIGNAL_RETRY + int bWait; +#endif //SQLITE_WCDB_SIGNAL_RETRY }; /* This variable holds the process id (pid) from when the xRandomness() @@ -1574,7 +1577,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ int rc = SQLITE_OK; #if SQLITE_WCDB_SIGNAL_RETRY int eBusyWait = SQLITE_WAIT_NONE; - int retry = 0; #endif// SQLITE_WCDB_SIGNAL_RETRY unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; @@ -1620,7 +1622,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY eBusyWait = SQLITE_WAIT_SHARED; - retry = 1; #endif //SQLITE_WCDB_SIGNAL_RETRY goto end_lock; } @@ -1705,7 +1706,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY eBusyWait = SQLITE_WAIT_EXCLUSIVE; - retry = 1; #endif// SQLITE_WCDB_SIGNAL_RETRY }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is @@ -1762,18 +1762,13 @@ static int unixLock(sqlite3_file *id, int eFileLock){ end_lock: #if SQLITE_WCDB_SIGNAL_RETRY if (eBusyWait!=SQLITE_WAIT_NONE) { - WCDBWait(pInode, pFile, eFileLock, eBusyWait); + WCDBOsWait(pInode, pFile, eFileLock, eBusyWait); } #endif// SQLITE_WCDB_SIGNAL_RETRY unixLeaveMutex(); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); -#if SQLITE_WCDB_SIGNAL_RETRY - //tail call can avoid call stack over flow - return retry?unixLock(id, eFileLock):rc; -#else//SQLITE_WCDB_SIGNAL_RETRY return rc; -#endif//SQLITE_WCDB_SIGNAL_RETRY } /* @@ -1950,7 +1945,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ } #if SQLITE_WCDB_SIGNAL_RETRY - WCDBTrySignal(pInode); + WCDBOsTrySignal(pInode); #endif// SQLITE_WCDB_SIGNAL_RETRY end_unlock: @@ -4611,9 +4606,6 @@ static int unixShmLock( unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ -#if SQLITE_WCDB_SIGNAL_RETRY - int retry = 0; -#endif //SQLITE_WCDB_SIGNAL_RETRY assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); @@ -4652,7 +4644,7 @@ static int unixShmLock( p->exclMask &= ~mask; p->sharedMask &= ~mask; #if SQLITE_WCDB_SIGNAL_RETRY - WCDBShmTrySignal(pShmNode); + WCDBOsShmTrySignal(pShmNode); #endif// SQLITE_WCDB_SIGNAL_RETRY } }else if( flags & SQLITE_SHM_SHARED ){ @@ -4666,8 +4658,7 @@ static int unixShmLock( if( (pX->exclMask & mask)!=0 ){ rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY - WCDBShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_SHARED); - retry = 1; + WCDBOsShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_SHARED); #endif// SQLITE_WCDB_SIGNAL_RETRY break; } @@ -4695,8 +4686,7 @@ static int unixShmLock( if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ rc = SQLITE_BUSY; #if SQLITE_WCDB_SIGNAL_RETRY - WCDBShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_EXCLUSIVE); - retry = 1; + WCDBOsShmWait(pShmNode, pDbFd, mask, SQLITE_SHM_EXCLUSIVE); #endif// SQLITE_WCDB_SIGNAL_RETRY break; } @@ -4716,11 +4706,7 @@ static int unixShmLock( sqlite3_mutex_leave(pShmNode->mutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); -#if SQLITE_WCDB_SIGNAL_RETRY - return retry?unixShmLock(fd, ofst, n, flags):rc; -#else//SQLITE_WCDB_SIGNAL_RETRY return rc; -#endif// SQLITE_WCDB_SIGNAL_RETRY } /* @@ -5348,6 +5334,9 @@ static int fillInUnixFile( pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; +#if SQLITE_WCDB_SIGNAL_RETRY + pNew->bWait = 0; +#endif //SQLITE_WCDB_SIGNAL_RETRY #if SQLITE_MAX_MMAP_SIZE>0 pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif @@ -7775,6 +7764,17 @@ unixShm* WCDBFileGetShm(unixFile* pFile) { return pFile->pShm; } + +int WCDBFileGetWait(unixFile* pFile) +{ + return pFile->bWait; +} + +void WCDBFileSetWait(unixFile* pFile, int bFlag) +{ + pFile->bWait = bFlag; +} + #endif// SQLITE_WCDB_SIGNAL_RETRY #endif /* SQLITE_OS_UNIX */ diff --git a/src/os_wcdb.c b/src/os_wcdb.c index 1f1c0fded8..f424bdc93a 100644 --- a/src/os_wcdb.c +++ b/src/os_wcdb.c @@ -27,97 +27,102 @@ #include "os.h" #include -extern Queue* WCDBInodeGetWaitQueue(unixInodeInfo* pInode); -extern sqlite3_condition* WCDBInodeGetCond(unixInodeInfo* pInode); -extern unsigned char WCDBInodeGetShared(unixInodeInfo* pInode); -extern int WCDBInodeGetFileLock(unixInodeInfo* pInode); +Queue* WCDBInodeGetWaitQueue(unixInodeInfo* pInode); +sqlite3_condition* WCDBInodeGetCond(unixInodeInfo* pInode); +unsigned char WCDBInodeGetShared(unixInodeInfo* pInode); +int WCDBInodeGetFileLock(unixInodeInfo* pInode); -extern Queue* WCDBShmNodeGetWaitQueue(unixShmNode* pShmNode); -extern sqlite3_condition* WCDBShmNodeGetCond(unixShmNode* pShmNode); -extern unixShm* WCDBShmNodeGetShm(unixShmNode* pShmNode); -extern sqlite3_mutex* WCDBShmNodeGetMutex(unixShmNode* pShmNode); +Queue* WCDBShmNodeGetWaitQueue(unixShmNode* pShmNode); +sqlite3_condition* WCDBShmNodeGetCond(unixShmNode* pShmNode); +unixShm* WCDBShmNodeGetShm(unixShmNode* pShmNode); +sqlite3_mutex* WCDBShmNodeGetMutex(unixShmNode* pShmNode); -extern unixShm* WCDBShmGetNext(unixShm* pShm); -extern u16 WCDBShmGetExclMask(unixShm* pShm); -extern u16 WCDBShmGetSharedMask(unixShm* pShm); +unixShm* WCDBShmGetNext(unixShm* pShm); +u16 WCDBShmGetExclMask(unixShm* pShm); +u16 WCDBShmGetSharedMask(unixShm* pShm); -extern unsigned char WCDBFileGetFileLock(unixFile* pFile); -extern unixShm* WCDBFileGetShm(unixFile* pFile); +unsigned char WCDBFileGetFileLock(unixFile* pFile); +unixShm* WCDBFileGetShm(unixFile* pFile); +int WCDBFileGetWait(unixFile* pFile); +void WCDBFileSetWait(unixFile* pFile, int bFlag); -void WCDBSignal(unixInodeInfo* pInode) +void WCDBOsSignal(unixInodeInfo* pInode) { - WCDBWaitInfo* pWaitInfo = (WCDBWaitInfo*)sqlite3QueuePop(WCDBInodeGetWaitQueue(pInode)); - if (pWaitInfo) { - pthreadCondSignal(WCDBInodeGetCond(pInode), pWaitInfo->pThread); - pthreadFree(pWaitInfo->pThread); - sqlite3_free(pWaitInfo); - } + WCDBWaitInfo* pWaitInfo = (WCDBWaitInfo*)sqlite3QueuePop(WCDBInodeGetWaitQueue(pInode)); + if (pWaitInfo) { + pthreadCondSignal(WCDBInodeGetCond(pInode), pWaitInfo->pThread); + pthreadFree(pWaitInfo->pThread); + sqlite3_free(pWaitInfo); + } } -void WCDBTrySignal(unixInodeInfo* pInode) +void WCDBOsTrySignal(unixInodeInfo* pInode) { - int rc; - do { - rc = SQLITE_BUSY; - WCDBWaitInfo* pWaitInfo = (WCDBWaitInfo*)sqlite3QueueFront(WCDBInodeGetWaitQueue(pInode)); - if (!pWaitInfo) { - break; - } - int eFlag = pWaitInfo->eFlag; - int eFileLock = pWaitInfo->eFileLock; - unixFile* pFile = pWaitInfo->pFile; - switch (eFlag) { - case SQLITE_WAIT_SHARED: { - rc = SQLITE_OK; - if( (WCDBFileGetFileLock(pFile)!=WCDBInodeGetFileLock(pInode) && - (WCDBInodeGetFileLock(pInode)>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ) { - rc = SQLITE_BUSY; - } - break; - } - case SQLITE_WAIT_EXCLUSIVE: { - rc = SQLITE_OK; - if( eFileLock==EXCLUSIVE_LOCK && WCDBInodeGetShared(pInode)>1 ) { - rc = SQLITE_BUSY; - } - break; - } - default: - break; + int rc; + do { + rc = SQLITE_BUSY; + WCDBWaitInfo* pWaitInfo = (WCDBWaitInfo*)sqlite3QueueFront(WCDBInodeGetWaitQueue(pInode)); + if (!pWaitInfo) { + break; + } + int eFlag = pWaitInfo->eFlag; + int eFileLock = pWaitInfo->eFileLock; + unixFile* pFile = pWaitInfo->pFile; + switch (eFlag) { + case SQLITE_WAIT_SHARED: { + rc = SQLITE_OK; + if( (WCDBFileGetFileLock(pFile)!=WCDBInodeGetFileLock(pInode) && + (WCDBInodeGetFileLock(pInode)>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ) { + rc = SQLITE_BUSY; } - if (rc==SQLITE_OK) { - WCDBSignal(pInode); + break; + } + case SQLITE_WAIT_EXCLUSIVE: { + rc = SQLITE_OK; + if( eFileLock==EXCLUSIVE_LOCK && WCDBInodeGetShared(pInode)>1 ) { + rc = SQLITE_BUSY; } - } while (rc==SQLITE_OK); + break; + } + default: + break; + } + if (rc==SQLITE_OK) { + WCDBOsSignal(pInode); + } + } while (rc==SQLITE_OK); } -void WCDBWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag) +void WCDBOsWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag) { - WCDBWaitInfo* lastInfo = (WCDBWaitInfo*)sqlite3QueueFront(WCDBInodeGetWaitQueue(pInode)); - if (lastInfo) { - if ( (eFileLock==EXCLUSIVE_LOCK&&lastInfo->eFileLock>SHARED_LOCK) - || (lastInfo->eFileLock==EXCLUSIVE_LOCK&&eFileLock>SHARED_LOCK)) { - WCDBSignal(pInode); - return; - } - } - WCDBWaitInfo* info = (WCDBWaitInfo*)sqlite3_malloc(sizeof(WCDBWaitInfo)); - info->eFlag = eFlag; - info->eFileLock = eFileLock; - info->pFile = pFile; - info->pThread = pthreadAlloc(); - pthreadSelf(info->pThread); - if (pthreadIsMain()) { - sqlite3QueuePushFront(WCDBInodeGetWaitQueue(pInode), info); - }else { - sqlite3QueuePush(WCDBInodeGetWaitQueue(pInode), info); - } - if (pthreadCondWait(WCDBInodeGetCond(pInode), unixVFSMutex(), 10)==ETIMEDOUT) { - sqlite3_log(SQLITE_WARNING, "Wait Failed With Timeout"); + if (!WCDBFileGetWait(pFile)) { + return; + } + WCDBWaitInfo* lastInfo = (WCDBWaitInfo*)sqlite3QueueFront(WCDBInodeGetWaitQueue(pInode)); + if (lastInfo) { + if ( (eFileLock==EXCLUSIVE_LOCK&&lastInfo->eFileLock>SHARED_LOCK) + || (lastInfo->eFileLock==EXCLUSIVE_LOCK&&eFileLock>SHARED_LOCK)) { + WCDBOsSignal(pInode); + return; } + } + WCDBWaitInfo* info = (WCDBWaitInfo*)sqlite3_malloc(sizeof(WCDBWaitInfo)); + info->eFlag = eFlag; + info->eFileLock = eFileLock; + info->pFile = pFile; + info->pThread = pthreadAlloc(); + pthreadSelf(info->pThread); + if (pthreadIsMain()) { + sqlite3QueuePushFront(WCDBInodeGetWaitQueue(pInode), info); + }else { + sqlite3QueuePush(WCDBInodeGetWaitQueue(pInode), info); + } + if (pthreadCondWait(WCDBInodeGetCond(pInode), unixVFSMutex(), 10)==ETIMEDOUT) { + sqlite3_log(SQLITE_WARNING, "Wait Failed With Timeout"); + } } -void WCDBShmSignal(unixShmNode* pShmNode) +void WCDBOsShmSignal(unixShmNode* pShmNode) { WCDBShmWaitInfo* pInfo = (WCDBShmWaitInfo*)sqlite3QueuePop(WCDBShmNodeGetWaitQueue(pShmNode)); if (pInfo) { @@ -127,7 +132,7 @@ void WCDBShmSignal(unixShmNode* pShmNode) } } -void WCDBShmTrySignal(unixShmNode* pShmNode){ +void WCDBOsShmTrySignal(unixShmNode* pShmNode){ int rc; do { rc = SQLITE_BUSY; @@ -164,27 +169,30 @@ void WCDBShmTrySignal(unixShmNode* pShmNode){ break; } if (rc==SQLITE_OK) { - WCDBShmSignal(pShmNode); + WCDBOsShmSignal(pShmNode); } } while (rc==SQLITE_OK); } -void WCDBShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag) +void WCDBOsShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag) { + if (!WCDBFileGetWait(pFile)) { + return; + } WCDBShmWaitInfo* lastInfo = (WCDBShmWaitInfo*)sqlite3QueueFront(WCDBShmNodeGetWaitQueue(pShmNode)); if (lastInfo) { if (lastInfo->eFlag==SQLITE_SHM_EXCLUSIVE &&((WCDBShmGetExclMask(WCDBFileGetShm(pFile))&lastInfo->oMask)!=0 ||(WCDBShmGetSharedMask(WCDBFileGetShm(pFile))&lastInfo->oMask)!=0)) { - WCDBShmSignal(pShmNode); - return; - } + WCDBOsShmSignal(pShmNode); + return; + } if (eFlag==SQLITE_SHM_EXCLUSIVE &&((WCDBShmGetExclMask(WCDBFileGetShm(lastInfo->pFile))&oMask)!=0 ||(WCDBShmGetSharedMask(WCDBFileGetShm(lastInfo->pFile))&oMask)!=0)) { - WCDBShmSignal(pShmNode); - return; - } + WCDBOsShmSignal(pShmNode); + return; + } } WCDBShmWaitInfo* info = (WCDBShmWaitInfo*)sqlite3_malloc(sizeof(WCDBShmWaitInfo)); @@ -203,4 +211,14 @@ void WCDBShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag) } } +void WCDBOsFileSetWait(sqlite3_file* id, int bFlag) +{ + WCDBFileSetWait((unixFile*)id, bFlag); +} + +int WCDBOsFileGetWait(sqlite3_file* id) +{ + return WCDBFileGetWait((unixFile*)id); +} + #endif// SQLITE_WCDB_SIGNAL_RETRY diff --git a/src/os_wcdb.h b/src/os_wcdb.h index 74953ccaae..e06079f807 100644 --- a/src/os_wcdb.h +++ b/src/os_wcdb.h @@ -51,13 +51,16 @@ struct WCDBShmWaitInfo { unixFile* pFile; }; -void WCDBSignal(unixInodeInfo* pInode); -void WCDBTrySignal(unixInodeInfo* pInode); -void WCDBWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag); +void WCDBOsSignal(unixInodeInfo* pInode); +void WCDBOsTrySignal(unixInodeInfo* pInode); +void WCDBOsWait(unixInodeInfo* pInode, unixFile* pFile, int eFileLock, int eFlag); -void WCDBShmSignal(unixShmNode* pShmNode); -void WCDBShmTrySignal(unixShmNode* pShmNode); -void WCDBShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag); +void WCDBOsShmSignal(unixShmNode* pShmNode); +void WCDBOsShmTrySignal(unixShmNode* pShmNode); +void WCDBOsShmWait(unixShmNode* pShmNode, unixFile* pFile, int oMask, int eFlag); + +void WCDBOsFileSetWait(sqlite3_file* fd, int bFlag); +int WCDBOsFileGetWait(sqlite3_file* fd); #endif// SQLITE_WCDB_SIGNAL_RETRY diff --git a/src/pager.c b/src/pager.c index f146c96de0..47b410a637 100644 --- a/src/pager.c +++ b/src/pager.c @@ -21,6 +21,9 @@ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "wal.h" +#if SQLITE_WCDB_SIGNAL_RETRY +#include "os_wcdb.h" +#endif// SQLITE_WCDB_SIGNAL_RETRY /******************* NOTES ON THE DESIGN OF THE PAGER ************************ @@ -3840,9 +3843,15 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK) ); +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBPagerSetWait(pPager, 1); +#endif// SQLITE_WCDB_SIGNAL_RETRY do { rc = pagerLockDb(pPager, locktype); }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) ); +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBPagerSetWait(pPager, 0); +#endif// SQLITE_WCDB_SIGNAL_RETRY return rc; } @@ -7412,6 +7421,17 @@ int sqlite3PagerWalFramesize(Pager *pPager){ } #endif +#if SQLITE_WCDB_SIGNAL_RETRY +void WCDBPagerSetWait(Pager* pPager, int bFlag) +{ + WCDBOsFileSetWait(pPager->fd, bFlag); +} +int WCDBPagerGetWait(Pager* pPager) +{ + return WCDBOsFileGetWait(pPager->fd); +} +#endif// SQLITE_WCDB_SIGNAL_RETRY + #endif /* SQLITE_OMIT_DISKIO */ /* BEGIN SQLCIPHER */ diff --git a/src/pager.h b/src/pager.h index fe71fde50b..a283cebed7 100644 --- a/src/pager.h +++ b/src/pager.h @@ -233,4 +233,9 @@ void *sqlite3PagerCodec(DbPage *); # define enable_simulated_io_errors() #endif +#if SQLITE_WCDB_SIGNAL_RETRY +void WCDBPagerSetWait(Pager* pPager, int bFlag); +int WCDBPagerGetWait(Pager* pPager); +#endif// SQLITE_WCDB_SIGNAL_RETRY + #endif /* SQLITE_PAGER_H */ diff --git a/src/wal.c b/src/wal.c index 235d383e1a..7b2fb6b1db 100644 --- a/src/wal.c +++ b/src/wal.c @@ -243,6 +243,9 @@ #ifndef SQLITE_OMIT_WAL #include "wal.h" +#if SQLITE_WCDB_SIGNAL_RETRY +#include "os_wcdb.h" +#endif// SQLITE_WCDB_SIGNAL_RETRY /* ** Trace output macros @@ -2304,7 +2307,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ && (mxReadMarkpDbFd); + WCDBOsFileSetWait(pWal->pDbFd, 0); +#endif// SQLITE_WCDB_SIGNAL_RETRY rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); +#if SQLITE_WCDB_SIGNAL_RETRY + WCDBOsFileSetWait(pWal->pDbFd, bWait); +#endif// SQLITE_WCDB_SIGNAL_RETRY if( rc==SQLITE_OK ){ mxReadMark = pInfo->aReadMark[i] = mxFrame; mxI = i; From 56dad2e480f7a88757ba3c5f369c7cd48a2aba32 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 2 May 2017 17:42:26 +0800 Subject: [PATCH 45/94] [iOS]add recommended compiler optional --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 9554f95e1d..ef732efa33 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -755,6 +755,14 @@ HAVE_USLEEP, "SQLITE_MALLOC_SOFT_LIMIT=0", "SQLITE_WCDB_SIGNAL_RETRY=1", + "SQLITE_DEFAULT_MEMSTATUS=0", + "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", + SQLITE_LIKE_DOESNT_MATCH_BLOBS, + "SQLITE_MAX_EXPR_DEPTH=0", + SQLITE_OMIT_DECLTYPE, + SQLITE_OMIT_DEPRECATED, + SQLITE_OMIT_PROGRESS_CALLBACK, + SQLITE_OMIT_SHARED_CACHE, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -843,6 +851,14 @@ HAVE_USLEEP, "SQLITE_MALLOC_SOFT_LIMIT=0", "SQLITE_WCDB_SIGNAL_RETRY=1", + "SQLITE_DEFAULT_MEMSTATUS=0", + "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", + SQLITE_LIKE_DOESNT_MATCH_BLOBS, + "SQLITE_MAX_EXPR_DEPTH=0", + SQLITE_OMIT_DECLTYPE, + SQLITE_OMIT_DEPRECATED, + SQLITE_OMIT_PROGRESS_CALLBACK, + SQLITE_OMIT_SHARED_CACHE, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; From 2efced72b82f1ca40b773adf2b3807ee907aa3be Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sat, 6 May 2017 21:18:26 +0800 Subject: [PATCH 46/94] [iOS]SQLITE_ENABLE_UPDATE_DELETE_LIMIT options that must be known by the code generators includes --- Makefile.preprocessed | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.preprocessed b/Makefile.preprocessed index 9d23f5599a..1aa603fb06 100644 --- a/Makefile.preprocessed +++ b/Makefile.preprocessed @@ -14,7 +14,8 @@ all: $(SRC) $(SRC): Makefile make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c Makefile: configure - ./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2" --disable-amalgamation + ./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" --disable-amalgamation make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c clean: make clean + rm Makefile \ No newline at end of file From 0ca064e6196062833a5578c44ff2d293c81cc17e Mon Sep 17 00:00:00 2001 From: johnwhe Date: Mon, 15 May 2017 20:39:45 +0800 Subject: [PATCH 47/94] Add devlock crypto extension for KKDB LockDevice compatibility. --- Makefile.in | 6 +- ext/crypto/devlock.c | 175 +++++++++++++++++++++++++++++++++++++++++++ ext/crypto/xxtea.c | 40 +++++++--- src/crypto_custom.c | 44 ++++++++++- src/crypto_impl.c | 13 ++++ src/loadext.c | 14 +++- src/sqlcipher.h | 1 + src/sqlite3ext.h | 7 +- tool/mksqlite3c.tcl | 1 + 9 files changed, 279 insertions(+), 22 deletions(-) create mode 100644 ext/crypto/devlock.c diff --git a/Makefile.in b/Makefile.in index 4bbc21f65e..47f5f581d1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -377,7 +377,8 @@ SRC += \ # Source code for crypto extensions # SRC += \ - $(TOP)/ext/crypto/xxtea.c + $(TOP)/ext/crypto/xxtea.c \ + $(TOP)/ext/crypto/devlock.c # Generated source code files @@ -1068,6 +1069,9 @@ json1.lo: $(TOP)/ext/misc/json1.c xxtea.lo: $(TOP)/ext/crypto/xxtea.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/crypto/xxtea.c +devlock.lo: $(TOP)/ext/crypto/devlock.c + $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/crypto/devlock.c + # FTS5 things # FTS5_SRC = \ diff --git a/ext/crypto/devlock.c b/ext/crypto/devlock.c new file mode 100644 index 0000000000..6a0541c633 --- /dev/null +++ b/ext/crypto/devlock.c @@ -0,0 +1,175 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* BEGIN SQLCIPHER */ +#if defined(SQLITE_HAS_CODEC) && defined(SQLCIPHER_CRYPTO_CUSTOM) +#if defined(SQLCIPHER_CRYPTO_DEVLOCK) || !defined(SQLITE_CORE) + +#include +#include +#include +#include +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 + + +static unsigned char g_device_salt[16]; +static volatile int g_init = 0; + + +static int read_cpu_serial(char *buf, int buf_len) { + int ret = 0; + char line[256]; + FILE *fp = fopen("/proc/cpuinfo", "r"); + if (!fp) return 0; + + while (fgets(line, sizeof(line), fp)) { + if (strncmp(line, "Serial", 6)) + continue; + + char *pch = strchr(line, ':'); + if (!pch) continue; + + char c; + while ((c = *++pch) != 0) { + if (c != ' ' && c != '\t') break; + } + + while ((c = *++pch) != 0) { + if (c == '\r' || c == '\n') break; + if (ret >= buf_len) break; + buf[ret++] = c; + } + break; + } + + fclose(fp); + return ret; +} + +#ifdef __ANDROID__ +#include + +static int read_android_serial(char *buf, int buf_len) { + assert(buf_len >= PROP_VALUE_MAX); + return __system_property_get("ro.serialno", buf); +} +#endif + + +static void init_device_salt(void *ctx) { + if (g_init) return; + + char serial[256]; + int serial_len = 0; + +#ifdef __ANDROID__ + serial_len += read_android_serial(serial + serial_len, sizeof(serial) - serial_len); +#endif + serial_len += read_cpu_serial(serial + serial_len, sizeof(serial) - serial_len); + + sqlcipher_get_fallback_provider()->kdf(ctx, (unsigned char *) serial, serial_len, + (unsigned char *) serial, serial_len, 1, sizeof(g_device_salt), g_device_salt); + + g_init = 1; +} + +static int sqlcipher_devlock_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, + int salt_sz, int workfactor, int key_sz, unsigned char *key) { + + const sqlcipher_provider *p = sqlcipher_get_fallback_provider(); + int ret = p->kdf(ctx, pass, pass_sz, salt, salt_sz, workfactor, key_sz, key); + if (ret != SQLITE_OK) + return ret; + + unsigned char *buf = alloca(key_sz); + memcpy(buf, key, key_sz); + return p->kdf(ctx, buf, key_sz, g_device_salt, sizeof(g_device_salt), 1, key_sz, key); +} + +static const char *sqlcipher_devlock_get_provider_name(void *ctx) { + return "devlock"; +} + +static const char *sqlcipher_devlock_get_provider_version(void *ctx) { + return "0.1"; +} + +static int sqlcipher_devlock_set_cipher(void *ctx, const char *cipher_name) { + return sqlcipher_get_fallback_provider()->set_cipher(ctx, "aes-256-cbc"); +} + +static const char *sqlcipher_devlock_get_cipher(void *ctx) { + return "devlock"; +} + +static int sqlcipher_devlock_ctx_init(void **ctx) { + sqlcipher_get_fallback_provider()->ctx_init(ctx); + init_device_salt(*ctx); + return SQLITE_OK; +} + +static volatile int g_devlock_registered = 0; +static const sqlcipher_provider g_devlock_provider = { + 0, /* activate */ + 0, /* deactivate */ + sqlcipher_devlock_get_provider_name,/* get_provider_name */ + 0, /* add_random */ + 0, /* random */ + 0, /* hmac */ + sqlcipher_devlock_kdf, /* kdf */ + 0, /* cipher */ + sqlcipher_devlock_set_cipher, /* set_cipher */ + sqlcipher_devlock_get_cipher, /* get_cipher */ + 0, /* get_key_sz */ + 0, /* get_iv_sz */ + 0, /* get_block_sz */ + 0, /* get_hmac_sz */ + 0, /* ctx_copy */ + 0, /* ctx_cmp */ + sqlcipher_devlock_ctx_init, /* ctx_init */ + 0, /* ctx_free */ + 0, /* fips_status */ + sqlcipher_devlock_get_provider_version +}; + +#ifndef SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_devlock_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { + SQLITE_EXTENSION_INIT2(pApi); + + if (!g_devlock_registered) { + g_devlock_registered = 1; + return sqlcipher_register_custom_provider("devlock", &g_devlock_provider); + } + + return SQLITE_OK; +} +#else /* SQLITE_CORE */ +int sqlcipherCryptoDevlockInit() { + g_devlock_registered = 1; + return sqlcipher_register_custom_provider("devlock", &g_devlock_provider); +} +#endif + +#endif /* defined(SQLCIPHER_CRYPTO_DEVLOCK) || !defined(SQLITE_CORE) */ +#endif /* SQLITE_HAS_CODEC && SQLCIPHER_CRYPTO_CUSTOM */ diff --git a/ext/crypto/xxtea.c b/ext/crypto/xxtea.c index 9fac9ff6ba..7503e32a6e 100644 --- a/ext/crypto/xxtea.c +++ b/ext/crypto/xxtea.c @@ -1,5 +1,25 @@ +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /* BEGIN SQLCIPHER */ -#ifdef SQLITE_HAS_CODEC +#if defined(SQLITE_HAS_CODEC) && defined(SQLCIPHER_CRYPTO_CUSTOM) #if defined(SQLCIPHER_CRYPTO_XXTEA) || !defined(SQLITE_CORE) #include "sqlite3ext.h" @@ -163,14 +183,10 @@ static int sqlcipher_xxtea_fips_status(void *ctx) { return 0; } -static int sqlcipher_xxtea_dummy_activate(void *ctx) { - return SQLITE_OK; -} - -static volatile int g_cipher_registered = 0; +static volatile int g_xxtea_registered = 0; static const sqlcipher_provider g_xxtea_provider = { - sqlcipher_xxtea_dummy_activate, /* activate */ - sqlcipher_xxtea_dummy_activate, /* deactivate */ + 0, /* activate */ + 0, /* deactivate */ sqlcipher_xxtea_get_provider_name, /* get_provider_name */ 0, /* add_random */ 0, /* random */ @@ -198,8 +214,8 @@ __declspec(dllexport) int sqlite3_xxtea_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { SQLITE_EXTENSION_INIT2(pApi); - if (!g_cipher_registered) { - g_cipher_registered = 1; + if (!g_xxtea_registered) { + g_xxtea_registered = 1; return sqlcipher_register_custom_provider("xxtea", &g_xxtea_provider); } @@ -207,10 +223,10 @@ int sqlite3_xxtea_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines } #else /* SQLITE_CORE */ int sqlcipherCryptoXxteaInit() { - g_cipher_registered = 1; + g_xxtea_registered = 1; return sqlcipher_register_custom_provider("xxtea", &g_xxtea_provider); } #endif #endif /* defined(SQLCIPHER_CRYPTO_XXTEA) || !defined(SQLITE_CORE) */ -#endif /* SQLITE_HAS_CODEC */ +#endif /* SQLITE_HAS_CODEC && SQLCIPHER_CRYPTO_CUSTOM */ diff --git a/src/crypto_custom.c b/src/crypto_custom.c index b62a0529c8..18e124136c 100644 --- a/src/crypto_custom.c +++ b/src/crypto_custom.c @@ -1,5 +1,24 @@ - -#ifdef SQLITE_HAS_CODEC +/* + * Tencent is pleased to support the open source community by making + * WCDB available. + * + * Copyright (C) 2017 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(SQLITE_HAS_CODEC) && defined(SQLCIPHER_CRYPTO_CUSTOM) #include "sqliteInt.h" #include "sqlcipher.h" @@ -29,12 +48,19 @@ static sqlite3_mutex *custom_providers_mutex; static sqlcipher_provider *fallback_provider; static int activate_count = 0; +static int sqlcipher_dummy_activate(void *ctx) { + return SQLITE_OK; +} + static void provider_overload(const sqlcipher_provider *base, sqlcipher_provider *p) { + if (!p->activate) p->activate = sqlcipher_dummy_activate; + if (!p->deactivate) p->deactivate = sqlcipher_dummy_activate; + /* sqlcipher_provider is actually a pile of function pointers, which has the same size of (void *). We can just run a loop comparing and assigning raw pointers. */ int n = sizeof(sqlcipher_provider) / sizeof(void *); int i; - for (i = 0; i < n; i++) { + for (i = 2; i < n; i++) { if ( ((void **) p)[i] == 0 ) ((void **) p)[i] = ((void **) base)[i]; } @@ -144,6 +170,10 @@ int sqlcipher_unregister_custom_provider(const char *name) { return SQLITE_OK; } +const sqlcipher_provider *sqlcipher_get_fallback_provider() { + return fallback_provider; +} + static int sqlcipher_custom_activate(void *ctx) { sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(mutex); @@ -175,6 +205,12 @@ static int sqlcipher_custom_activate(void *ctx) { extern int sqlcipherCryptoXxteaInit(); rc = sqlcipherCryptoXxteaInit(); } +#endif +#ifdef SQLCIPHER_CRYPTO_DEVLOCK + if (rc == SQLITE_OK) { + extern int sqlcipherCryptoDevlockInit(); + rc = sqlcipherCryptoDevlockInit(); + } #endif (void) rc; } @@ -361,4 +397,4 @@ int sqlcipher_custom_setup(sqlcipher_provider *p) { return SQLITE_OK; } -#endif /* SQLITE_HAS_CODEC */ +#endif /* SQLITE_HAS_CODEC && SQLCIPHER_CRYPTO_CUSTOM */ diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 1a8c394be8..5d6eb4a80a 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -120,8 +120,21 @@ void sqlcipher_activate() { if(sqlcipher_get_provider() == NULL) { sqlcipher_provider *p = sqlcipher_malloc(sizeof(sqlcipher_provider)); +#if defined(SQLCIPHER_CRYPTO_CUSTOM) extern int sqlcipher_custom_setup(sqlcipher_provider *p); sqlcipher_custom_setup(p); +#elif defined (SQLCIPHER_CRYPTO_CC) + extern int sqlcipher_cc_setup(sqlcipher_provider *p); + sqlcipher_cc_setup(fallback_provider); +#elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) + extern int sqlcipher_ltc_setup(sqlcipher_provider *p); + sqlcipher_ltc_setup(fallback_provider); +#elif defined (SQLCIPHER_CRYPTO_OPENSSL) + extern int sqlcipher_openssl_setup(sqlcipher_provider *p); + sqlcipher_openssl_setup(fallback_provider); +#else +#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED" +#endif sqlcipher_register_provider(p); } diff --git a/src/loadext.c b/src/loadext.c index 0e790ff756..7cf9b4638c 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -133,12 +133,20 @@ static const sqlcipher_api_routines sqlcipherApis = { sqlcipher_register_provider, sqlcipher_get_provider, - sqlcipher_register_custom_provider, - sqlcipher_unregister_custom_provider, sqlite3_key, sqlite3_key_v2, sqlite3_rekey, - sqlite3_rekey_v2 + sqlite3_rekey_v2, + +#ifdef SQLCIPHER_CRYPTO_CUSTOM + sqlcipher_register_custom_provider, + sqlcipher_unregister_custom_provider, + sqlcipher_get_fallback_provider, +#else + 0, + 0, + 0, +#endif }; #endif diff --git a/src/sqlcipher.h b/src/sqlcipher.h index d93727086c..aa97ecaddc 100644 --- a/src/sqlcipher.h +++ b/src/sqlcipher.h @@ -64,6 +64,7 @@ SQLITE_API int SQLITE_STDCALL sqlcipher_register_provider(sqlcipher_provider *p) SQLITE_API sqlcipher_provider* SQLITE_STDCALL sqlcipher_get_provider(); SQLITE_API int SQLITE_STDCALL sqlcipher_register_custom_provider(const char *name, const sqlcipher_provider *p); SQLITE_API int SQLITE_STDCALL sqlcipher_unregister_custom_provider(const char *name); +SQLITE_API const sqlcipher_provider* SQLITE_STDCALL sqlcipher_get_fallback_provider(); #endif #endif diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 2e83a719b0..219f556625 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -37,12 +37,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; struct sqlcipher_api_routines { int (*register_provider)(sqlcipher_provider *p); sqlcipher_provider* (*get_provider)(); - int (*register_custom_provider)(const char *name, const sqlcipher_provider *p); - int (*unregister_custom_provider)(const char *name); int (*key)(sqlite3 *db, const void *pKey, int nKey); int (*key_v2)(sqlite3 *db, const char *zDb, const void *pKey, int nKey); int (*rekey)(sqlite3 *db, const void *pKey, int nKey); int (*rekey_v2)(sqlite3 *db, const char *zDb, const void *pKey, int nKey); + + int (*register_custom_provider)(const char *name, const sqlcipher_provider *p); + int (*unregister_custom_provider)(const char *name); + const sqlcipher_provider* (*get_fallback_provider)(); }; #endif @@ -576,6 +578,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlcipher_get_provider sqlite3_api->sqlcipher->get_provider #define sqlcipher_register_custom_provider sqlite3_api->sqlcipher->register_custom_provider #define sqlcipher_unregister_custom_provider sqlite3_api->sqlcipher->unregister_custom_provider +#define sqlcipher_get_fallback_provider sqlite3_api->sqlcipher->get_fallback_provider #endif #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index c084ccab7a..79d76c8caa 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -401,6 +401,7 @@ foreach file { json1.c fts5.c xxtea.c + devlock.c } { copy_file tsrc/$file } From 0afe66021bb8a86ac0067a5186790bd11609135d Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 19 May 2017 11:42:43 +0800 Subject: [PATCH 48/94] [iOS]remove unused file;mute all warning --- macosx/module.modulemap | 6 +++ sqlcipher framework/Info.plist | 26 ----------- sqlcipher framework/sqcliphertest.h | 31 ------------- .../project.pbxproj | 46 ++++++++----------- 4 files changed, 25 insertions(+), 84 deletions(-) create mode 100644 macosx/module.modulemap delete mode 100644 sqlcipher framework/Info.plist delete mode 100644 sqlcipher framework/sqcliphertest.h diff --git a/macosx/module.modulemap b/macosx/module.modulemap new file mode 100644 index 0000000000..899233d985 --- /dev/null +++ b/macosx/module.modulemap @@ -0,0 +1,6 @@ +framework module sqlcipher { + umbrella header "sqlite3.h" + + export * + module * { export * } +} diff --git a/sqlcipher framework/Info.plist b/sqlcipher framework/Info.plist deleted file mode 100644 index b38c994e86..0000000000 --- a/sqlcipher framework/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2017年 sanhuazhang. All rights reserved. - NSPrincipalClass - - - diff --git a/sqlcipher framework/sqcliphertest.h b/sqlcipher framework/sqcliphertest.h deleted file mode 100644 index 97bb95c485..0000000000 --- a/sqlcipher framework/sqcliphertest.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making - * WCDB available. - * - * Copyright (C) 2017 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of - * the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import - -//! Project version number for sqcliphertest. -FOUNDATION_EXPORT double sqcliphertestVersionNumber; - -//! Project version string for sqcliphertest. -FOUNDATION_EXPORT const unsigned char sqcliphertestVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index ef732efa33..3763b138c7 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -125,8 +125,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 2311206C1E8373A6008A94C3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2311206D1E8373A6008A94C3 /* sqcliphertest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqcliphertest.h; sourceTree = ""; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 234E92221EAEF58100C5428D /* os_wcdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_wcdb.c; path = src/os_wcdb.c; sourceTree = SOURCE_ROOT; }; 234E92231EAEF58100C5428D /* os_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_wcdb.h; path = src/os_wcdb.h; sourceTree = SOURCE_ROOT; }; @@ -267,6 +265,7 @@ 2395298F1E7010030054D75E /* vdbemem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbemem.c; path = src/vdbemem.c; sourceTree = SOURCE_ROOT; }; 239529901E7010030054D75E /* vdbesort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbesort.c; path = src/vdbesort.c; sourceTree = SOURCE_ROOT; }; 239529911E7010030054D75E /* vdbetrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbetrace.c; path = src/vdbetrace.c; sourceTree = SOURCE_ROOT; }; + 239D64E61ECE9FE8008F5B61 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -280,19 +279,10 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 2311206B1E8373A6008A94C3 /* sqlcipher framework */ = { - isa = PBXGroup; - children = ( - 2311206C1E8373A6008A94C3 /* Info.plist */, - 2311206D1E8373A6008A94C3 /* sqcliphertest.h */, - ); - path = "sqlcipher framework"; - sourceTree = ""; - }; 23121ADB1E6FF9110012B45E = { isa = PBXGroup; children = ( - 2311206B1E8373A6008A94C3 /* sqlcipher framework */, + 239D64E41ECE9FE8008F5B61 /* macosx */, 23121B7C1E6FF93D0012B45E /* src */, 23121C061E6FFA890012B45E /* Frameworks */, 23121AE51E6FF9110012B45E /* Products */, @@ -461,6 +451,14 @@ name = Frameworks; sourceTree = ""; }; + 239D64E41ECE9FE8008F5B61 /* macosx */ = { + isa = PBXGroup; + children = ( + 239D64E61ECE9FE8008F5B61 /* Info.plist */, + ); + path = macosx; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -495,9 +493,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 239325C71E836A7700D677CC /* sqlcipher framework */ = { + 239325C71E836A7700D677CC /* sqlcipher */ = { isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; buildPhases = ( 239325C31E836A7700D677CC /* Sources */, 239325C41E836A7700D677CC /* Frameworks */, @@ -509,7 +507,7 @@ dependencies = ( 239325D11E836A9000D677CC /* PBXTargetDependency */, ); - name = "sqlcipher framework"; + name = sqlcipher; productName = sqlcipher; productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; @@ -545,7 +543,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 239325C71E836A7700D677CC /* sqlcipher framework */, + 239325C71E836A7700D677CC /* sqlcipher */, 2395299B1E702CF90054D75E /* preprocess */, ); }; @@ -717,7 +715,6 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; @@ -764,12 +761,9 @@ SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; @@ -816,7 +810,6 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; @@ -860,12 +853,9 @@ SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; @@ -890,10 +880,11 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = "sqlcipher framework/Info.plist"; + INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; + MODULEMAP_FILE = macosx/module.modulemap; PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; @@ -913,10 +904,11 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "sqlcipher framework/Info.plist"; + INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; + MODULEMAP_FILE = macosx/module.modulemap; PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; @@ -964,7 +956,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */ = { + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { isa = XCConfigurationList; buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, From ea2bef658ef72d1ef6925c03e57804decc3edb9b Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sat, 6 May 2017 21:18:26 +0800 Subject: [PATCH 49/94] [iOS]SQLITE_ENABLE_UPDATE_DELETE_LIMIT options that must be known by the code generators includes --- Makefile.preprocessed | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.preprocessed b/Makefile.preprocessed index 9d23f5599a..1aa603fb06 100644 --- a/Makefile.preprocessed +++ b/Makefile.preprocessed @@ -14,7 +14,8 @@ all: $(SRC) $(SRC): Makefile make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c Makefile: configure - ./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2" --disable-amalgamation + ./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" --disable-amalgamation make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c clean: make clean + rm Makefile \ No newline at end of file From da39f274a46c732b2c007b87dfaf89ecf1b9d93e Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 19 May 2017 11:42:43 +0800 Subject: [PATCH 50/94] [iOS]remove unused file;mute all warning --- macosx/module.modulemap | 6 +++ sqlcipher framework/Info.plist | 26 ----------- sqlcipher framework/sqcliphertest.h | 31 ------------- .../project.pbxproj | 46 ++++++++----------- 4 files changed, 25 insertions(+), 84 deletions(-) create mode 100644 macosx/module.modulemap delete mode 100644 sqlcipher framework/Info.plist delete mode 100644 sqlcipher framework/sqcliphertest.h diff --git a/macosx/module.modulemap b/macosx/module.modulemap new file mode 100644 index 0000000000..899233d985 --- /dev/null +++ b/macosx/module.modulemap @@ -0,0 +1,6 @@ +framework module sqlcipher { + umbrella header "sqlite3.h" + + export * + module * { export * } +} diff --git a/sqlcipher framework/Info.plist b/sqlcipher framework/Info.plist deleted file mode 100644 index b38c994e86..0000000000 --- a/sqlcipher framework/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2017年 sanhuazhang. All rights reserved. - NSPrincipalClass - - - diff --git a/sqlcipher framework/sqcliphertest.h b/sqlcipher framework/sqcliphertest.h deleted file mode 100644 index 97bb95c485..0000000000 --- a/sqlcipher framework/sqcliphertest.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making - * WCDB available. - * - * Copyright (C) 2017 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of - * the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import - -//! Project version number for sqcliphertest. -FOUNDATION_EXPORT double sqcliphertestVersionNumber; - -//! Project version string for sqcliphertest. -FOUNDATION_EXPORT const unsigned char sqcliphertestVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index ef732efa33..3763b138c7 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -125,8 +125,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 2311206C1E8373A6008A94C3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2311206D1E8373A6008A94C3 /* sqcliphertest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqcliphertest.h; sourceTree = ""; }; 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 234E92221EAEF58100C5428D /* os_wcdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_wcdb.c; path = src/os_wcdb.c; sourceTree = SOURCE_ROOT; }; 234E92231EAEF58100C5428D /* os_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_wcdb.h; path = src/os_wcdb.h; sourceTree = SOURCE_ROOT; }; @@ -267,6 +265,7 @@ 2395298F1E7010030054D75E /* vdbemem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbemem.c; path = src/vdbemem.c; sourceTree = SOURCE_ROOT; }; 239529901E7010030054D75E /* vdbesort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbesort.c; path = src/vdbesort.c; sourceTree = SOURCE_ROOT; }; 239529911E7010030054D75E /* vdbetrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbetrace.c; path = src/vdbetrace.c; sourceTree = SOURCE_ROOT; }; + 239D64E61ECE9FE8008F5B61 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -280,19 +279,10 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 2311206B1E8373A6008A94C3 /* sqlcipher framework */ = { - isa = PBXGroup; - children = ( - 2311206C1E8373A6008A94C3 /* Info.plist */, - 2311206D1E8373A6008A94C3 /* sqcliphertest.h */, - ); - path = "sqlcipher framework"; - sourceTree = ""; - }; 23121ADB1E6FF9110012B45E = { isa = PBXGroup; children = ( - 2311206B1E8373A6008A94C3 /* sqlcipher framework */, + 239D64E41ECE9FE8008F5B61 /* macosx */, 23121B7C1E6FF93D0012B45E /* src */, 23121C061E6FFA890012B45E /* Frameworks */, 23121AE51E6FF9110012B45E /* Products */, @@ -461,6 +451,14 @@ name = Frameworks; sourceTree = ""; }; + 239D64E41ECE9FE8008F5B61 /* macosx */ = { + isa = PBXGroup; + children = ( + 239D64E61ECE9FE8008F5B61 /* Info.plist */, + ); + path = macosx; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -495,9 +493,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 239325C71E836A7700D677CC /* sqlcipher framework */ = { + 239325C71E836A7700D677CC /* sqlcipher */ = { isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; buildPhases = ( 239325C31E836A7700D677CC /* Sources */, 239325C41E836A7700D677CC /* Frameworks */, @@ -509,7 +507,7 @@ dependencies = ( 239325D11E836A9000D677CC /* PBXTargetDependency */, ); - name = "sqlcipher framework"; + name = sqlcipher; productName = sqlcipher; productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; @@ -545,7 +543,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 239325C71E836A7700D677CC /* sqlcipher framework */, + 239325C71E836A7700D677CC /* sqlcipher */, 2395299B1E702CF90054D75E /* preprocess */, ); }; @@ -717,7 +715,6 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; @@ -764,12 +761,9 @@ SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; @@ -816,7 +810,6 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; @@ -860,12 +853,9 @@ SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; @@ -890,10 +880,11 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = "sqlcipher framework/Info.plist"; + INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; + MODULEMAP_FILE = macosx/module.modulemap; PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; @@ -913,10 +904,11 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "sqlcipher framework/Info.plist"; + INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; + MODULEMAP_FILE = macosx/module.modulemap; PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; @@ -964,7 +956,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher framework" */ = { + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { isa = XCConfigurationList; buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, From e1e056fd46ecd9d9ff0192ee85b61ac5fcbbaeec Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 19 May 2017 17:03:46 +0800 Subject: [PATCH 51/94] [iOS]update bundle id --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 3763b138c7..c6097f03e4 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -885,7 +885,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; + PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -909,7 +909,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; + PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; From 67ff7c94a87aa600a9220ac8354eb44dc889eb96 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 19 May 2017 17:05:10 +0800 Subject: [PATCH 52/94] [iOS]update bundle id --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 3763b138c7..c6097f03e4 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -885,7 +885,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; + PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -909,7 +909,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; - PRODUCT_BUNDLE_IDENTIFIER = com.sanhuazhang.sqlcipher; + PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; From cac4fa33d3c183f549e92861f125a759311a1ccb Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 23 May 2017 17:41:06 +0800 Subject: [PATCH 53/94] Fix compilation error when SQLITE_CRYPTO_CUSTOM is not defined. --- src/crypto_impl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 5d6eb4a80a..71b70b9cc9 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -125,13 +125,13 @@ void sqlcipher_activate() { sqlcipher_custom_setup(p); #elif defined (SQLCIPHER_CRYPTO_CC) extern int sqlcipher_cc_setup(sqlcipher_provider *p); - sqlcipher_cc_setup(fallback_provider); + sqlcipher_cc_setup(p); #elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) extern int sqlcipher_ltc_setup(sqlcipher_provider *p); - sqlcipher_ltc_setup(fallback_provider); + sqlcipher_ltc_setup(p); #elif defined (SQLCIPHER_CRYPTO_OPENSSL) extern int sqlcipher_openssl_setup(sqlcipher_provider *p); - sqlcipher_openssl_setup(fallback_provider); + sqlcipher_openssl_setup(p); #else #error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED" #endif From 659d27e91a4f47f3d539cc58c7e3da696eb472cb Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 25 May 2017 15:17:17 +0800 Subject: [PATCH 54/94] avoid clean error --- Makefile.preprocessed | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile.preprocessed b/Makefile.preprocessed index 1aa603fb06..bba9d7dbb1 100644 --- a/Makefile.preprocessed +++ b/Makefile.preprocessed @@ -17,5 +17,8 @@ Makefile: configure ./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" --disable-amalgamation make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c clean: - make clean - rm Makefile \ No newline at end of file + if [ -f Makefile ] ; \ + then \ + make clean;\ + rm Makefile;\ + fi; \ No newline at end of file From 9495b084e960a0128161746529278d35d03b2233 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 25 May 2017 16:31:17 +0800 Subject: [PATCH 55/94] define SQLITE_ENABLE_COLUMN_METADATA --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index c6097f03e4..fb5e01494e 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -753,10 +753,10 @@ "SQLITE_MALLOC_SOFT_LIMIT=0", "SQLITE_WCDB_SIGNAL_RETRY=1", "SQLITE_DEFAULT_MEMSTATUS=0", + SQLITE_ENABLE_COLUMN_METADATA, "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", SQLITE_LIKE_DOESNT_MATCH_BLOBS, "SQLITE_MAX_EXPR_DEPTH=0", - SQLITE_OMIT_DECLTYPE, SQLITE_OMIT_DEPRECATED, SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, @@ -848,10 +848,10 @@ "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", SQLITE_LIKE_DOESNT_MATCH_BLOBS, "SQLITE_MAX_EXPR_DEPTH=0", - SQLITE_OMIT_DECLTYPE, SQLITE_OMIT_DEPRECATED, SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, + SQLITE_ENABLE_COLUMN_METADATA, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; From 562ff1e483ea3c98532d97ee459c18f07f39e188 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 25 May 2017 17:22:24 +0800 Subject: [PATCH 56/94] remove arch armv7s and i386 --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index fb5e01494e..8022013ff6 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -685,19 +685,16 @@ ALWAYS_SEARCH_USER_PATHS = NO; "ARCHS[sdk=iphoneos*]" = ( "$(ARCHS_STANDARD)", - armv7s, arm64, armv7, ); "ARCHS[sdk=iphonesimulator*]" = ( "$(ARCHS_STANDARD)", - armv7s, armv7, arm64, ); "ARCHS[sdk=macosx*]" = ( "$(ARCHS_STANDARD)", - i386, x86_64, ); CLANG_ANALYZER_NONNULL = YES; @@ -770,7 +767,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; - VALID_ARCHS = "i386 x86_64 armv7s armv7 arm64"; + VALID_ARCHS = "x86_64 armv7 arm64"; }; name = Debug; }; @@ -780,19 +777,16 @@ ALWAYS_SEARCH_USER_PATHS = NO; "ARCHS[sdk=iphoneos*]" = ( "$(ARCHS_STANDARD)", - armv7s, armv7, arm64, ); "ARCHS[sdk=iphonesimulator*]" = ( "$(ARCHS_STANDARD)", - armv7s, armv7, arm64, ); "ARCHS[sdk=macosx*]" = ( "$(ARCHS_STANDARD)", - i386, i86_64, ); CLANG_ANALYZER_NONNULL = YES; @@ -861,7 +855,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; - VALID_ARCHS = "i386 x86_64 armv7s armv7 arm64"; + VALID_ARCHS = "x86_64 armv7 arm64"; }; name = Release; }; From 2343222671861ea6a4192e193452add7c591b0c3 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 25 May 2017 17:50:23 +0800 Subject: [PATCH 57/94] mute unnecessary warning --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ src/os_unix.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 8022013ff6..62e1922c9c 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -879,6 +879,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; @@ -903,6 +904,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; diff --git a/src/os_unix.c b/src/os_unix.c index 98fba3bb8d..83580a5200 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -117,7 +117,7 @@ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0)) # define HAVE_GETHOSTUUID 1 # else -# warning "gethostuuid() is disabled." +//# warning "gethostuuid() is disabled." # endif #endif From 68312506962a2eba03fd6b834e17439c21446664 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 26 May 2017 15:16:04 +0800 Subject: [PATCH 58/94] set deployment target to 8.0 --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 62e1922c9c..32bbb217b8 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -685,8 +685,8 @@ ALWAYS_SEARCH_USER_PATHS = NO; "ARCHS[sdk=iphoneos*]" = ( "$(ARCHS_STANDARD)", - arm64, armv7, + arm64, ); "ARCHS[sdk=iphonesimulator*]" = ( "$(ARCHS_STANDARD)", @@ -761,7 +761,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -787,7 +787,7 @@ ); "ARCHS[sdk=macosx*]" = ( "$(ARCHS_STANDARD)", - i86_64, + x86_64, ); CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -850,7 +850,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; @@ -870,10 +870,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; From cf21a928b1d5567d5d974ce28207fd24297a5904 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Fri, 26 May 2017 15:40:03 +0800 Subject: [PATCH 59/94] Add an optional argument to sqlcipher_export() function to specify source database for exporting data. --- src/crypto.c | 49 +++++++++++++++++++++++++------------------------ src/func.c | 1 + 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index a25b6cc859..e36da1423c 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -632,7 +632,8 @@ static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql) */ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **argv) { sqlite3 *db = sqlite3_context_db_handle(context); - const char* attachedDb = (const char*) sqlite3_value_text(argv[0]); + const char* toDb = (const char*) sqlite3_value_text(argv[0]); + const char* fromDb = (argc > 1) ? (const char *) sqlite3_value_text(argv[1]) : "main"; int saved_flags; /* Saved value of the db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ @@ -653,26 +654,26 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar ** in the temporary database. */ zSql = sqlite3_mprintf( - "SELECT 'CREATE TABLE %s.' || substr(sql,14) " - " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" + "SELECT 'CREATE TABLE %1$s.' || substr(sql,14) " + " FROM %2$s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'" " AND rootpage>0" - , attachedDb); + , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); zSql = sqlite3_mprintf( - "SELECT 'CREATE INDEX %s.' || substr(sql,14)" - " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%' " - , attachedDb); + "SELECT 'CREATE INDEX %1$s.' || substr(sql,14)" + " FROM %2$s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' " + , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); zSql = sqlite3_mprintf( - "SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) " - " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'" - , attachedDb); + "SELECT 'CREATE UNIQUE INDEX %1$s.' || substr(sql,21) " + " FROM %2$s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'" + , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); @@ -682,12 +683,12 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar ** the contents to the temporary database. */ zSql = sqlite3_mprintf( - "SELECT 'INSERT INTO %s.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) || ';'" - "FROM main.sqlite_master " + "SELECT 'INSERT INTO %1$s.' || quote(name) " + "|| ' SELECT * FROM %2$s.' || quote(name) || ';'" + "FROM %2$s.sqlite_master " "WHERE type = 'table' AND name!='sqlite_sequence' " " AND rootpage>0" - , attachedDb); + , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); @@ -695,18 +696,18 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar /* Copy over the sequence table */ zSql = sqlite3_mprintf( - "SELECT 'DELETE FROM %s.' || quote(name) || ';' " - "FROM %s.sqlite_master WHERE name='sqlite_sequence' " - , attachedDb, attachedDb); + "SELECT 'DELETE FROM %1$s.' || quote(name) || ';' " + "FROM %1$s.sqlite_master WHERE name='sqlite_sequence' " + , toDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); zSql = sqlite3_mprintf( - "SELECT 'INSERT INTO %s.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) || ';' " - "FROM %s.sqlite_master WHERE name=='sqlite_sequence';" - , attachedDb, attachedDb); + "SELECT 'INSERT INTO %1$s.' || quote(name) " + "|| ' SELECT * FROM %2$s.' || quote(name) || ';' " + "FROM %1$s.sqlite_master WHERE name=='sqlite_sequence';" + , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); @@ -717,12 +718,12 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar ** from the SQLITE_MASTER table. */ zSql = sqlite3_mprintf( - "INSERT INTO %s.sqlite_master " + "INSERT INTO %1$s.sqlite_master " " SELECT type, name, tbl_name, rootpage, sql" - " FROM main.sqlite_master" + " FROM %2$s.sqlite_master" " WHERE type='view' OR type='trigger'" " OR (type='table' AND rootpage=0)" - , attachedDb); + , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); diff --git a/src/func.c b/src/func.c index 5397d3f2a8..4d00ad4bb0 100644 --- a/src/func.c +++ b/src/func.c @@ -1658,6 +1658,7 @@ void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ #ifdef SQLITE_HAS_CODEC #ifndef OMIT_EXPORT sqlite3CreateFunc(db, "sqlcipher_export", 1, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0); + sqlite3CreateFunc(db, "sqlcipher_export", 2, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0); #endif #endif /* END SQLCIPHER */ From 5368fd21c0055e5f98c40c9779c22ed1516a414b Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 26 May 2017 16:53:44 +0800 Subject: [PATCH 60/94] avoid archive error --- Makefile.preprocessed | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.preprocessed b/Makefile.preprocessed index bba9d7dbb1..cf6e1c9c03 100644 --- a/Makefile.preprocessed +++ b/Makefile.preprocessed @@ -11,6 +11,7 @@ parse.h \ parse.c all: $(SRC) +install: $(SRC) $(SRC): Makefile make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c Makefile: configure From ac299a64a1889b5ec5f646c63feb30263d22e50a Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 29 May 2017 22:56:44 +0800 Subject: [PATCH 61/94] Link CoreFoundation, Security framework. Add OMIT_CONSTTIME_MEM macro. Remove unused file. --- .../project.pbxproj | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 32bbb217b8..cef41a00d5 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */; }; 234E922C1EAEFF8D00C5428D /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E922A1EAEFF8D00C5428D /* queue.c */; }; 234E922D1EAEFF8D00C5428D /* queue.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E922B1EAEFF8D00C5428D /* queue.h */; }; + 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */; }; + 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; 239325D31E836A9C00D677CC /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; 239325D41E836A9C00D677CC /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; @@ -99,11 +101,9 @@ 239326251E836A9C00D677CC /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529741E700F870054D75E /* random.c */; }; 239326261E836A9C00D677CC /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529761E700F940054D75E /* utf.c */; }; 239326271E836A9C00D677CC /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529771E700F940054D75E /* util.c */; }; - 239326281E836A9C00D677CC /* crypto_custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297A1E700FA60054D75E /* crypto_custom.c */; }; 239326291E836A9C00D677CC /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297C1E700FC60054D75E /* crypto_cc.c */; }; 2393262A1E836A9C00D677CC /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297D1E700FC60054D75E /* crypto_impl.c */; }; 2393262B1E836A9C00D677CC /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */; }; - 2393262C1E836A9C00D677CC /* crypto_openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297F1E700FC60054D75E /* crypto_openssl.c */; }; 2393262D1E836A9C00D677CC /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529801E700FC60054D75E /* crypto.c */; }; 2393262E1E836A9C00D677CC /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298A1E7010030054D75E /* vdbe.c */; }; 2393262F1E836A9C00D677CC /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298C1E7010030054D75E /* vdbeaux.c */; }; @@ -132,6 +132,10 @@ 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex_wcdb.h; path = src/mutex_wcdb.h; sourceTree = SOURCE_ROOT; }; 234E922A1EAEFF8D00C5428D /* queue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = queue.c; path = src/queue.c; sourceTree = SOURCE_ROOT; }; 234E922B1EAEFF8D00C5428D /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = queue.h; path = src/queue.h; sourceTree = SOURCE_ROOT; }; + 2384AB4A1EDBFD43007369FF /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 2384AB4F1EDBFDEC007369FF /* libcommonCrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcommonCrypto.tbd; path = usr/lib/system/libcommonCrypto.tbd; sourceTree = SDKROOT; }; + 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = usr/lib/system/libcorecrypto.tbd; sourceTree = SDKROOT; }; 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; @@ -249,11 +253,9 @@ 239529741E700F870054D75E /* random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = random.c; path = src/random.c; sourceTree = SOURCE_ROOT; }; 239529761E700F940054D75E /* utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf.c; path = src/utf.c; sourceTree = SOURCE_ROOT; }; 239529771E700F940054D75E /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = src/util.c; sourceTree = SOURCE_ROOT; }; - 2395297A1E700FA60054D75E /* crypto_custom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_custom.c; path = src/crypto_custom.c; sourceTree = SOURCE_ROOT; }; 2395297C1E700FC60054D75E /* crypto_cc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_cc.c; path = src/crypto_cc.c; sourceTree = SOURCE_ROOT; }; 2395297D1E700FC60054D75E /* crypto_impl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_impl.c; path = src/crypto_impl.c; sourceTree = SOURCE_ROOT; }; 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_libtomcrypt.c; path = src/crypto_libtomcrypt.c; sourceTree = SOURCE_ROOT; }; - 2395297F1E700FC60054D75E /* crypto_openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_openssl.c; path = src/crypto_openssl.c; sourceTree = SOURCE_ROOT; }; 239529801E700FC60054D75E /* crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto.c; path = src/crypto.c; sourceTree = SOURCE_ROOT; }; 239529811E700FC60054D75E /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = src/crypto.h; sourceTree = SOURCE_ROOT; }; 239529881E700FD90054D75E /* sqlcipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlcipher.h; path = src/sqlcipher.h; sourceTree = SOURCE_ROOT; }; @@ -273,6 +275,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */, + 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -423,11 +427,9 @@ 239529741E700F870054D75E /* random.c */, 239529761E700F940054D75E /* utf.c */, 239529771E700F940054D75E /* util.c */, - 2395297A1E700FA60054D75E /* crypto_custom.c */, 2395297C1E700FC60054D75E /* crypto_cc.c */, 2395297D1E700FC60054D75E /* crypto_impl.c */, 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */, - 2395297F1E700FC60054D75E /* crypto_openssl.c */, 239529801E700FC60054D75E /* crypto.c */, 239529811E700FC60054D75E /* crypto.h */, 2395298A1E7010030054D75E /* vdbe.c */, @@ -446,6 +448,10 @@ 23121C061E6FFA890012B45E /* Frameworks */ = { isa = PBXGroup; children = ( + 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */, + 2384AB4F1EDBFDEC007369FF /* libcommonCrypto.tbd */, + 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */, + 2384AB4A1EDBFD43007369FF /* libz.tbd */, 23121C071E6FFA890012B45E /* Security.framework */, ); name = Frameworks; @@ -653,11 +659,9 @@ 239326251E836A9C00D677CC /* random.c in Sources */, 239326261E836A9C00D677CC /* utf.c in Sources */, 239326271E836A9C00D677CC /* util.c in Sources */, - 239326281E836A9C00D677CC /* crypto_custom.c in Sources */, 239326291E836A9C00D677CC /* crypto_cc.c in Sources */, 2393262A1E836A9C00D677CC /* crypto_impl.c in Sources */, 2393262B1E836A9C00D677CC /* crypto_libtomcrypt.c in Sources */, - 2393262C1E836A9C00D677CC /* crypto_openssl.c in Sources */, 2393262D1E836A9C00D677CC /* crypto.c in Sources */, 2393262E1E836A9C00D677CC /* vdbe.c in Sources */, 2393262F1E836A9C00D677CC /* vdbeaux.c in Sources */, @@ -757,6 +761,7 @@ SQLITE_OMIT_DEPRECATED, SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, + OMIT_CONSTTIME_MEM, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -846,6 +851,7 @@ SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, SQLITE_ENABLE_COLUMN_METADATA, + OMIT_CONSTTIME_MEM, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -873,6 +879,10 @@ INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/usr/lib/system", + ); MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; @@ -898,6 +908,10 @@ INFOPLIST_FILE = macosx/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/usr/lib/system", + ); MACH_O_TYPE = staticlib; MODULEMAP_FILE = macosx/module.modulemap; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; From b7976651de1bad53f40f300755648a60496252c0 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 30 May 2017 17:08:47 +0800 Subject: [PATCH 62/94] Fix non-constant-time sqlcipher_memset() --- src/crypto_impl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 71b70b9cc9..bd19250510 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -181,12 +181,12 @@ void* sqlcipher_memset(void *v, unsigned char value, int len) { int len2 = len % sizeof(unsigned long); len = len / sizeof(unsigned long); - unsigned long *aa = (unsigned long *) v; + volatile unsigned long *aa = (unsigned long *) v; for (i = 0; i < len; i++) { *aa++ = val; } - unsigned char *a = (unsigned char *) aa; - for (i = 0; i < len; i++) { + volatile unsigned char *a = (unsigned char *) aa; + for (i = 0; i < len2; i++) { *a++ = value; } From 4285ad8785fbea536df07758bcc64437bf4f9e09 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 31 May 2017 16:51:58 +0800 Subject: [PATCH 63/94] OMIT_MEMLOCK --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index cef41a00d5..4ec6a4ec6f 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -762,6 +762,7 @@ SQLITE_OMIT_PROGRESS_CALLBACK, SQLITE_OMIT_SHARED_CACHE, OMIT_CONSTTIME_MEM, + OMIT_MEMLOCK, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -852,6 +853,7 @@ SQLITE_OMIT_SHARED_CACHE, SQLITE_ENABLE_COLUMN_METADATA, OMIT_CONSTTIME_MEM, + OMIT_MEMLOCK, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; From a374293b985e4e170d2f4690e54787b59c3a390c Mon Sep 17 00:00:00 2001 From: johnwhe Date: Wed, 7 Jun 2017 17:49:04 +0800 Subject: [PATCH 64/94] Do not use positional printf on sqlcipher_export() --- src/crypto.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index e36da1423c..54efc8897e 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -654,8 +654,8 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar ** in the temporary database. */ zSql = sqlite3_mprintf( - "SELECT 'CREATE TABLE %1$s.' || substr(sql,14) " - " FROM %2$s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'" + "SELECT 'CREATE TABLE %s.' || substr(sql,14) " + " FROM %s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'" " AND rootpage>0" , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); @@ -663,16 +663,16 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar sqlite3_free(zSql); zSql = sqlite3_mprintf( - "SELECT 'CREATE INDEX %1$s.' || substr(sql,14)" - " FROM %2$s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' " + "SELECT 'CREATE INDEX %s.' || substr(sql,14)" + " FROM %s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' " , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); zSql = sqlite3_mprintf( - "SELECT 'CREATE UNIQUE INDEX %1$s.' || substr(sql,21) " - " FROM %2$s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'" + "SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) " + " FROM %s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'" , toDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; @@ -683,12 +683,12 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar ** the contents to the temporary database. */ zSql = sqlite3_mprintf( - "SELECT 'INSERT INTO %1$s.' || quote(name) " - "|| ' SELECT * FROM %2$s.' || quote(name) || ';'" - "FROM %2$s.sqlite_master " + "SELECT 'INSERT INTO %s.' || quote(name) " + "|| ' SELECT * FROM %s.' || quote(name) || ';'" + "FROM %s.sqlite_master " "WHERE type = 'table' AND name!='sqlite_sequence' " " AND rootpage>0" - , toDb, fromDb); + , toDb, fromDb, fromDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); @@ -696,18 +696,18 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar /* Copy over the sequence table */ zSql = sqlite3_mprintf( - "SELECT 'DELETE FROM %1$s.' || quote(name) || ';' " - "FROM %1$s.sqlite_master WHERE name='sqlite_sequence' " - , toDb); + "SELECT 'DELETE FROM %s.' || quote(name) || ';' " + "FROM %s.sqlite_master WHERE name='sqlite_sequence' " + , toDb, toDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); zSql = sqlite3_mprintf( - "SELECT 'INSERT INTO %1$s.' || quote(name) " - "|| ' SELECT * FROM %2$s.' || quote(name) || ';' " - "FROM %1$s.sqlite_master WHERE name=='sqlite_sequence';" - , toDb, fromDb); + "SELECT 'INSERT INTO %s.' || quote(name) " + "|| ' SELECT * FROM %s.' || quote(name) || ';' " + "FROM %s.sqlite_master WHERE name=='sqlite_sequence';" + , toDb, fromDb, toDb); rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); if( rc!=SQLITE_OK ) goto end_of_export; sqlite3_free(zSql); @@ -718,9 +718,9 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar ** from the SQLITE_MASTER table. */ zSql = sqlite3_mprintf( - "INSERT INTO %1$s.sqlite_master " + "INSERT INTO %s.sqlite_master " " SELECT type, name, tbl_name, rootpage, sql" - " FROM %2$s.sqlite_master" + " FROM %s.sqlite_master" " WHERE type='view' OR type='trigger'" " OR (type='table' AND rootpage=0)" , toDb, fromDb); From 2a224dc36f4fefae9169a299f3624d20fb126f94 Mon Sep 17 00:00:00 2001 From: johnwhe Date: Tue, 13 Jun 2017 15:35:04 +0800 Subject: [PATCH 65/94] DevLock: fix /proc/cpuinfo parsing. --- ext/crypto/devlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/crypto/devlock.c b/ext/crypto/devlock.c index 6a0541c633..04a1a7a40b 100644 --- a/ext/crypto/devlock.c +++ b/ext/crypto/devlock.c @@ -52,7 +52,7 @@ static int read_cpu_serial(char *buf, int buf_len) { if (c != ' ' && c != '\t') break; } - while ((c = *++pch) != 0) { + while ((c = *pch++) != 0) { if (c == '\r' || c == '\n') break; if (ret >= buf_len) break; buf[ret++] = c; From 226408d01f5489919a1d9ea3728bf61f7afa581d Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 19 Jun 2017 10:46:35 +0800 Subject: [PATCH 66/94] Deploy to iOS 7 and macOS 10.9 --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 4ec6a4ec6f..e9193d5f37 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -767,8 +767,8 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -858,8 +858,8 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; From 35ddb1621de746b933c5d5a9fbced9d83965a63c Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 28 Jun 2017 11:20:19 +0800 Subject: [PATCH 67/94] Update cache size to 2000 bytes --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index e9193d5f37..1a809b591b 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -741,8 +741,7 @@ SQLITE_OMIT_LOAD_EXTENSION, SQLITE_CORE, "SQLITE_THREADSAFE=2", - "SQLITE_DEFAULT_CACHE_SIZE=250", - "SQLITE_DEFAULT_CKPTFULLFSYNC=1", + "SQLITE_DEFAULT_CACHE_SIZE=-2000", "SQLITE_DEFAULT_PAGE_SIZE=4096", SQLITE_OMIT_SHARED_CACHE, SQLITE_HAS_CODEC, @@ -833,8 +832,7 @@ SQLITE_SYSTEM_MALLOC, "SQLITE_THREADSAFE=2", "SQLITE_DEFAULT_PAGE_SIZE=4096", - "SQLITE_DEFAULT_CKPTFULLFSYNC=1", - "SQLITE_DEFAULT_CACHE_SIZE=250", + "SQLITE_DEFAULT_CACHE_SIZE=-2000", SQLITE_CORE, SQLITE_HAS_CODEC, "SQLITE_TEMP_STORE=2", From 7aeafc43019f3203c7846eee5a7a00316c0527c4 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 19 Jul 2017 10:24:58 +0800 Subject: [PATCH 68/94] Do not strip installed product --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 1a809b591b..a25ecb52bc 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -771,6 +771,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; VALID_ARCHS = "x86_64 armv7 arm64"; }; @@ -860,6 +861,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; VALID_ARCHS = "x86_64 armv7 arm64"; }; From e8a8011854a1a6a04e9bceecc0ebf91a6f616968 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 19 Sep 2017 11:01:33 +0800 Subject: [PATCH 69/94] Upgrade check --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index a25ecb52bc..235814b4af 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -524,7 +524,7 @@ 23121ADC1E6FF9110012B45E /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0830; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = sanhuazhang; TargetAttributes = { 239325C71E836A7700D677CC = { From bfff58e32b6668d7f2710d7acd01de20f449b73e Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 19 Sep 2017 11:07:07 +0800 Subject: [PATCH 70/94] Enable FTS3 tokenizer by default --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index 235814b4af..c305dd03bf 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -762,6 +762,7 @@ SQLITE_OMIT_SHARED_CACHE, OMIT_CONSTTIME_MEM, OMIT_MEMLOCK, + SQLITE_ENABLE_FTS3_TOKENIZER, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -853,6 +854,7 @@ SQLITE_ENABLE_COLUMN_METADATA, OMIT_CONSTTIME_MEM, OMIT_MEMLOCK, + SQLITE_ENABLE_FTS3_TOKENIZER, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; From d4726337010f60408a9c99633b35f01a8a7ae2de Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 22 Sep 2017 11:48:15 +0800 Subject: [PATCH 71/94] Make fts3_tokenizer public --- sqlcipher-preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj index c305dd03bf..a8a39c10b4 100644 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher-preprocessed.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */; }; 234E922C1EAEFF8D00C5428D /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E922A1EAEFF8D00C5428D /* queue.c */; }; 234E922D1EAEFF8D00C5428D /* queue.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E922B1EAEFF8D00C5428D /* queue.h */; }; + 23577F5F1F74BF6700D31C05 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528B51E700CB60054D75E /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */; }; 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; @@ -472,6 +473,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 23577F5F1F74BF6700D31C05 /* fts3_tokenizer.h in Headers */, 234E92251EAEF58100C5428D /* os_wcdb.h in Headers */, 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */, 234E922D1EAEFF8D00C5428D /* queue.h in Headers */, From 2940a9c279c3cbdb7f1ca6b883a22da88786a942 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 8 Jan 2018 20:12:49 +0800 Subject: [PATCH 72/94] Remove preprocessed project --- .../project.pbxproj | 992 ------------------ 1 file changed, 992 deletions(-) delete mode 100644 sqlcipher-preprocessed.xcodeproj/project.pbxproj diff --git a/sqlcipher-preprocessed.xcodeproj/project.pbxproj b/sqlcipher-preprocessed.xcodeproj/project.pbxproj deleted file mode 100644 index a8a39c10b4..0000000000 --- a/sqlcipher-preprocessed.xcodeproj/project.pbxproj +++ /dev/null @@ -1,992 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 234E92241EAEF58100C5428D /* os_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E92221EAEF58100C5428D /* os_wcdb.c */; }; - 234E92251EAEF58100C5428D /* os_wcdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E92231EAEF58100C5428D /* os_wcdb.h */; }; - 234E92281EAEFD3B00C5428D /* mutex_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E92261EAEFD3B00C5428D /* mutex_wcdb.c */; }; - 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */; }; - 234E922C1EAEFF8D00C5428D /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 234E922A1EAEFF8D00C5428D /* queue.c */; }; - 234E922D1EAEFF8D00C5428D /* queue.h in Headers */ = {isa = PBXBuildFile; fileRef = 234E922B1EAEFF8D00C5428D /* queue.h */; }; - 23577F5F1F74BF6700D31C05 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 239528B51E700CB60054D75E /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */; }; - 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; - 239325D21E836A9C00D677CC /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528941E700BCB0054D75E /* callback.c */; }; - 239325D31E836A9C00D677CC /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528961E700BEB0054D75E /* loadext.c */; }; - 239325D41E836A9C00D677CC /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528981E700BFE0054D75E /* rowset.c */; }; - 239325D51E836A9C00D677CC /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289A1E700C100054D75E /* treeview.c */; }; - 239325D61E836A9C00D677CC /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289C1E700C1B0054D75E /* userauth.c */; }; - 239325D71E836A9C00D677CC /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395289E1E700C250054D75E /* vtab.c */; }; - 239325D81E836A9C00D677CC /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A01E700C370054D75E /* btmutex.c */; }; - 239325D91E836A9C00D677CC /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A21E700C4A0054D75E /* btree.c */; }; - 239325DA1E836A9C00D677CC /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528A81E700C820054D75E /* fts5.c */; }; - 239325DB1E836A9C00D677CC /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AC1E700CB60054D75E /* fts3_aux.c */; }; - 239325DC1E836A9C00D677CC /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AD1E700CB60054D75E /* fts3_expr.c */; }; - 239325DD1E836A9C00D677CC /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528AE1E700CB60054D75E /* fts3_hash.c */; }; - 239325DE1E836A9C00D677CC /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B01E700CB60054D75E /* fts3_icu.c */; }; - 239325DF1E836A9C00D677CC /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B11E700CB60054D75E /* fts3_porter.c */; }; - 239325E01E836A9C00D677CC /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B21E700CB60054D75E /* fts3_snippet.c */; }; - 239325E11E836A9C00D677CC /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */; }; - 239325E21E836A9C00D677CC /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B41E700CB60054D75E /* fts3_tokenizer.c */; }; - 239325E31E836A9C00D677CC /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B61E700CB60054D75E /* fts3_tokenizer1.c */; }; - 239325E41E836A9C00D677CC /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B71E700CB60054D75E /* fts3_unicode.c */; }; - 239325E51E836A9C00D677CC /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B81E700CB60054D75E /* fts3_unicode2.c */; }; - 239325E61E836A9C00D677CC /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528B91E700CB60054D75E /* fts3_write.c */; }; - 239325E71E836A9C00D677CC /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528BA1E700CB60054D75E /* fts3.c */; }; - 239325E81E836A9C00D677CC /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528CE1E700CC30054D75E /* backup.c */; }; - 239325E91E836A9C00D677CC /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D01E700CCD0054D75E /* legacy.c */; }; - 239325EA1E836A9C00D677CC /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D21E700CD70054D75E /* main.c */; }; - 239325EB1E836A9C00D677CC /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D41E700CE10054D75E /* notify.c */; }; - 239325EC1E836A9C00D677CC /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D61E700CED0054D75E /* vdbeapi.c */; }; - 239325ED1E836A9C00D677CC /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528D81E700CFB0054D75E /* table.c */; }; - 239325EE1E836A9C00D677CC /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DA1E700D0A0054D75E /* wal.c */; }; - 239325EF1E836A9C00D677CC /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528DE1E700D170054D75E /* status.c */; }; - 239325F01E836A9C00D677CC /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E01E700D220054D75E /* prepare.c */; }; - 239325F11E836A9C00D677CC /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E21E700D320054D75E /* malloc.c */; }; - 239325F21E836A9C00D677CC /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E41E700D460054D75E /* mem0.c */; }; - 239325F31E836A9C00D677CC /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E51E700D460054D75E /* mem1.c */; }; - 239325F41E836A9C00D677CC /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E61E700D460054D75E /* mem2.c */; }; - 239325F51E836A9C00D677CC /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E71E700D460054D75E /* mem3.c */; }; - 239325F61E836A9C00D677CC /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528E81E700D460054D75E /* mem5.c */; }; - 239325F71E836A9C00D677CC /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528EE1E700D4A0054D75E /* memjournal.c */; }; - 239325F81E836A9C00D677CC /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F01E700D570054D75E /* mutex_unix.c */; }; - 239325F91E836A9C00D677CC /* mutex_noop.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F21E700D600054D75E /* mutex_noop.c */; }; - 239325FA1E836A9C00D677CC /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528F41E700D6C0054D75E /* mutex.c */; }; - 239325FB1E836A9C00D677CC /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FA1E700D790054D75E /* os_unix.c */; }; - 239325FC1E836A9C00D677CC /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 239528FE1E700D880054D75E /* os.c */; }; - 239325FD1E836A9C00D677CC /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529021E700D920054D75E /* threads.c */; }; - 239325FE1E836A9C00D677CC /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529041E700D9D0054D75E /* bitvec.c */; }; - 239325FF1E836A9C00D677CC /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529061E700DA70054D75E /* pager.c */; }; - 239326001E836A9C00D677CC /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290A1E700DB90054D75E /* pcache.c */; }; - 239326011E836A9C00D677CC /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395290C1E700DB90054D75E /* pcache1.c */; }; - 239326021E836A9C00D677CC /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529101E700DD10054D75E /* rtree.c */; }; - 239326031E836A9C00D677CC /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529161E700DDF0054D75E /* complete.c */; }; - 239326041E836A9C00D677CC /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529181E700DED0054D75E /* tokenize.c */; }; - 239326051E836A9C00D677CC /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291A1E700DFD0054D75E /* resolve.c */; }; - 239326061E836A9C00D677CC /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395291C1E700E080054D75E /* parse.c */; }; - 239326071E836A9C00D677CC /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529201E700E170054D75E /* analyze.c */; }; - 239326081E836A9C00D677CC /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529221E700E1E0054D75E /* func.c */; }; - 239326091E836A9C00D677CC /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529241E700E280054D75E /* wherecode.c */; }; - 2393260A1E836A9C00D677CC /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529261E700E2F0054D75E /* whereexpr.c */; }; - 2393260B1E836A9C00D677CC /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292A1E700E3C0054D75E /* alter.c */; }; - 2393260C1E836A9C00D677CC /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292C1E700E450054D75E /* attach.c */; }; - 2393260D1E836A9C00D677CC /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395292E1E700E4C0054D75E /* auth.c */; }; - 2393260E1E836A9C00D677CC /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529301E700E590054D75E /* build.c */; }; - 2393260F1E836A9C00D677CC /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529321E700E5F0054D75E /* delete.c */; }; - 239326101E836A9C00D677CC /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529341E700E660054D75E /* expr.c */; }; - 239326111E836A9C00D677CC /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529361E700E6D0054D75E /* insert.c */; }; - 239326121E836A9C00D677CC /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529381E700E780054D75E /* pragma.c */; }; - 239326131E836A9C00D677CC /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293C1E700E810054D75E /* select.c */; }; - 239326141E836A9C00D677CC /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395293E1E700E8A0054D75E /* trigger.c */; }; - 239326151E836A9C00D677CC /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529401E700E910054D75E /* update.c */; }; - 239326161E836A9C00D677CC /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529421E700E9C0054D75E /* vacuum.c */; }; - 239326171E836A9C00D677CC /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529441E700EA40054D75E /* walker.c */; }; - 239326181E836A9C00D677CC /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529461E700EAF0054D75E /* where.c */; }; - 239326191E836A9C00D677CC /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529481E700EBC0054D75E /* opcodes.c */; }; - 2393261A1E836A9C00D677CC /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395294D1E700EE70054D75E /* sqlite3rbu.c */; }; - 2393261B1E836A9C00D677CC /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529541E700EF00054D75E /* json1.c */; }; - 2393261C1E836A9C00D677CC /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529561E700EF90054D75E /* icu.c */; }; - 2393261D1E836A9C00D677CC /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295A1E700F0F0054D75E /* global.c */; }; - 2393261E1E836A9C00D677CC /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395295C1E700F170054D75E /* ctime.c */; }; - 2393261F1E836A9C00D677CC /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529601E700F2C0054D75E /* date.c */; }; - 239326201E836A9C00D677CC /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529621E700F360054D75E /* dbstat.c */; }; - 239326211E836A9C00D677CC /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529641E700F410054D75E /* fault.c */; }; - 239326221E836A9C00D677CC /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529661E700F490054D75E /* fkey.c */; }; - 239326231E836A9C00D677CC /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395296E1E700F760054D75E /* hash.c */; }; - 239326241E836A9C00D677CC /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529721E700F7F0054D75E /* printf.c */; }; - 239326251E836A9C00D677CC /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529741E700F870054D75E /* random.c */; }; - 239326261E836A9C00D677CC /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529761E700F940054D75E /* utf.c */; }; - 239326271E836A9C00D677CC /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529771E700F940054D75E /* util.c */; }; - 239326291E836A9C00D677CC /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297C1E700FC60054D75E /* crypto_cc.c */; }; - 2393262A1E836A9C00D677CC /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297D1E700FC60054D75E /* crypto_impl.c */; }; - 2393262B1E836A9C00D677CC /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */; }; - 2393262D1E836A9C00D677CC /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529801E700FC60054D75E /* crypto.c */; }; - 2393262E1E836A9C00D677CC /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298A1E7010030054D75E /* vdbe.c */; }; - 2393262F1E836A9C00D677CC /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298C1E7010030054D75E /* vdbeaux.c */; }; - 239326301E836A9C00D677CC /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298D1E7010030054D75E /* vdbeblob.c */; }; - 239326311E836A9C00D677CC /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 2395298F1E7010030054D75E /* vdbemem.c */; }; - 239326321E836A9C00D677CC /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529901E7010030054D75E /* vdbesort.c */; }; - 239326331E836A9C00D677CC /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 239529911E7010030054D75E /* vdbetrace.c */; }; - 239326341E836AAA00D677CC /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2395294C1E700EE70054D75E /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 239325D01E836A9000D677CC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 2395299B1E702CF90054D75E; - remoteInfo = preprocess; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; - 234E92221EAEF58100C5428D /* os_wcdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_wcdb.c; path = src/os_wcdb.c; sourceTree = SOURCE_ROOT; }; - 234E92231EAEF58100C5428D /* os_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_wcdb.h; path = src/os_wcdb.h; sourceTree = SOURCE_ROOT; }; - 234E92261EAEFD3B00C5428D /* mutex_wcdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_wcdb.c; path = src/mutex_wcdb.c; sourceTree = SOURCE_ROOT; }; - 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex_wcdb.h; path = src/mutex_wcdb.h; sourceTree = SOURCE_ROOT; }; - 234E922A1EAEFF8D00C5428D /* queue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = queue.c; path = src/queue.c; sourceTree = SOURCE_ROOT; }; - 234E922B1EAEFF8D00C5428D /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = queue.h; path = src/queue.h; sourceTree = SOURCE_ROOT; }; - 2384AB4A1EDBFD43007369FF /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; - 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; - 2384AB4F1EDBFDEC007369FF /* libcommonCrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcommonCrypto.tbd; path = usr/lib/system/libcommonCrypto.tbd; sourceTree = SDKROOT; }; - 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = usr/lib/system/libcorecrypto.tbd; sourceTree = SDKROOT; }; - 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 239528921E700BBC0054D75E /* keywordhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywordhash.h; sourceTree = SOURCE_ROOT; }; - 239528941E700BCB0054D75E /* callback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = callback.c; path = src/callback.c; sourceTree = SOURCE_ROOT; }; - 239528961E700BEB0054D75E /* loadext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loadext.c; path = src/loadext.c; sourceTree = SOURCE_ROOT; }; - 239528981E700BFE0054D75E /* rowset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rowset.c; path = src/rowset.c; sourceTree = SOURCE_ROOT; }; - 2395289A1E700C100054D75E /* treeview.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = treeview.c; path = src/treeview.c; sourceTree = SOURCE_ROOT; }; - 2395289C1E700C1B0054D75E /* userauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = userauth.c; path = ext/userauth/userauth.c; sourceTree = SOURCE_ROOT; }; - 2395289E1E700C250054D75E /* vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vtab.c; path = src/vtab.c; sourceTree = SOURCE_ROOT; }; - 239528A01E700C370054D75E /* btmutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btmutex.c; path = src/btmutex.c; sourceTree = SOURCE_ROOT; }; - 239528A21E700C4A0054D75E /* btree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = btree.c; path = src/btree.c; sourceTree = SOURCE_ROOT; }; - 239528A41E700C550054D75E /* btreeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btreeInt.h; path = src/btreeInt.h; sourceTree = SOURCE_ROOT; }; - 239528A61E700C670054D75E /* btree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = btree.h; path = src/btree.h; sourceTree = SOURCE_ROOT; }; - 239528A81E700C820054D75E /* fts5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fts5.c; sourceTree = SOURCE_ROOT; }; - 239528A91E700C820054D75E /* fts5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fts5.h; sourceTree = SOURCE_ROOT; }; - 239528AC1E700CB60054D75E /* fts3_aux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_aux.c; path = ext/fts3/fts3_aux.c; sourceTree = SOURCE_ROOT; }; - 239528AD1E700CB60054D75E /* fts3_expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_expr.c; path = ext/fts3/fts3_expr.c; sourceTree = SOURCE_ROOT; }; - 239528AE1E700CB60054D75E /* fts3_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_hash.c; path = ext/fts3/fts3_hash.c; sourceTree = SOURCE_ROOT; }; - 239528AF1E700CB60054D75E /* fts3_hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_hash.h; path = ext/fts3/fts3_hash.h; sourceTree = SOURCE_ROOT; }; - 239528B01E700CB60054D75E /* fts3_icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_icu.c; path = ext/fts3/fts3_icu.c; sourceTree = SOURCE_ROOT; }; - 239528B11E700CB60054D75E /* fts3_porter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_porter.c; path = ext/fts3/fts3_porter.c; sourceTree = SOURCE_ROOT; }; - 239528B21E700CB60054D75E /* fts3_snippet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_snippet.c; path = ext/fts3/fts3_snippet.c; sourceTree = SOURCE_ROOT; }; - 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenize_vtab.c; path = ext/fts3/fts3_tokenize_vtab.c; sourceTree = SOURCE_ROOT; }; - 239528B41E700CB60054D75E /* fts3_tokenizer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer.c; path = ext/fts3/fts3_tokenizer.c; sourceTree = SOURCE_ROOT; }; - 239528B51E700CB60054D75E /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ext/fts3/fts3_tokenizer.h; sourceTree = SOURCE_ROOT; }; - 239528B61E700CB60054D75E /* fts3_tokenizer1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer1.c; path = ext/fts3/fts3_tokenizer1.c; sourceTree = SOURCE_ROOT; }; - 239528B71E700CB60054D75E /* fts3_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode.c; path = ext/fts3/fts3_unicode.c; sourceTree = SOURCE_ROOT; }; - 239528B81E700CB60054D75E /* fts3_unicode2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_unicode2.c; path = ext/fts3/fts3_unicode2.c; sourceTree = SOURCE_ROOT; }; - 239528B91E700CB60054D75E /* fts3_write.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3_write.c; path = ext/fts3/fts3_write.c; sourceTree = SOURCE_ROOT; }; - 239528BA1E700CB60054D75E /* fts3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fts3.c; path = ext/fts3/fts3.c; sourceTree = SOURCE_ROOT; }; - 239528BB1E700CB60054D75E /* fts3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3.h; path = ext/fts3/fts3.h; sourceTree = SOURCE_ROOT; }; - 239528BC1E700CB60054D75E /* fts3Int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3Int.h; path = ext/fts3/fts3Int.h; sourceTree = SOURCE_ROOT; }; - 239528CE1E700CC30054D75E /* backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = backup.c; path = src/backup.c; sourceTree = SOURCE_ROOT; }; - 239528D01E700CCD0054D75E /* legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = legacy.c; path = src/legacy.c; sourceTree = SOURCE_ROOT; }; - 239528D21E700CD70054D75E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = SOURCE_ROOT; }; - 239528D41E700CE10054D75E /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = src/notify.c; sourceTree = SOURCE_ROOT; }; - 239528D61E700CED0054D75E /* vdbeapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeapi.c; path = src/vdbeapi.c; sourceTree = SOURCE_ROOT; }; - 239528D81E700CFB0054D75E /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = table.c; path = src/table.c; sourceTree = SOURCE_ROOT; }; - 239528DA1E700D0A0054D75E /* wal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wal.c; path = src/wal.c; sourceTree = SOURCE_ROOT; }; - 239528DB1E700D0A0054D75E /* wal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wal.h; path = src/wal.h; sourceTree = SOURCE_ROOT; }; - 239528DE1E700D170054D75E /* status.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = status.c; path = src/status.c; sourceTree = SOURCE_ROOT; }; - 239528E01E700D220054D75E /* prepare.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = prepare.c; path = src/prepare.c; sourceTree = SOURCE_ROOT; }; - 239528E21E700D320054D75E /* malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = malloc.c; path = src/malloc.c; sourceTree = SOURCE_ROOT; }; - 239528E41E700D460054D75E /* mem0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem0.c; path = src/mem0.c; sourceTree = SOURCE_ROOT; }; - 239528E51E700D460054D75E /* mem1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem1.c; path = src/mem1.c; sourceTree = SOURCE_ROOT; }; - 239528E61E700D460054D75E /* mem2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem2.c; path = src/mem2.c; sourceTree = SOURCE_ROOT; }; - 239528E71E700D460054D75E /* mem3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem3.c; path = src/mem3.c; sourceTree = SOURCE_ROOT; }; - 239528E81E700D460054D75E /* mem5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mem5.c; path = src/mem5.c; sourceTree = SOURCE_ROOT; }; - 239528EE1E700D4A0054D75E /* memjournal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memjournal.c; path = src/memjournal.c; sourceTree = SOURCE_ROOT; }; - 239528F01E700D570054D75E /* mutex_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_unix.c; path = src/mutex_unix.c; sourceTree = SOURCE_ROOT; }; - 239528F21E700D600054D75E /* mutex_noop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex_noop.c; path = src/mutex_noop.c; sourceTree = SOURCE_ROOT; }; - 239528F41E700D6C0054D75E /* mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mutex.c; path = src/mutex.c; sourceTree = SOURCE_ROOT; }; - 239528F51E700D6C0054D75E /* mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mutex.h; path = src/mutex.h; sourceTree = SOURCE_ROOT; }; - 239528F81E700D790054D75E /* os_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_common.h; path = src/os_common.h; sourceTree = SOURCE_ROOT; }; - 239528F91E700D790054D75E /* os_setup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os_setup.h; path = src/os_setup.h; sourceTree = SOURCE_ROOT; }; - 239528FA1E700D790054D75E /* os_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os_unix.c; path = src/os_unix.c; sourceTree = SOURCE_ROOT; }; - 239528FE1E700D880054D75E /* os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os.c; path = src/os.c; sourceTree = SOURCE_ROOT; }; - 239528FF1E700D880054D75E /* os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os.h; path = src/os.h; sourceTree = SOURCE_ROOT; }; - 239529021E700D920054D75E /* threads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threads.c; path = src/threads.c; sourceTree = SOURCE_ROOT; }; - 239529041E700D9D0054D75E /* bitvec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bitvec.c; path = src/bitvec.c; sourceTree = SOURCE_ROOT; }; - 239529061E700DA70054D75E /* pager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pager.c; path = src/pager.c; sourceTree = SOURCE_ROOT; }; - 239529071E700DA70054D75E /* pager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pager.h; path = src/pager.h; sourceTree = SOURCE_ROOT; }; - 2395290A1E700DB90054D75E /* pcache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache.c; path = src/pcache.c; sourceTree = SOURCE_ROOT; }; - 2395290B1E700DB90054D75E /* pcache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pcache.h; path = src/pcache.h; sourceTree = SOURCE_ROOT; }; - 2395290C1E700DB90054D75E /* pcache1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pcache1.c; path = src/pcache1.c; sourceTree = SOURCE_ROOT; }; - 239529101E700DD10054D75E /* rtree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rtree.c; path = ext/rtree/rtree.c; sourceTree = SOURCE_ROOT; }; - 239529111E700DD10054D75E /* rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rtree.h; path = ext/rtree/rtree.h; sourceTree = SOURCE_ROOT; }; - 239529121E700DD10054D75E /* sqlite3rtree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rtree.h; path = ext/rtree/sqlite3rtree.h; sourceTree = SOURCE_ROOT; }; - 239529161E700DDF0054D75E /* complete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = complete.c; path = src/complete.c; sourceTree = SOURCE_ROOT; }; - 239529181E700DED0054D75E /* tokenize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tokenize.c; path = src/tokenize.c; sourceTree = SOURCE_ROOT; }; - 2395291A1E700DFD0054D75E /* resolve.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = resolve.c; path = src/resolve.c; sourceTree = SOURCE_ROOT; }; - 2395291C1E700E080054D75E /* parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parse.c; sourceTree = SOURCE_ROOT; }; - 2395291D1E700E080054D75E /* parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parse.h; sourceTree = SOURCE_ROOT; }; - 239529201E700E170054D75E /* analyze.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = analyze.c; path = src/analyze.c; sourceTree = SOURCE_ROOT; }; - 239529221E700E1E0054D75E /* func.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = func.c; path = src/func.c; sourceTree = SOURCE_ROOT; }; - 239529241E700E280054D75E /* wherecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wherecode.c; path = src/wherecode.c; sourceTree = SOURCE_ROOT; }; - 239529261E700E2F0054D75E /* whereexpr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = whereexpr.c; path = src/whereexpr.c; sourceTree = SOURCE_ROOT; }; - 239529281E700E340054D75E /* whereInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = whereInt.h; path = src/whereInt.h; sourceTree = SOURCE_ROOT; }; - 2395292A1E700E3C0054D75E /* alter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alter.c; path = src/alter.c; sourceTree = SOURCE_ROOT; }; - 2395292C1E700E450054D75E /* attach.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = attach.c; path = src/attach.c; sourceTree = SOURCE_ROOT; }; - 2395292E1E700E4C0054D75E /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = src/auth.c; sourceTree = SOURCE_ROOT; }; - 239529301E700E590054D75E /* build.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = build.c; path = src/build.c; sourceTree = SOURCE_ROOT; }; - 239529321E700E5F0054D75E /* delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = delete.c; path = src/delete.c; sourceTree = SOURCE_ROOT; }; - 239529341E700E660054D75E /* expr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = expr.c; path = src/expr.c; sourceTree = SOURCE_ROOT; }; - 239529361E700E6D0054D75E /* insert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = insert.c; path = src/insert.c; sourceTree = SOURCE_ROOT; }; - 239529381E700E780054D75E /* pragma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pragma.c; path = src/pragma.c; sourceTree = SOURCE_ROOT; }; - 239529391E700E780054D75E /* pragma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pragma.h; path = src/pragma.h; sourceTree = SOURCE_ROOT; }; - 2395293C1E700E810054D75E /* select.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = select.c; path = src/select.c; sourceTree = SOURCE_ROOT; }; - 2395293E1E700E8A0054D75E /* trigger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trigger.c; path = src/trigger.c; sourceTree = SOURCE_ROOT; }; - 239529401E700E910054D75E /* update.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = update.c; path = src/update.c; sourceTree = SOURCE_ROOT; }; - 239529421E700E9C0054D75E /* vacuum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vacuum.c; path = src/vacuum.c; sourceTree = SOURCE_ROOT; }; - 239529441E700EA40054D75E /* walker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = walker.c; path = src/walker.c; sourceTree = SOURCE_ROOT; }; - 239529461E700EAF0054D75E /* where.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = where.c; path = src/where.c; sourceTree = SOURCE_ROOT; }; - 239529481E700EBC0054D75E /* opcodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opcodes.c; sourceTree = SOURCE_ROOT; }; - 239529491E700EBC0054D75E /* opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcodes.h; sourceTree = SOURCE_ROOT; }; - 2395294C1E700EE70054D75E /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = SOURCE_ROOT; }; - 2395294D1E700EE70054D75E /* sqlite3rbu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sqlite3rbu.c; path = ext/rbu/sqlite3rbu.c; sourceTree = SOURCE_ROOT; }; - 2395294E1E700EE70054D75E /* sqlite3rbu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3rbu.h; path = ext/rbu/sqlite3rbu.h; sourceTree = SOURCE_ROOT; }; - 2395294F1E700EE70054D75E /* sqlite3userauth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3userauth.h; path = ext/userauth/sqlite3userauth.h; sourceTree = SOURCE_ROOT; }; - 239529541E700EF00054D75E /* json1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = json1.c; path = ext/misc/json1.c; sourceTree = SOURCE_ROOT; }; - 239529561E700EF90054D75E /* icu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = icu.c; path = ext/icu/icu.c; sourceTree = SOURCE_ROOT; }; - 239529581E700F060054D75E /* sqliteicu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteicu.h; path = ext/icu/sqliteicu.h; sourceTree = SOURCE_ROOT; }; - 2395295A1E700F0F0054D75E /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = global.c; path = src/global.c; sourceTree = SOURCE_ROOT; }; - 2395295C1E700F170054D75E /* ctime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ctime.c; path = src/ctime.c; sourceTree = SOURCE_ROOT; }; - 2395295E1E700F200054D75E /* hwtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwtime.h; path = src/hwtime.h; sourceTree = SOURCE_ROOT; }; - 239529601E700F2C0054D75E /* date.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = date.c; path = src/date.c; sourceTree = SOURCE_ROOT; }; - 239529621E700F360054D75E /* dbstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dbstat.c; path = src/dbstat.c; sourceTree = SOURCE_ROOT; }; - 239529641E700F410054D75E /* fault.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fault.c; path = src/fault.c; sourceTree = SOURCE_ROOT; }; - 239529661E700F490054D75E /* fkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fkey.c; path = src/fkey.c; sourceTree = SOURCE_ROOT; }; - 239529681E700F570054D75E /* sqliteInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteInt.h; path = src/sqliteInt.h; sourceTree = SOURCE_ROOT; }; - 2395296A1E700F600054D75E /* sqliteLimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqliteLimit.h; path = src/sqliteLimit.h; sourceTree = SOURCE_ROOT; }; - 2395296C1E700F6C0054D75E /* sqlite3ext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlite3ext.h; path = src/sqlite3ext.h; sourceTree = SOURCE_ROOT; }; - 2395296E1E700F760054D75E /* hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hash.c; path = src/hash.c; sourceTree = SOURCE_ROOT; }; - 2395296F1E700F760054D75E /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hash.h; path = src/hash.h; sourceTree = SOURCE_ROOT; }; - 239529721E700F7F0054D75E /* printf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = printf.c; path = src/printf.c; sourceTree = SOURCE_ROOT; }; - 239529741E700F870054D75E /* random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = random.c; path = src/random.c; sourceTree = SOURCE_ROOT; }; - 239529761E700F940054D75E /* utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf.c; path = src/utf.c; sourceTree = SOURCE_ROOT; }; - 239529771E700F940054D75E /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = src/util.c; sourceTree = SOURCE_ROOT; }; - 2395297C1E700FC60054D75E /* crypto_cc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_cc.c; path = src/crypto_cc.c; sourceTree = SOURCE_ROOT; }; - 2395297D1E700FC60054D75E /* crypto_impl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_impl.c; path = src/crypto_impl.c; sourceTree = SOURCE_ROOT; }; - 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto_libtomcrypt.c; path = src/crypto_libtomcrypt.c; sourceTree = SOURCE_ROOT; }; - 239529801E700FC60054D75E /* crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crypto.c; path = src/crypto.c; sourceTree = SOURCE_ROOT; }; - 239529811E700FC60054D75E /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = src/crypto.h; sourceTree = SOURCE_ROOT; }; - 239529881E700FD90054D75E /* sqlcipher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sqlcipher.h; path = src/sqlcipher.h; sourceTree = SOURCE_ROOT; }; - 2395298A1E7010030054D75E /* vdbe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbe.c; path = src/vdbe.c; sourceTree = SOURCE_ROOT; }; - 2395298B1E7010030054D75E /* vdbe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbe.h; path = src/vdbe.h; sourceTree = SOURCE_ROOT; }; - 2395298C1E7010030054D75E /* vdbeaux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeaux.c; path = src/vdbeaux.c; sourceTree = SOURCE_ROOT; }; - 2395298D1E7010030054D75E /* vdbeblob.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbeblob.c; path = src/vdbeblob.c; sourceTree = SOURCE_ROOT; }; - 2395298E1E7010030054D75E /* vdbeInt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdbeInt.h; path = src/vdbeInt.h; sourceTree = SOURCE_ROOT; }; - 2395298F1E7010030054D75E /* vdbemem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbemem.c; path = src/vdbemem.c; sourceTree = SOURCE_ROOT; }; - 239529901E7010030054D75E /* vdbesort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbesort.c; path = src/vdbesort.c; sourceTree = SOURCE_ROOT; }; - 239529911E7010030054D75E /* vdbetrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdbetrace.c; path = src/vdbetrace.c; sourceTree = SOURCE_ROOT; }; - 239D64E61ECE9FE8008F5B61 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 239325C41E836A7700D677CC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */, - 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 23121ADB1E6FF9110012B45E = { - isa = PBXGroup; - children = ( - 239D64E41ECE9FE8008F5B61 /* macosx */, - 23121B7C1E6FF93D0012B45E /* src */, - 23121C061E6FFA890012B45E /* Frameworks */, - 23121AE51E6FF9110012B45E /* Products */, - ); - sourceTree = ""; - }; - 23121AE51E6FF9110012B45E /* Products */ = { - isa = PBXGroup; - children = ( - 239325C81E836A7700D677CC /* sqlcipher.framework */, - ); - name = Products; - sourceTree = ""; - }; - 23121B7C1E6FF93D0012B45E /* src */ = { - isa = PBXGroup; - children = ( - 239528921E700BBC0054D75E /* keywordhash.h */, - 239528941E700BCB0054D75E /* callback.c */, - 239528961E700BEB0054D75E /* loadext.c */, - 239528981E700BFE0054D75E /* rowset.c */, - 2395289A1E700C100054D75E /* treeview.c */, - 2395289C1E700C1B0054D75E /* userauth.c */, - 2395289E1E700C250054D75E /* vtab.c */, - 239528A01E700C370054D75E /* btmutex.c */, - 239528A21E700C4A0054D75E /* btree.c */, - 239528A41E700C550054D75E /* btreeInt.h */, - 239528A61E700C670054D75E /* btree.h */, - 239528A81E700C820054D75E /* fts5.c */, - 239528A91E700C820054D75E /* fts5.h */, - 239528AC1E700CB60054D75E /* fts3_aux.c */, - 239528AD1E700CB60054D75E /* fts3_expr.c */, - 239528AE1E700CB60054D75E /* fts3_hash.c */, - 239528AF1E700CB60054D75E /* fts3_hash.h */, - 239528B01E700CB60054D75E /* fts3_icu.c */, - 239528B11E700CB60054D75E /* fts3_porter.c */, - 239528B21E700CB60054D75E /* fts3_snippet.c */, - 239528B31E700CB60054D75E /* fts3_tokenize_vtab.c */, - 239528B41E700CB60054D75E /* fts3_tokenizer.c */, - 239528B51E700CB60054D75E /* fts3_tokenizer.h */, - 239528B61E700CB60054D75E /* fts3_tokenizer1.c */, - 239528B71E700CB60054D75E /* fts3_unicode.c */, - 239528B81E700CB60054D75E /* fts3_unicode2.c */, - 239528B91E700CB60054D75E /* fts3_write.c */, - 239528BA1E700CB60054D75E /* fts3.c */, - 239528BB1E700CB60054D75E /* fts3.h */, - 239528BC1E700CB60054D75E /* fts3Int.h */, - 239528CE1E700CC30054D75E /* backup.c */, - 239528D01E700CCD0054D75E /* legacy.c */, - 239528D21E700CD70054D75E /* main.c */, - 239528D41E700CE10054D75E /* notify.c */, - 239528D61E700CED0054D75E /* vdbeapi.c */, - 239528D81E700CFB0054D75E /* table.c */, - 239528DA1E700D0A0054D75E /* wal.c */, - 239528DB1E700D0A0054D75E /* wal.h */, - 239528DE1E700D170054D75E /* status.c */, - 239528E01E700D220054D75E /* prepare.c */, - 239528E21E700D320054D75E /* malloc.c */, - 239528E41E700D460054D75E /* mem0.c */, - 239528E51E700D460054D75E /* mem1.c */, - 239528E61E700D460054D75E /* mem2.c */, - 239528E71E700D460054D75E /* mem3.c */, - 239528E81E700D460054D75E /* mem5.c */, - 239528EE1E700D4A0054D75E /* memjournal.c */, - 239528F01E700D570054D75E /* mutex_unix.c */, - 239528F21E700D600054D75E /* mutex_noop.c */, - 239528F41E700D6C0054D75E /* mutex.c */, - 239528F51E700D6C0054D75E /* mutex.h */, - 239528F81E700D790054D75E /* os_common.h */, - 239528F91E700D790054D75E /* os_setup.h */, - 239528FA1E700D790054D75E /* os_unix.c */, - 234E922A1EAEFF8D00C5428D /* queue.c */, - 234E922B1EAEFF8D00C5428D /* queue.h */, - 234E92221EAEF58100C5428D /* os_wcdb.c */, - 234E92231EAEF58100C5428D /* os_wcdb.h */, - 234E92261EAEFD3B00C5428D /* mutex_wcdb.c */, - 234E92271EAEFD3B00C5428D /* mutex_wcdb.h */, - 239528FE1E700D880054D75E /* os.c */, - 239528FF1E700D880054D75E /* os.h */, - 239529021E700D920054D75E /* threads.c */, - 239529041E700D9D0054D75E /* bitvec.c */, - 239529061E700DA70054D75E /* pager.c */, - 239529071E700DA70054D75E /* pager.h */, - 2395290A1E700DB90054D75E /* pcache.c */, - 2395290B1E700DB90054D75E /* pcache.h */, - 2395290C1E700DB90054D75E /* pcache1.c */, - 239529101E700DD10054D75E /* rtree.c */, - 239529111E700DD10054D75E /* rtree.h */, - 239529121E700DD10054D75E /* sqlite3rtree.h */, - 239529161E700DDF0054D75E /* complete.c */, - 239529181E700DED0054D75E /* tokenize.c */, - 2395291A1E700DFD0054D75E /* resolve.c */, - 2395291C1E700E080054D75E /* parse.c */, - 2395291D1E700E080054D75E /* parse.h */, - 239529201E700E170054D75E /* analyze.c */, - 239529221E700E1E0054D75E /* func.c */, - 239529241E700E280054D75E /* wherecode.c */, - 239529261E700E2F0054D75E /* whereexpr.c */, - 239529281E700E340054D75E /* whereInt.h */, - 2395292A1E700E3C0054D75E /* alter.c */, - 2395292C1E700E450054D75E /* attach.c */, - 2395292E1E700E4C0054D75E /* auth.c */, - 239529301E700E590054D75E /* build.c */, - 239529321E700E5F0054D75E /* delete.c */, - 239529341E700E660054D75E /* expr.c */, - 239529361E700E6D0054D75E /* insert.c */, - 239529381E700E780054D75E /* pragma.c */, - 239529391E700E780054D75E /* pragma.h */, - 2395293C1E700E810054D75E /* select.c */, - 2395293E1E700E8A0054D75E /* trigger.c */, - 239529401E700E910054D75E /* update.c */, - 239529421E700E9C0054D75E /* vacuum.c */, - 239529441E700EA40054D75E /* walker.c */, - 239529461E700EAF0054D75E /* where.c */, - 239529481E700EBC0054D75E /* opcodes.c */, - 239529491E700EBC0054D75E /* opcodes.h */, - 239529881E700FD90054D75E /* sqlcipher.h */, - 2395294C1E700EE70054D75E /* sqlite3.h */, - 2395294D1E700EE70054D75E /* sqlite3rbu.c */, - 2395294E1E700EE70054D75E /* sqlite3rbu.h */, - 2395294F1E700EE70054D75E /* sqlite3userauth.h */, - 239529541E700EF00054D75E /* json1.c */, - 239529561E700EF90054D75E /* icu.c */, - 239529581E700F060054D75E /* sqliteicu.h */, - 2395295A1E700F0F0054D75E /* global.c */, - 2395295C1E700F170054D75E /* ctime.c */, - 2395295E1E700F200054D75E /* hwtime.h */, - 239529601E700F2C0054D75E /* date.c */, - 239529621E700F360054D75E /* dbstat.c */, - 239529641E700F410054D75E /* fault.c */, - 239529661E700F490054D75E /* fkey.c */, - 239529681E700F570054D75E /* sqliteInt.h */, - 2395296A1E700F600054D75E /* sqliteLimit.h */, - 2395296C1E700F6C0054D75E /* sqlite3ext.h */, - 2395296E1E700F760054D75E /* hash.c */, - 2395296F1E700F760054D75E /* hash.h */, - 239529721E700F7F0054D75E /* printf.c */, - 239529741E700F870054D75E /* random.c */, - 239529761E700F940054D75E /* utf.c */, - 239529771E700F940054D75E /* util.c */, - 2395297C1E700FC60054D75E /* crypto_cc.c */, - 2395297D1E700FC60054D75E /* crypto_impl.c */, - 2395297E1E700FC60054D75E /* crypto_libtomcrypt.c */, - 239529801E700FC60054D75E /* crypto.c */, - 239529811E700FC60054D75E /* crypto.h */, - 2395298A1E7010030054D75E /* vdbe.c */, - 2395298B1E7010030054D75E /* vdbe.h */, - 2395298C1E7010030054D75E /* vdbeaux.c */, - 2395298D1E7010030054D75E /* vdbeblob.c */, - 2395298E1E7010030054D75E /* vdbeInt.h */, - 2395298F1E7010030054D75E /* vdbemem.c */, - 239529901E7010030054D75E /* vdbesort.c */, - 239529911E7010030054D75E /* vdbetrace.c */, - ); - name = src; - path = "sqlcipher-preprocessed"; - sourceTree = ""; - }; - 23121C061E6FFA890012B45E /* Frameworks */ = { - isa = PBXGroup; - children = ( - 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */, - 2384AB4F1EDBFDEC007369FF /* libcommonCrypto.tbd */, - 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */, - 2384AB4A1EDBFD43007369FF /* libz.tbd */, - 23121C071E6FFA890012B45E /* Security.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 239D64E41ECE9FE8008F5B61 /* macosx */ = { - isa = PBXGroup; - children = ( - 239D64E61ECE9FE8008F5B61 /* Info.plist */, - ); - path = macosx; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 239325C51E836A7700D677CC /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 23577F5F1F74BF6700D31C05 /* fts3_tokenizer.h in Headers */, - 234E92251EAEF58100C5428D /* os_wcdb.h in Headers */, - 234E92291EAEFD3B00C5428D /* mutex_wcdb.h in Headers */, - 234E922D1EAEFF8D00C5428D /* queue.h in Headers */, - 239326341E836AAA00D677CC /* sqlite3.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXLegacyTarget section */ - 2395299B1E702CF90054D75E /* preprocess */ = { - isa = PBXLegacyTarget; - buildArgumentsString = "$(ACTION) -f Makefile.preprocessed"; - buildConfigurationList = 2395299C1E702CF90054D75E /* Build configuration list for PBXLegacyTarget "preprocess" */; - buildPhases = ( - ); - buildToolPath = /usr/bin/make; - buildWorkingDirectory = ""; - dependencies = ( - ); - name = preprocess; - passBuildSettingsInEnvironment = 0; - productName = preprocess; - }; -/* End PBXLegacyTarget section */ - -/* Begin PBXNativeTarget section */ - 239325C71E836A7700D677CC /* sqlcipher */ = { - isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; - buildPhases = ( - 239325C31E836A7700D677CC /* Sources */, - 239325C41E836A7700D677CC /* Frameworks */, - 239325C51E836A7700D677CC /* Headers */, - 239325C61E836A7700D677CC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 239325D11E836A9000D677CC /* PBXTargetDependency */, - ); - name = sqlcipher; - productName = sqlcipher; - productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 23121ADC1E6FF9110012B45E /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0900; - ORGANIZATIONNAME = sanhuazhang; - TargetAttributes = { - 239325C71E836A7700D677CC = { - CreatedOnToolsVersion = 8.2; - ProvisioningStyle = Automatic; - }; - 2395299B1E702CF90054D75E = { - CreatedOnToolsVersion = 8.2; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 23121ADF1E6FF9110012B45E /* Build configuration list for PBXProject "sqlcipher-preprocessed" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 23121ADB1E6FF9110012B45E; - productRefGroup = 23121AE51E6FF9110012B45E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 239325C71E836A7700D677CC /* sqlcipher */, - 2395299B1E702CF90054D75E /* preprocess */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 239325C61E836A7700D677CC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 239325C31E836A7700D677CC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 239325D21E836A9C00D677CC /* callback.c in Sources */, - 239325D31E836A9C00D677CC /* loadext.c in Sources */, - 239325D41E836A9C00D677CC /* rowset.c in Sources */, - 239325D51E836A9C00D677CC /* treeview.c in Sources */, - 239325D61E836A9C00D677CC /* userauth.c in Sources */, - 239325D71E836A9C00D677CC /* vtab.c in Sources */, - 239325D81E836A9C00D677CC /* btmutex.c in Sources */, - 239325D91E836A9C00D677CC /* btree.c in Sources */, - 239325DA1E836A9C00D677CC /* fts5.c in Sources */, - 239325DB1E836A9C00D677CC /* fts3_aux.c in Sources */, - 239325DC1E836A9C00D677CC /* fts3_expr.c in Sources */, - 239325DD1E836A9C00D677CC /* fts3_hash.c in Sources */, - 239325DE1E836A9C00D677CC /* fts3_icu.c in Sources */, - 239325DF1E836A9C00D677CC /* fts3_porter.c in Sources */, - 239325E01E836A9C00D677CC /* fts3_snippet.c in Sources */, - 239325E11E836A9C00D677CC /* fts3_tokenize_vtab.c in Sources */, - 239325E21E836A9C00D677CC /* fts3_tokenizer.c in Sources */, - 239325E31E836A9C00D677CC /* fts3_tokenizer1.c in Sources */, - 239325E41E836A9C00D677CC /* fts3_unicode.c in Sources */, - 239325E51E836A9C00D677CC /* fts3_unicode2.c in Sources */, - 239325E61E836A9C00D677CC /* fts3_write.c in Sources */, - 239325E71E836A9C00D677CC /* fts3.c in Sources */, - 239325E81E836A9C00D677CC /* backup.c in Sources */, - 239325E91E836A9C00D677CC /* legacy.c in Sources */, - 239325EA1E836A9C00D677CC /* main.c in Sources */, - 239325EB1E836A9C00D677CC /* notify.c in Sources */, - 239325EC1E836A9C00D677CC /* vdbeapi.c in Sources */, - 239325ED1E836A9C00D677CC /* table.c in Sources */, - 239325EE1E836A9C00D677CC /* wal.c in Sources */, - 239325EF1E836A9C00D677CC /* status.c in Sources */, - 239325F01E836A9C00D677CC /* prepare.c in Sources */, - 239325F11E836A9C00D677CC /* malloc.c in Sources */, - 239325F21E836A9C00D677CC /* mem0.c in Sources */, - 239325F31E836A9C00D677CC /* mem1.c in Sources */, - 234E92241EAEF58100C5428D /* os_wcdb.c in Sources */, - 239325F41E836A9C00D677CC /* mem2.c in Sources */, - 239325F51E836A9C00D677CC /* mem3.c in Sources */, - 239325F61E836A9C00D677CC /* mem5.c in Sources */, - 239325F71E836A9C00D677CC /* memjournal.c in Sources */, - 239325F81E836A9C00D677CC /* mutex_unix.c in Sources */, - 239325F91E836A9C00D677CC /* mutex_noop.c in Sources */, - 239325FA1E836A9C00D677CC /* mutex.c in Sources */, - 239325FB1E836A9C00D677CC /* os_unix.c in Sources */, - 239325FC1E836A9C00D677CC /* os.c in Sources */, - 239325FD1E836A9C00D677CC /* threads.c in Sources */, - 239325FE1E836A9C00D677CC /* bitvec.c in Sources */, - 239325FF1E836A9C00D677CC /* pager.c in Sources */, - 239326001E836A9C00D677CC /* pcache.c in Sources */, - 239326011E836A9C00D677CC /* pcache1.c in Sources */, - 239326021E836A9C00D677CC /* rtree.c in Sources */, - 239326031E836A9C00D677CC /* complete.c in Sources */, - 234E92281EAEFD3B00C5428D /* mutex_wcdb.c in Sources */, - 239326041E836A9C00D677CC /* tokenize.c in Sources */, - 239326051E836A9C00D677CC /* resolve.c in Sources */, - 239326061E836A9C00D677CC /* parse.c in Sources */, - 239326071E836A9C00D677CC /* analyze.c in Sources */, - 239326081E836A9C00D677CC /* func.c in Sources */, - 239326091E836A9C00D677CC /* wherecode.c in Sources */, - 2393260A1E836A9C00D677CC /* whereexpr.c in Sources */, - 2393260B1E836A9C00D677CC /* alter.c in Sources */, - 2393260C1E836A9C00D677CC /* attach.c in Sources */, - 2393260D1E836A9C00D677CC /* auth.c in Sources */, - 2393260E1E836A9C00D677CC /* build.c in Sources */, - 2393260F1E836A9C00D677CC /* delete.c in Sources */, - 239326101E836A9C00D677CC /* expr.c in Sources */, - 239326111E836A9C00D677CC /* insert.c in Sources */, - 239326121E836A9C00D677CC /* pragma.c in Sources */, - 239326131E836A9C00D677CC /* select.c in Sources */, - 239326141E836A9C00D677CC /* trigger.c in Sources */, - 239326151E836A9C00D677CC /* update.c in Sources */, - 239326161E836A9C00D677CC /* vacuum.c in Sources */, - 239326171E836A9C00D677CC /* walker.c in Sources */, - 239326181E836A9C00D677CC /* where.c in Sources */, - 234E922C1EAEFF8D00C5428D /* queue.c in Sources */, - 239326191E836A9C00D677CC /* opcodes.c in Sources */, - 2393261A1E836A9C00D677CC /* sqlite3rbu.c in Sources */, - 2393261B1E836A9C00D677CC /* json1.c in Sources */, - 2393261C1E836A9C00D677CC /* icu.c in Sources */, - 2393261D1E836A9C00D677CC /* global.c in Sources */, - 2393261E1E836A9C00D677CC /* ctime.c in Sources */, - 2393261F1E836A9C00D677CC /* date.c in Sources */, - 239326201E836A9C00D677CC /* dbstat.c in Sources */, - 239326211E836A9C00D677CC /* fault.c in Sources */, - 239326221E836A9C00D677CC /* fkey.c in Sources */, - 239326231E836A9C00D677CC /* hash.c in Sources */, - 239326241E836A9C00D677CC /* printf.c in Sources */, - 239326251E836A9C00D677CC /* random.c in Sources */, - 239326261E836A9C00D677CC /* utf.c in Sources */, - 239326271E836A9C00D677CC /* util.c in Sources */, - 239326291E836A9C00D677CC /* crypto_cc.c in Sources */, - 2393262A1E836A9C00D677CC /* crypto_impl.c in Sources */, - 2393262B1E836A9C00D677CC /* crypto_libtomcrypt.c in Sources */, - 2393262D1E836A9C00D677CC /* crypto.c in Sources */, - 2393262E1E836A9C00D677CC /* vdbe.c in Sources */, - 2393262F1E836A9C00D677CC /* vdbeaux.c in Sources */, - 239326301E836A9C00D677CC /* vdbeblob.c in Sources */, - 239326311E836A9C00D677CC /* vdbemem.c in Sources */, - 239326321E836A9C00D677CC /* vdbesort.c in Sources */, - 239326331E836A9C00D677CC /* vdbetrace.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 239325D11E836A9000D677CC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 2395299B1E702CF90054D75E /* preprocess */; - targetProxy = 239325D01E836A9000D677CC /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 23121AE61E6FF9110012B45E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = ( - "$(ARCHS_STANDARD)", - armv7, - arm64, - ); - "ARCHS[sdk=iphonesimulator*]" = ( - "$(ARCHS_STANDARD)", - armv7, - arm64, - ); - "ARCHS[sdk=macosx*]" = ( - "$(ARCHS_STANDARD)", - x86_64, - ); - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - SQLITE_ENABLE_FTS3, - SQLITE_ENABLE_FTS3_PARENTHESIS, - SQLITE_ENABLE_API_ARMOR, - SQLITE_OMIT_BUILTIN_TEST, - SQLITE_OMIT_AUTORESET, - SQLITE_ENABLE_UPDATE_DELETE_LIMIT, - SQLITE_ENABLE_RTREE, - "SQLITE_ENABLE_LOCKING_STYLE=1", - SQLITE_SYSTEM_MALLOC, - SQLITE_OMIT_LOAD_EXTENSION, - SQLITE_CORE, - "SQLITE_THREADSAFE=2", - "SQLITE_DEFAULT_CACHE_SIZE=-2000", - "SQLITE_DEFAULT_PAGE_SIZE=4096", - SQLITE_OMIT_SHARED_CACHE, - SQLITE_HAS_CODEC, - SQLCIPHER_CRYPTO_CC, - "USE_PREAD=1", - "SQLITE_TEMP_STORE=2", - SQLCIPHER_PREPROCESSED, - HAVE_USLEEP, - "SQLITE_MALLOC_SOFT_LIMIT=0", - "SQLITE_WCDB_SIGNAL_RETRY=1", - "SQLITE_DEFAULT_MEMSTATUS=0", - SQLITE_ENABLE_COLUMN_METADATA, - "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", - SQLITE_LIKE_DOESNT_MATCH_BLOBS, - "SQLITE_MAX_EXPR_DEPTH=0", - SQLITE_OMIT_DEPRECATED, - SQLITE_OMIT_PROGRESS_CALLBACK, - SQLITE_OMIT_SHARED_CACHE, - OMIT_CONSTTIME_MEM, - OMIT_MEMLOCK, - SQLITE_ENABLE_FTS3_TOKENIZER, - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - STRIP_INSTALLED_PRODUCT = NO; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; - VALID_ARCHS = "x86_64 armv7 arm64"; - }; - name = Debug; - }; - 23121AE71E6FF9110012B45E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = ( - "$(ARCHS_STANDARD)", - armv7, - arm64, - ); - "ARCHS[sdk=iphonesimulator*]" = ( - "$(ARCHS_STANDARD)", - armv7, - arm64, - ); - "ARCHS[sdk=macosx*]" = ( - "$(ARCHS_STANDARD)", - x86_64, - ); - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - SQLITE_ENABLE_FTS3, - SQLITE_ENABLE_FTS3_PARENTHESIS, - SQLITE_ENABLE_API_ARMOR, - "$(inherited)", - SQLITE_ENABLE_RTREE, - "SQLITE_ENABLE_LOCKING_STYLE=1", - SQLITE_OMIT_LOAD_EXTENSION, - SQLITE_OMIT_BUILTIN_TEST, - SQLITE_OMIT_SHARED_CACHE, - SQLITE_OMIT_AUTORESET, - SQLITE_ENABLE_UPDATE_DELETE_LIMIT, - SQLITE_SYSTEM_MALLOC, - "SQLITE_THREADSAFE=2", - "SQLITE_DEFAULT_PAGE_SIZE=4096", - "SQLITE_DEFAULT_CACHE_SIZE=-2000", - SQLITE_CORE, - SQLITE_HAS_CODEC, - "SQLITE_TEMP_STORE=2", - SQLCIPHER_CRYPTO_CC, - "USE_PREAD=1", - SQLCIPHER_PREPROCESSED, - HAVE_USLEEP, - "SQLITE_MALLOC_SOFT_LIMIT=0", - "SQLITE_WCDB_SIGNAL_RETRY=1", - "SQLITE_DEFAULT_MEMSTATUS=0", - "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", - SQLITE_LIKE_DOESNT_MATCH_BLOBS, - "SQLITE_MAX_EXPR_DEPTH=0", - SQLITE_OMIT_DEPRECATED, - SQLITE_OMIT_PROGRESS_CALLBACK, - SQLITE_OMIT_SHARED_CACHE, - SQLITE_ENABLE_COLUMN_METADATA, - OMIT_CONSTTIME_MEM, - OMIT_MEMLOCK, - SQLITE_ENABLE_FTS3_TOKENIZER, - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - STRIP_INSTALLED_PRODUCT = NO; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; - VALID_ARCHS = "x86_64 armv7 arm64"; - }; - name = Release; - }; - 239325CD1E836A7700D677CC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = macosx/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)/usr/lib/system", - ); - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = macosx/module.modulemap; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; - PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; - PRODUCT_NAME = sqlcipher; - SKIP_INSTALL = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 239325CE1E836A7700D677CC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = macosx/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)/usr/lib/system", - ); - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = macosx/module.modulemap; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; - PRODUCT_BUNDLE_IDENTIFIER = com.tencent.sqlcipher; - PRODUCT_NAME = sqlcipher; - SKIP_INSTALL = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 2395299D1E702CF90054D75E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUGGING_SYMBOLS = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 2395299E1E702CF90054D75E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 23121ADF1E6FF9110012B45E /* Build configuration list for PBXProject "sqlcipher-preprocessed" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 23121AE61E6FF9110012B45E /* Debug */, - 23121AE71E6FF9110012B45E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 239325CD1E836A7700D677CC /* Debug */, - 239325CE1E836A7700D677CC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2395299C1E702CF90054D75E /* Build configuration list for PBXLegacyTarget "preprocess" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2395299D1E702CF90054D75E /* Debug */, - 2395299E1E702CF90054D75E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 23121ADC1E6FF9110012B45E /* Project object */; -} From eeb86f7a5fa48df5e1fbd1cc74a0f06899e1cef7 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 23 Jan 2018 16:39:31 +0800 Subject: [PATCH 73/94] Add shared proprocessed xcodeproj --- .../project.pbxproj | 1005 +++++++++++++++++ .../xcshareddata/xcschemes/sqlcipher.xcscheme | 82 ++ 2 files changed, 1087 insertions(+) create mode 100644 sqlcipher.preprocessed.xcodeproj/project.pbxproj create mode 100644 sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..9e2862b5bc --- /dev/null +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -0,0 +1,1005 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 232DA3221FB0700A0075F021 /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3211FB070090075F021 /* callback.c */; }; + 232DA3241FB070110075F021 /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3231FB070110075F021 /* loadext.c */; }; + 232DA3261FB070180075F021 /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3251FB070180075F021 /* rowset.c */; }; + 232DA3281FB070210075F021 /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3271FB070210075F021 /* treeview.c */; }; + 232DA32A1FB0703C0075F021 /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3291FB0703C0075F021 /* userauth.c */; }; + 232DA32C1FB070540075F021 /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA32B1FB070530075F021 /* vtab.c */; }; + 232DA32E1FB070640075F021 /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA32D1FB070640075F021 /* btmutex.c */; }; + 232DA3301FB0706B0075F021 /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA32F1FB0706B0075F021 /* btree.c */; }; + 232DA3351FB0708F0075F021 /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3331FB0708E0075F021 /* fts5.c */; }; + 232DA3371FB070BB0075F021 /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3361FB070BB0075F021 /* fts3_aux.c */; }; + 232DA3391FB070C00075F021 /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3381FB070C00075F021 /* fts3_expr.c */; }; + 232DA33C1FB070C50075F021 /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA33B1FB070C50075F021 /* fts3_hash.c */; }; + 232DA33E1FB070CD0075F021 /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA33D1FB070CD0075F021 /* fts3_icu.c */; }; + 232DA3401FB070D60075F021 /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA33F1FB070D60075F021 /* fts3_porter.c */; }; + 232DA3421FB070DA0075F021 /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3411FB070DA0075F021 /* fts3_snippet.c */; }; + 232DA34D1FB070F20075F021 /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3431FB070EF0075F021 /* fts3_tokenize_vtab.c */; }; + 232DA34E1FB070F20075F021 /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3451FB070EF0075F021 /* fts3_tokenizer.c */; }; + 232DA34F1FB070F20075F021 /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3461FB070EF0075F021 /* fts3_tokenizer1.c */; }; + 232DA3501FB070F20075F021 /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3481FB070F00075F021 /* fts3.c */; }; + 232DA3511FB070F20075F021 /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3491FB070F00075F021 /* fts3_write.c */; }; + 232DA3521FB070F20075F021 /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA34B1FB070F10075F021 /* fts3_unicode.c */; }; + 232DA3531FB070F20075F021 /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA34C1FB070F10075F021 /* fts3_unicode2.c */; }; + 232DA3551FB071030075F021 /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3541FB071020075F021 /* backup.c */; }; + 232DA3571FB071070075F021 /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3561FB071070075F021 /* legacy.c */; }; + 232DA3591FB0710D0075F021 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3581FB0710C0075F021 /* main.c */; }; + 232DA35B1FB071120075F021 /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA35A1FB071110075F021 /* notify.c */; }; + 232DA35D1FB0711D0075F021 /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA35C1FB0711D0075F021 /* vdbeapi.c */; }; + 232DA35F1FB071240075F021 /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA35E1FB071230075F021 /* table.c */; }; + 232DA3621FB0712A0075F021 /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3601FB071290075F021 /* wal.c */; }; + 232DA3641FB071310075F021 /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3631FB071310075F021 /* status.c */; }; + 232DA3661FB071390075F021 /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3651FB071380075F021 /* prepare.c */; }; + 232DA36D1FB071460075F021 /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3671FB071440075F021 /* mem0.c */; }; + 232DA36E1FB071460075F021 /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3681FB071450075F021 /* mem1.c */; }; + 232DA36F1FB071460075F021 /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3691FB071450075F021 /* mem3.c */; }; + 232DA3701FB071460075F021 /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA36A1FB071450075F021 /* malloc.c */; }; + 232DA3711FB071460075F021 /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA36B1FB071460075F021 /* mem2.c */; }; + 232DA3721FB071460075F021 /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA36C1FB071460075F021 /* mem5.c */; }; + 232DA3781FB0716B0075F021 /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3731FB071690075F021 /* mutex_unix.c */; }; + 232DA3791FB0716B0075F021 /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3751FB0716A0075F021 /* mutex.c */; }; + 232DA37A1FB0716B0075F021 /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3761FB0716A0075F021 /* memjournal.c */; }; + 232DA37B1FB0716B0075F021 /* mutex_noop.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3771FB0716A0075F021 /* mutex_noop.c */; }; + 232DA3811FB071790075F021 /* os_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA37E1FB071780075F021 /* os_wcdb.c */; }; + 232DA3821FB071790075F021 /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA37F1FB071780075F021 /* os_unix.c */; }; + 232DA3851FB0717E0075F021 /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3841FB0717D0075F021 /* queue.c */; }; + 232DA3881FB071870075F021 /* mutex_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3871FB071870075F021 /* mutex_wcdb.c */; }; + 232DA38B1FB0718F0075F021 /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA38A1FB0718E0075F021 /* os.c */; }; + 232DA38D1FB071980075F021 /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA38C1FB071970075F021 /* threads.c */; }; + 232DA38F1FB0719E0075F021 /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA38E1FB0719E0075F021 /* bitvec.c */; }; + 232DA3921FB071A70075F021 /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3901FB071A60075F021 /* pager.c */; }; + 232DA3961FB071AC0075F021 /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3931FB071AB0075F021 /* pcache.c */; }; + 232DA3971FB071AC0075F021 /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3951FB071AB0075F021 /* pcache1.c */; }; + 232DA39A1FB081DA0075F021 /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3991FB081D90075F021 /* rtree.c */; }; + 232DA39D1FB081F90075F021 /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA39C1FB081F90075F021 /* complete.c */; }; + 232DA39F1FB082040075F021 /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA39E1FB082030075F021 /* tokenize.c */; }; + 232DA3A11FB082090075F021 /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A01FB082090075F021 /* resolve.c */; }; + 232DA3A41FB0822B0075F021 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A21FB0822A0075F021 /* parse.c */; }; + 232DA3A61FB082380075F021 /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A51FB082380075F021 /* analyze.c */; }; + 232DA3A81FB0823F0075F021 /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A71FB0823F0075F021 /* func.c */; }; + 232DA3AC1FB0824D0075F021 /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3AA1FB0824C0075F021 /* wherecode.c */; }; + 232DA3AD1FB0824D0075F021 /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3AB1FB0824C0075F021 /* whereexpr.c */; }; + 232DA3AF1FB082530075F021 /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3AE1FB082530075F021 /* where.c */; }; + 232DA3B21FB0825F0075F021 /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B01FB0825E0075F021 /* alter.c */; }; + 232DA3B31FB0825F0075F021 /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B11FB0825E0075F021 /* attach.c */; }; + 232DA3C01FB082A90075F021 /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B41FB082A60075F021 /* expr.c */; }; + 232DA3C11FB082A90075F021 /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B51FB082A60075F021 /* vacuum.c */; }; + 232DA3C21FB082A90075F021 /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B61FB082A70075F021 /* select.c */; }; + 232DA3C31FB082A90075F021 /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B81FB082A70075F021 /* pragma.c */; }; + 232DA3C41FB082A90075F021 /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B91FB082A70075F021 /* build.c */; }; + 232DA3C51FB082A90075F021 /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BA1FB082A80075F021 /* trigger.c */; }; + 232DA3C61FB082A90075F021 /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BB1FB082A80075F021 /* auth.c */; }; + 232DA3C71FB082A90075F021 /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BC1FB082A80075F021 /* update.c */; }; + 232DA3C81FB082A90075F021 /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BD1FB082A80075F021 /* delete.c */; }; + 232DA3C91FB082A90075F021 /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BE1FB082A90075F021 /* insert.c */; }; + 232DA3CA1FB082A90075F021 /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BF1FB082A90075F021 /* walker.c */; }; + 232DA3CD1FB082B40075F021 /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3CB1FB082B30075F021 /* opcodes.c */; }; + 232DA3D21FB082DB0075F021 /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D11FB082DA0075F021 /* sqlite3rbu.c */; }; + 232DA3D51FB082F30075F021 /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D41FB082F30075F021 /* json1.c */; }; + 232DA3D81FB082FA0075F021 /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D61FB082FA0075F021 /* icu.c */; }; + 232DA3F61FB0836E0075F021 /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D91FB083660075F021 /* vdbeaux.c */; }; + 232DA3F71FB0836E0075F021 /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3DC1FB083670075F021 /* vdbetrace.c */; }; + 232DA3F81FB0836E0075F021 /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3DE1FB083680075F021 /* utf.c */; }; + 232DA3F91FB0836E0075F021 /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3DF1FB083680075F021 /* vdbe.c */; }; + 232DA3FA1FB0836E0075F021 /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E01FB083680075F021 /* crypto_libtomcrypt.c */; }; + 232DA3FB1FB0836E0075F021 /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E11FB083680075F021 /* crypto_impl.c */; }; + 232DA3FC1FB0836E0075F021 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E21FB083690075F021 /* util.c */; }; + 232DA3FD1FB0836E0075F021 /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E31FB083690075F021 /* hash.c */; }; + 232DA3FE1FB0836E0075F021 /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E41FB083690075F021 /* global.c */; }; + 232DA3FF1FB0836E0075F021 /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E51FB083690075F021 /* ctime.c */; }; + 232DA4001FB0836E0075F021 /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E61FB0836A0075F021 /* fkey.c */; }; + 232DA4011FB0836E0075F021 /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E71FB0836A0075F021 /* date.c */; }; + 232DA4021FB0836E0075F021 /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E81FB0836A0075F021 /* printf.c */; }; + 232DA4031FB0836E0075F021 /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E91FB0836B0075F021 /* random.c */; }; + 232DA4041FB0836E0075F021 /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3EA1FB0836B0075F021 /* dbstat.c */; }; + 232DA4051FB0836E0075F021 /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3EB1FB0836B0075F021 /* vdbemem.c */; }; + 232DA4061FB0836E0075F021 /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3ED1FB0836C0075F021 /* vdbeblob.c */; }; + 232DA4071FB0836E0075F021 /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3EF1FB0836C0075F021 /* vdbesort.c */; }; + 232DA4081FB0836E0075F021 /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3F01FB0836D0075F021 /* crypto.c */; }; + 232DA4091FB0836E0075F021 /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3F31FB0836E0075F021 /* crypto_cc.c */; }; + 232DA40A1FB0836E0075F021 /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3F41FB0836E0075F021 /* fault.c */; }; + 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */; }; + 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; + 23E737C71FB1689500EEBC3D /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA3CF1FB082C70075F021 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 23E737C81FB1689A00EEBC3D /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA34A1FB070F00075F021 /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 23E737CD1FB1693400EEBC3D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 23E737C91FB168B500EEBC3D; + remoteInfo = preprocess; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 232DA3201FB06FFD0075F021 /* keywordhash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = keywordhash.h; path = ../keywordhash.h; sourceTree = ""; }; + 232DA3211FB070090075F021 /* callback.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = callback.c; sourceTree = ""; }; + 232DA3231FB070110075F021 /* loadext.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loadext.c; sourceTree = ""; }; + 232DA3251FB070180075F021 /* rowset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rowset.c; sourceTree = ""; }; + 232DA3271FB070210075F021 /* treeview.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = treeview.c; sourceTree = ""; }; + 232DA3291FB0703C0075F021 /* userauth.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = userauth.c; path = ../ext/userauth/userauth.c; sourceTree = ""; }; + 232DA32B1FB070530075F021 /* vtab.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vtab.c; sourceTree = ""; }; + 232DA32D1FB070640075F021 /* btmutex.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = btmutex.c; sourceTree = ""; }; + 232DA32F1FB0706B0075F021 /* btree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = btree.c; sourceTree = ""; }; + 232DA3311FB0706F0075F021 /* btreeInt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = btreeInt.h; sourceTree = ""; }; + 232DA3321FB070730075F021 /* btree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = btree.h; sourceTree = ""; }; + 232DA3331FB0708E0075F021 /* fts5.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts5.c; path = ../fts5.c; sourceTree = ""; }; + 232DA3341FB0708F0075F021 /* fts5.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fts5.h; path = ../fts5.h; sourceTree = ""; }; + 232DA3361FB070BB0075F021 /* fts3_aux.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_aux.c; path = ../ext/fts3/fts3_aux.c; sourceTree = ""; }; + 232DA3381FB070C00075F021 /* fts3_expr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_expr.c; path = ../ext/fts3/fts3_expr.c; sourceTree = ""; }; + 232DA33A1FB070C50075F021 /* fts3_hash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fts3_hash.h; path = ../ext/fts3/fts3_hash.h; sourceTree = ""; }; + 232DA33B1FB070C50075F021 /* fts3_hash.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_hash.c; path = ../ext/fts3/fts3_hash.c; sourceTree = ""; }; + 232DA33D1FB070CD0075F021 /* fts3_icu.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_icu.c; path = ../ext/fts3/fts3_icu.c; sourceTree = ""; }; + 232DA33F1FB070D60075F021 /* fts3_porter.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_porter.c; path = ../ext/fts3/fts3_porter.c; sourceTree = ""; }; + 232DA3411FB070DA0075F021 /* fts3_snippet.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_snippet.c; path = ../ext/fts3/fts3_snippet.c; sourceTree = ""; }; + 232DA3431FB070EF0075F021 /* fts3_tokenize_vtab.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_tokenize_vtab.c; path = ../ext/fts3/fts3_tokenize_vtab.c; sourceTree = ""; }; + 232DA3441FB070EF0075F021 /* fts3Int.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fts3Int.h; path = ../ext/fts3/fts3Int.h; sourceTree = ""; }; + 232DA3451FB070EF0075F021 /* fts3_tokenizer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer.c; path = ../ext/fts3/fts3_tokenizer.c; sourceTree = ""; }; + 232DA3461FB070EF0075F021 /* fts3_tokenizer1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_tokenizer1.c; path = ../ext/fts3/fts3_tokenizer1.c; sourceTree = ""; }; + 232DA3471FB070F00075F021 /* fts3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fts3.h; path = ../ext/fts3/fts3.h; sourceTree = ""; }; + 232DA3481FB070F00075F021 /* fts3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3.c; path = ../ext/fts3/fts3.c; sourceTree = ""; }; + 232DA3491FB070F00075F021 /* fts3_write.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_write.c; path = ../ext/fts3/fts3_write.c; sourceTree = ""; }; + 232DA34A1FB070F00075F021 /* fts3_tokenizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ../ext/fts3/fts3_tokenizer.h; sourceTree = ""; }; + 232DA34B1FB070F10075F021 /* fts3_unicode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_unicode.c; path = ../ext/fts3/fts3_unicode.c; sourceTree = ""; }; + 232DA34C1FB070F10075F021 /* fts3_unicode2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = fts3_unicode2.c; path = ../ext/fts3/fts3_unicode2.c; sourceTree = ""; }; + 232DA3541FB071020075F021 /* backup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = backup.c; sourceTree = ""; }; + 232DA3561FB071070075F021 /* legacy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = legacy.c; sourceTree = ""; }; + 232DA3581FB0710C0075F021 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 232DA35A1FB071110075F021 /* notify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify.c; sourceTree = ""; }; + 232DA35C1FB0711D0075F021 /* vdbeapi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbeapi.c; sourceTree = ""; }; + 232DA35E1FB071230075F021 /* table.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = table.c; sourceTree = ""; }; + 232DA3601FB071290075F021 /* wal.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wal.c; sourceTree = ""; }; + 232DA3611FB0712A0075F021 /* wal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wal.h; sourceTree = ""; }; + 232DA3631FB071310075F021 /* status.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = status.c; sourceTree = ""; }; + 232DA3651FB071380075F021 /* prepare.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = prepare.c; sourceTree = ""; }; + 232DA3671FB071440075F021 /* mem0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mem0.c; sourceTree = ""; }; + 232DA3681FB071450075F021 /* mem1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mem1.c; sourceTree = ""; }; + 232DA3691FB071450075F021 /* mem3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mem3.c; sourceTree = ""; }; + 232DA36A1FB071450075F021 /* malloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = malloc.c; sourceTree = ""; }; + 232DA36B1FB071460075F021 /* mem2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mem2.c; sourceTree = ""; }; + 232DA36C1FB071460075F021 /* mem5.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mem5.c; sourceTree = ""; }; + 232DA3731FB071690075F021 /* mutex_unix.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mutex_unix.c; sourceTree = ""; }; + 232DA3741FB0716A0075F021 /* mutex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mutex.h; sourceTree = ""; }; + 232DA3751FB0716A0075F021 /* mutex.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mutex.c; sourceTree = ""; }; + 232DA3761FB0716A0075F021 /* memjournal.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = memjournal.c; sourceTree = ""; }; + 232DA3771FB0716A0075F021 /* mutex_noop.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mutex_noop.c; sourceTree = ""; }; + 232DA37C1FB071770075F021 /* os_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_common.h; sourceTree = ""; }; + 232DA37D1FB071780075F021 /* os_wcdb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_wcdb.h; sourceTree = ""; }; + 232DA37E1FB071780075F021 /* os_wcdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_wcdb.c; sourceTree = ""; }; + 232DA37F1FB071780075F021 /* os_unix.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_unix.c; sourceTree = ""; }; + 232DA3801FB071790075F021 /* os_setup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_setup.h; sourceTree = ""; }; + 232DA3831FB0717D0075F021 /* queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = queue.h; sourceTree = ""; }; + 232DA3841FB0717D0075F021 /* queue.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = queue.c; sourceTree = ""; }; + 232DA3861FB071870075F021 /* mutex_wcdb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mutex_wcdb.h; sourceTree = ""; }; + 232DA3871FB071870075F021 /* mutex_wcdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mutex_wcdb.c; sourceTree = ""; }; + 232DA3891FB0718E0075F021 /* os.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os.h; sourceTree = ""; }; + 232DA38A1FB0718E0075F021 /* os.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os.c; sourceTree = ""; }; + 232DA38C1FB071970075F021 /* threads.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = threads.c; sourceTree = ""; }; + 232DA38E1FB0719E0075F021 /* bitvec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = bitvec.c; sourceTree = ""; }; + 232DA3901FB071A60075F021 /* pager.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pager.c; sourceTree = ""; }; + 232DA3911FB071A60075F021 /* pager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pager.h; sourceTree = ""; }; + 232DA3931FB071AB0075F021 /* pcache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pcache.c; sourceTree = ""; }; + 232DA3941FB071AB0075F021 /* pcache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pcache.h; sourceTree = ""; }; + 232DA3951FB071AB0075F021 /* pcache1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pcache1.c; sourceTree = ""; }; + 232DA3981FB081D90075F021 /* rtree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rtree.h; path = ../ext/rtree/rtree.h; sourceTree = ""; }; + 232DA3991FB081D90075F021 /* rtree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = rtree.c; path = ../ext/rtree/rtree.c; sourceTree = ""; }; + 232DA39B1FB081DE0075F021 /* sqlite3rtree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sqlite3rtree.h; path = ../ext/rtree/sqlite3rtree.h; sourceTree = ""; }; + 232DA39C1FB081F90075F021 /* complete.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = complete.c; sourceTree = ""; }; + 232DA39E1FB082030075F021 /* tokenize.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tokenize.c; sourceTree = ""; }; + 232DA3A01FB082090075F021 /* resolve.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = resolve.c; sourceTree = ""; }; + 232DA3A21FB0822A0075F021 /* parse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = parse.c; path = ../parse.c; sourceTree = ""; }; + 232DA3A31FB0822A0075F021 /* parse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = parse.h; path = ../parse.h; sourceTree = ""; }; + 232DA3A51FB082380075F021 /* analyze.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = analyze.c; sourceTree = ""; }; + 232DA3A71FB0823F0075F021 /* func.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = func.c; sourceTree = ""; }; + 232DA3A91FB0824C0075F021 /* whereInt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = whereInt.h; sourceTree = ""; }; + 232DA3AA1FB0824C0075F021 /* wherecode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wherecode.c; sourceTree = ""; }; + 232DA3AB1FB0824C0075F021 /* whereexpr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = whereexpr.c; sourceTree = ""; }; + 232DA3AE1FB082530075F021 /* where.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = where.c; sourceTree = ""; }; + 232DA3B01FB0825E0075F021 /* alter.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = alter.c; sourceTree = ""; }; + 232DA3B11FB0825E0075F021 /* attach.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = attach.c; sourceTree = ""; }; + 232DA3B41FB082A60075F021 /* expr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = expr.c; sourceTree = ""; }; + 232DA3B51FB082A60075F021 /* vacuum.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vacuum.c; sourceTree = ""; }; + 232DA3B61FB082A70075F021 /* select.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = select.c; sourceTree = ""; }; + 232DA3B71FB082A70075F021 /* pragma.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pragma.h; sourceTree = ""; }; + 232DA3B81FB082A70075F021 /* pragma.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pragma.c; sourceTree = ""; }; + 232DA3B91FB082A70075F021 /* build.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = build.c; sourceTree = ""; }; + 232DA3BA1FB082A80075F021 /* trigger.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = trigger.c; sourceTree = ""; }; + 232DA3BB1FB082A80075F021 /* auth.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = auth.c; sourceTree = ""; }; + 232DA3BC1FB082A80075F021 /* update.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = update.c; sourceTree = ""; }; + 232DA3BD1FB082A80075F021 /* delete.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = delete.c; sourceTree = ""; }; + 232DA3BE1FB082A90075F021 /* insert.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = insert.c; sourceTree = ""; }; + 232DA3BF1FB082A90075F021 /* walker.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = walker.c; sourceTree = ""; }; + 232DA3CB1FB082B30075F021 /* opcodes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = opcodes.c; path = ../opcodes.c; sourceTree = ""; }; + 232DA3CC1FB082B30075F021 /* opcodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = opcodes.h; path = ../opcodes.h; sourceTree = ""; }; + 232DA3CE1FB082C20075F021 /* sqlcipher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sqlcipher.h; sourceTree = ""; }; + 232DA3CF1FB082C70075F021 /* sqlite3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sqlite3.h; path = ../sqlite3.h; sourceTree = ""; }; + 232DA3D01FB082DA0075F021 /* sqlite3rbu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sqlite3rbu.h; path = ../ext/rbu/sqlite3rbu.h; sourceTree = ""; }; + 232DA3D11FB082DA0075F021 /* sqlite3rbu.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sqlite3rbu.c; path = ../ext/rbu/sqlite3rbu.c; sourceTree = ""; }; + 232DA3D31FB082E40075F021 /* sqlite3userauth.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sqlite3userauth.h; path = ../ext/userauth/sqlite3userauth.h; sourceTree = ""; }; + 232DA3D41FB082F30075F021 /* json1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = json1.c; path = ../ext/misc/json1.c; sourceTree = ""; }; + 232DA3D61FB082FA0075F021 /* icu.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = icu.c; path = ../ext/icu/icu.c; sourceTree = ""; }; + 232DA3D71FB082FA0075F021 /* sqliteicu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sqliteicu.h; path = ../ext/icu/sqliteicu.h; sourceTree = ""; }; + 232DA3D91FB083660075F021 /* vdbeaux.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbeaux.c; sourceTree = ""; }; + 232DA3DA1FB083670075F021 /* vdbeInt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vdbeInt.h; sourceTree = ""; }; + 232DA3DB1FB083670075F021 /* sqlite3ext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sqlite3ext.h; sourceTree = ""; }; + 232DA3DC1FB083670075F021 /* vdbetrace.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbetrace.c; sourceTree = ""; }; + 232DA3DD1FB083670075F021 /* vdbe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vdbe.h; sourceTree = ""; }; + 232DA3DE1FB083680075F021 /* utf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = utf.c; sourceTree = ""; }; + 232DA3DF1FB083680075F021 /* vdbe.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbe.c; sourceTree = ""; }; + 232DA3E01FB083680075F021 /* crypto_libtomcrypt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = crypto_libtomcrypt.c; sourceTree = ""; }; + 232DA3E11FB083680075F021 /* crypto_impl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = crypto_impl.c; sourceTree = ""; }; + 232DA3E21FB083690075F021 /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = ""; }; + 232DA3E31FB083690075F021 /* hash.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hash.c; sourceTree = ""; }; + 232DA3E41FB083690075F021 /* global.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = global.c; sourceTree = ""; }; + 232DA3E51FB083690075F021 /* ctime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ctime.c; sourceTree = ""; }; + 232DA3E61FB0836A0075F021 /* fkey.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fkey.c; sourceTree = ""; }; + 232DA3E71FB0836A0075F021 /* date.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = date.c; sourceTree = ""; }; + 232DA3E81FB0836A0075F021 /* printf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = printf.c; sourceTree = ""; }; + 232DA3E91FB0836B0075F021 /* random.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = random.c; sourceTree = ""; }; + 232DA3EA1FB0836B0075F021 /* dbstat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dbstat.c; sourceTree = ""; }; + 232DA3EB1FB0836B0075F021 /* vdbemem.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbemem.c; sourceTree = ""; }; + 232DA3EC1FB0836B0075F021 /* sqliteInt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sqliteInt.h; sourceTree = ""; }; + 232DA3ED1FB0836C0075F021 /* vdbeblob.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbeblob.c; sourceTree = ""; }; + 232DA3EE1FB0836C0075F021 /* crypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crypto.h; sourceTree = ""; }; + 232DA3EF1FB0836C0075F021 /* vdbesort.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vdbesort.c; sourceTree = ""; }; + 232DA3F01FB0836D0075F021 /* crypto.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = crypto.c; sourceTree = ""; }; + 232DA3F11FB0836D0075F021 /* hwtime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hwtime.h; sourceTree = ""; }; + 232DA3F21FB0836D0075F021 /* hash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hash.h; sourceTree = ""; }; + 232DA3F31FB0836E0075F021 /* crypto_cc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = crypto_cc.c; sourceTree = ""; }; + 232DA3F41FB0836E0075F021 /* fault.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fault.c; sourceTree = ""; }; + 232DA3F51FB0836E0075F021 /* sqliteLimit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sqliteLimit.h; sourceTree = ""; }; + 2384AB4A1EDBFD43007369FF /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 2384AB4F1EDBFDEC007369FF /* libcommonCrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcommonCrypto.tbd; path = usr/lib/system/libcommonCrypto.tbd; sourceTree = SDKROOT; }; + 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = usr/lib/system/libcorecrypto.tbd; sourceTree = SDKROOT; }; + 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 239D64E61ECE9FE8008F5B61 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 239325C41E836A7700D677CC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */, + 2384AB4D1EDBFD48007369FF /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 23121ADB1E6FF9110012B45E = { + isa = PBXGroup; + children = ( + 239D64E41ECE9FE8008F5B61 /* macosx */, + 23121B7C1E6FF93D0012B45E /* src */, + 23121C061E6FFA890012B45E /* Frameworks */, + 23121AE51E6FF9110012B45E /* Products */, + ); + sourceTree = ""; + }; + 23121AE51E6FF9110012B45E /* Products */ = { + isa = PBXGroup; + children = ( + 239325C81E836A7700D677CC /* sqlcipher.framework */, + ); + name = Products; + sourceTree = ""; + }; + 23121B7C1E6FF93D0012B45E /* src */ = { + isa = PBXGroup; + children = ( + 232DA3201FB06FFD0075F021 /* keywordhash.h */, + 232DA3211FB070090075F021 /* callback.c */, + 232DA3231FB070110075F021 /* loadext.c */, + 232DA3251FB070180075F021 /* rowset.c */, + 232DA3271FB070210075F021 /* treeview.c */, + 232DA3291FB0703C0075F021 /* userauth.c */, + 232DA32B1FB070530075F021 /* vtab.c */, + 232DA32D1FB070640075F021 /* btmutex.c */, + 232DA32F1FB0706B0075F021 /* btree.c */, + 232DA3311FB0706F0075F021 /* btreeInt.h */, + 232DA3321FB070730075F021 /* btree.h */, + 232DA3331FB0708E0075F021 /* fts5.c */, + 232DA3341FB0708F0075F021 /* fts5.h */, + 232DA3361FB070BB0075F021 /* fts3_aux.c */, + 232DA3381FB070C00075F021 /* fts3_expr.c */, + 232DA33B1FB070C50075F021 /* fts3_hash.c */, + 232DA33A1FB070C50075F021 /* fts3_hash.h */, + 232DA33D1FB070CD0075F021 /* fts3_icu.c */, + 232DA33F1FB070D60075F021 /* fts3_porter.c */, + 232DA3411FB070DA0075F021 /* fts3_snippet.c */, + 232DA34A1FB070F00075F021 /* fts3_tokenizer.h */, + 232DA34B1FB070F10075F021 /* fts3_unicode.c */, + 232DA34C1FB070F10075F021 /* fts3_unicode2.c */, + 232DA3491FB070F00075F021 /* fts3_write.c */, + 232DA3481FB070F00075F021 /* fts3.c */, + 232DA3451FB070EF0075F021 /* fts3_tokenizer.c */, + 232DA3461FB070EF0075F021 /* fts3_tokenizer1.c */, + 232DA3471FB070F00075F021 /* fts3.h */, + 232DA3431FB070EF0075F021 /* fts3_tokenize_vtab.c */, + 232DA3441FB070EF0075F021 /* fts3Int.h */, + 232DA3541FB071020075F021 /* backup.c */, + 232DA3561FB071070075F021 /* legacy.c */, + 232DA3581FB0710C0075F021 /* main.c */, + 232DA35A1FB071110075F021 /* notify.c */, + 232DA35C1FB0711D0075F021 /* vdbeapi.c */, + 232DA35E1FB071230075F021 /* table.c */, + 232DA3601FB071290075F021 /* wal.c */, + 232DA3611FB0712A0075F021 /* wal.h */, + 232DA3631FB071310075F021 /* status.c */, + 232DA3651FB071380075F021 /* prepare.c */, + 232DA36A1FB071450075F021 /* malloc.c */, + 232DA36B1FB071460075F021 /* mem2.c */, + 232DA3671FB071440075F021 /* mem0.c */, + 232DA3681FB071450075F021 /* mem1.c */, + 232DA3691FB071450075F021 /* mem3.c */, + 232DA36C1FB071460075F021 /* mem5.c */, + 232DA3761FB0716A0075F021 /* memjournal.c */, + 232DA3771FB0716A0075F021 /* mutex_noop.c */, + 232DA3751FB0716A0075F021 /* mutex.c */, + 232DA3731FB071690075F021 /* mutex_unix.c */, + 232DA3741FB0716A0075F021 /* mutex.h */, + 232DA3801FB071790075F021 /* os_setup.h */, + 232DA3841FB0717D0075F021 /* queue.c */, + 232DA3831FB0717D0075F021 /* queue.h */, + 232DA37F1FB071780075F021 /* os_unix.c */, + 232DA37E1FB071780075F021 /* os_wcdb.c */, + 232DA37C1FB071770075F021 /* os_common.h */, + 232DA37D1FB071780075F021 /* os_wcdb.h */, + 232DA3871FB071870075F021 /* mutex_wcdb.c */, + 232DA3861FB071870075F021 /* mutex_wcdb.h */, + 232DA38A1FB0718E0075F021 /* os.c */, + 232DA3891FB0718E0075F021 /* os.h */, + 232DA38C1FB071970075F021 /* threads.c */, + 232DA38E1FB0719E0075F021 /* bitvec.c */, + 232DA3901FB071A60075F021 /* pager.c */, + 232DA3911FB071A60075F021 /* pager.h */, + 232DA3931FB071AB0075F021 /* pcache.c */, + 232DA3941FB071AB0075F021 /* pcache.h */, + 232DA3951FB071AB0075F021 /* pcache1.c */, + 232DA3991FB081D90075F021 /* rtree.c */, + 232DA3981FB081D90075F021 /* rtree.h */, + 232DA39B1FB081DE0075F021 /* sqlite3rtree.h */, + 232DA39C1FB081F90075F021 /* complete.c */, + 232DA39E1FB082030075F021 /* tokenize.c */, + 232DA3A01FB082090075F021 /* resolve.c */, + 232DA3A21FB0822A0075F021 /* parse.c */, + 232DA3A31FB0822A0075F021 /* parse.h */, + 232DA3A51FB082380075F021 /* analyze.c */, + 232DA3A71FB0823F0075F021 /* func.c */, + 232DA3AA1FB0824C0075F021 /* wherecode.c */, + 232DA3AB1FB0824C0075F021 /* whereexpr.c */, + 232DA3A91FB0824C0075F021 /* whereInt.h */, + 232DA3B01FB0825E0075F021 /* alter.c */, + 232DA3B11FB0825E0075F021 /* attach.c */, + 232DA3BB1FB082A80075F021 /* auth.c */, + 232DA3B91FB082A70075F021 /* build.c */, + 232DA3BD1FB082A80075F021 /* delete.c */, + 232DA3BE1FB082A90075F021 /* insert.c */, + 232DA3B81FB082A70075F021 /* pragma.c */, + 232DA3B71FB082A70075F021 /* pragma.h */, + 232DA3B61FB082A70075F021 /* select.c */, + 232DA3BA1FB082A80075F021 /* trigger.c */, + 232DA3BC1FB082A80075F021 /* update.c */, + 232DA3B41FB082A60075F021 /* expr.c */, + 232DA3B51FB082A60075F021 /* vacuum.c */, + 232DA3BF1FB082A90075F021 /* walker.c */, + 232DA3AE1FB082530075F021 /* where.c */, + 232DA3CB1FB082B30075F021 /* opcodes.c */, + 232DA3CC1FB082B30075F021 /* opcodes.h */, + 232DA3CE1FB082C20075F021 /* sqlcipher.h */, + 232DA3CF1FB082C70075F021 /* sqlite3.h */, + 232DA3D11FB082DA0075F021 /* sqlite3rbu.c */, + 232DA3D01FB082DA0075F021 /* sqlite3rbu.h */, + 232DA3D31FB082E40075F021 /* sqlite3userauth.h */, + 232DA3D41FB082F30075F021 /* json1.c */, + 232DA3F31FB0836E0075F021 /* crypto_cc.c */, + 232DA3E11FB083680075F021 /* crypto_impl.c */, + 232DA3E01FB083680075F021 /* crypto_libtomcrypt.c */, + 232DA3F01FB0836D0075F021 /* crypto.c */, + 232DA3EE1FB0836C0075F021 /* crypto.h */, + 232DA3E51FB083690075F021 /* ctime.c */, + 232DA3E71FB0836A0075F021 /* date.c */, + 232DA3EA1FB0836B0075F021 /* dbstat.c */, + 232DA3F41FB0836E0075F021 /* fault.c */, + 232DA3E61FB0836A0075F021 /* fkey.c */, + 232DA3E41FB083690075F021 /* global.c */, + 232DA3E31FB083690075F021 /* hash.c */, + 232DA3F21FB0836D0075F021 /* hash.h */, + 232DA3F11FB0836D0075F021 /* hwtime.h */, + 232DA3E81FB0836A0075F021 /* printf.c */, + 232DA3E91FB0836B0075F021 /* random.c */, + 232DA3DB1FB083670075F021 /* sqlite3ext.h */, + 232DA3EC1FB0836B0075F021 /* sqliteInt.h */, + 232DA3F51FB0836E0075F021 /* sqliteLimit.h */, + 232DA3DE1FB083680075F021 /* utf.c */, + 232DA3E21FB083690075F021 /* util.c */, + 232DA3DF1FB083680075F021 /* vdbe.c */, + 232DA3DD1FB083670075F021 /* vdbe.h */, + 232DA3D91FB083660075F021 /* vdbeaux.c */, + 232DA3ED1FB0836C0075F021 /* vdbeblob.c */, + 232DA3DA1FB083670075F021 /* vdbeInt.h */, + 232DA3EB1FB0836B0075F021 /* vdbemem.c */, + 232DA3EF1FB0836C0075F021 /* vdbesort.c */, + 232DA3DC1FB083670075F021 /* vdbetrace.c */, + 232DA3D61FB082FA0075F021 /* icu.c */, + 232DA3D71FB082FA0075F021 /* sqliteicu.h */, + ); + path = src; + sourceTree = ""; + }; + 23121C061E6FFA890012B45E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */, + 2384AB4F1EDBFDEC007369FF /* libcommonCrypto.tbd */, + 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */, + 2384AB4A1EDBFD43007369FF /* libz.tbd */, + 23121C071E6FFA890012B45E /* Security.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 239D64E41ECE9FE8008F5B61 /* macosx */ = { + isa = PBXGroup; + children = ( + 239D64E61ECE9FE8008F5B61 /* Info.plist */, + ); + path = macosx; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 239325C51E836A7700D677CC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 23E737C81FB1689A00EEBC3D /* fts3_tokenizer.h in Headers */, + 23E737C71FB1689500EEBC3D /* sqlite3.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXLegacyTarget section */ + 23E737C91FB168B500EEBC3D /* preprocess */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION) -f Makefile.preprocessed"; + buildConfigurationList = 23E737CA1FB168B500EEBC3D /* Build configuration list for PBXLegacyTarget "preprocess" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ./; + dependencies = ( + ); + name = preprocess; + passBuildSettingsInEnvironment = 0; + productName = preprocess; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXNativeTarget section */ + 239325C71E836A7700D677CC /* sqlcipher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; + buildPhases = ( + 239325C31E836A7700D677CC /* Sources */, + 239325C41E836A7700D677CC /* Frameworks */, + 239325C51E836A7700D677CC /* Headers */, + 239325C61E836A7700D677CC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */, + ); + name = sqlcipher; + productName = sqlcipher; + productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 23121ADC1E6FF9110012B45E /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = sanhuazhang; + TargetAttributes = { + 239325C71E836A7700D677CC = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + 23E737C91FB168B500EEBC3D = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 23121ADF1E6FF9110012B45E /* Build configuration list for PBXProject "sqlcipher.preprocessed" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 23121ADB1E6FF9110012B45E; + productRefGroup = 23121AE51E6FF9110012B45E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 239325C71E836A7700D677CC /* sqlcipher */, + 23E737C91FB168B500EEBC3D /* preprocess */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 239325C61E836A7700D677CC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 239325C31E836A7700D677CC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 232DA3C61FB082A90075F021 /* auth.c in Sources */, + 232DA3F71FB0836E0075F021 /* vdbetrace.c in Sources */, + 232DA3641FB071310075F021 /* status.c in Sources */, + 232DA3261FB070180075F021 /* rowset.c in Sources */, + 232DA3C51FB082A90075F021 /* trigger.c in Sources */, + 232DA3A61FB082380075F021 /* analyze.c in Sources */, + 232DA3A41FB0822B0075F021 /* parse.c in Sources */, + 232DA4011FB0836E0075F021 /* date.c in Sources */, + 232DA3521FB070F20075F021 /* fts3_unicode.c in Sources */, + 232DA3881FB071870075F021 /* mutex_wcdb.c in Sources */, + 232DA3D21FB082DB0075F021 /* sqlite3rbu.c in Sources */, + 232DA34E1FB070F20075F021 /* fts3_tokenizer.c in Sources */, + 232DA3511FB070F20075F021 /* fts3_write.c in Sources */, + 232DA36F1FB071460075F021 /* mem3.c in Sources */, + 232DA40A1FB0836E0075F021 /* fault.c in Sources */, + 232DA3621FB0712A0075F021 /* wal.c in Sources */, + 232DA3401FB070D60075F021 /* fts3_porter.c in Sources */, + 232DA37A1FB0716B0075F021 /* memjournal.c in Sources */, + 232DA3811FB071790075F021 /* os_wcdb.c in Sources */, + 232DA38B1FB0718F0075F021 /* os.c in Sources */, + 232DA3F61FB0836E0075F021 /* vdbeaux.c in Sources */, + 232DA3791FB0716B0075F021 /* mutex.c in Sources */, + 232DA36D1FB071460075F021 /* mem0.c in Sources */, + 232DA3FA1FB0836E0075F021 /* crypto_libtomcrypt.c in Sources */, + 232DA3C11FB082A90075F021 /* vacuum.c in Sources */, + 232DA3FD1FB0836E0075F021 /* hash.c in Sources */, + 232DA39D1FB081F90075F021 /* complete.c in Sources */, + 232DA4001FB0836E0075F021 /* fkey.c in Sources */, + 232DA32C1FB070540075F021 /* vtab.c in Sources */, + 232DA3C01FB082A90075F021 /* expr.c in Sources */, + 232DA39A1FB081DA0075F021 /* rtree.c in Sources */, + 232DA35F1FB071240075F021 /* table.c in Sources */, + 232DA3AC1FB0824D0075F021 /* wherecode.c in Sources */, + 232DA33E1FB070CD0075F021 /* fts3_icu.c in Sources */, + 232DA4061FB0836E0075F021 /* vdbeblob.c in Sources */, + 232DA35D1FB0711D0075F021 /* vdbeapi.c in Sources */, + 232DA3CA1FB082A90075F021 /* walker.c in Sources */, + 232DA3531FB070F20075F021 /* fts3_unicode2.c in Sources */, + 232DA37B1FB0716B0075F021 /* mutex_noop.c in Sources */, + 232DA3A81FB0823F0075F021 /* func.c in Sources */, + 232DA3371FB070BB0075F021 /* fts3_aux.c in Sources */, + 232DA32A1FB0703C0075F021 /* userauth.c in Sources */, + 232DA3701FB071460075F021 /* malloc.c in Sources */, + 232DA3C91FB082A90075F021 /* insert.c in Sources */, + 232DA3961FB071AC0075F021 /* pcache.c in Sources */, + 232DA4041FB0836E0075F021 /* dbstat.c in Sources */, + 232DA33C1FB070C50075F021 /* fts3_hash.c in Sources */, + 232DA3AF1FB082530075F021 /* where.c in Sources */, + 232DA3B21FB0825F0075F021 /* alter.c in Sources */, + 232DA3281FB070210075F021 /* treeview.c in Sources */, + 232DA34D1FB070F20075F021 /* fts3_tokenize_vtab.c in Sources */, + 232DA3421FB070DA0075F021 /* fts3_snippet.c in Sources */, + 232DA3C31FB082A90075F021 /* pragma.c in Sources */, + 232DA3AD1FB0824D0075F021 /* whereexpr.c in Sources */, + 232DA3B31FB0825F0075F021 /* attach.c in Sources */, + 232DA3711FB071460075F021 /* mem2.c in Sources */, + 232DA3971FB071AC0075F021 /* pcache1.c in Sources */, + 232DA3591FB0710D0075F021 /* main.c in Sources */, + 232DA3D81FB082FA0075F021 /* icu.c in Sources */, + 232DA3241FB070110075F021 /* loadext.c in Sources */, + 232DA4051FB0836E0075F021 /* vdbemem.c in Sources */, + 232DA3F81FB0836E0075F021 /* utf.c in Sources */, + 232DA3221FB0700A0075F021 /* callback.c in Sources */, + 232DA3391FB070C00075F021 /* fts3_expr.c in Sources */, + 232DA39F1FB082040075F021 /* tokenize.c in Sources */, + 232DA3921FB071A70075F021 /* pager.c in Sources */, + 232DA3851FB0717E0075F021 /* queue.c in Sources */, + 232DA3C71FB082A90075F021 /* update.c in Sources */, + 232DA3FF1FB0836E0075F021 /* ctime.c in Sources */, + 232DA3CD1FB082B40075F021 /* opcodes.c in Sources */, + 232DA4081FB0836E0075F021 /* crypto.c in Sources */, + 232DA3C41FB082A90075F021 /* build.c in Sources */, + 232DA4021FB0836E0075F021 /* printf.c in Sources */, + 232DA34F1FB070F20075F021 /* fts3_tokenizer1.c in Sources */, + 232DA3FC1FB0836E0075F021 /* util.c in Sources */, + 232DA3FE1FB0836E0075F021 /* global.c in Sources */, + 232DA3571FB071070075F021 /* legacy.c in Sources */, + 232DA3351FB0708F0075F021 /* fts5.c in Sources */, + 232DA3C21FB082A90075F021 /* select.c in Sources */, + 232DA3FB1FB0836E0075F021 /* crypto_impl.c in Sources */, + 232DA32E1FB070640075F021 /* btmutex.c in Sources */, + 232DA35B1FB071120075F021 /* notify.c in Sources */, + 232DA3D51FB082F30075F021 /* json1.c in Sources */, + 232DA36E1FB071460075F021 /* mem1.c in Sources */, + 232DA3721FB071460075F021 /* mem5.c in Sources */, + 232DA3F91FB0836E0075F021 /* vdbe.c in Sources */, + 232DA3C81FB082A90075F021 /* delete.c in Sources */, + 232DA3A11FB082090075F021 /* resolve.c in Sources */, + 232DA4091FB0836E0075F021 /* crypto_cc.c in Sources */, + 232DA38D1FB071980075F021 /* threads.c in Sources */, + 232DA4031FB0836E0075F021 /* random.c in Sources */, + 232DA3661FB071390075F021 /* prepare.c in Sources */, + 232DA3821FB071790075F021 /* os_unix.c in Sources */, + 232DA4071FB0836E0075F021 /* vdbesort.c in Sources */, + 232DA38F1FB0719E0075F021 /* bitvec.c in Sources */, + 232DA3501FB070F20075F021 /* fts3.c in Sources */, + 232DA3301FB0706B0075F021 /* btree.c in Sources */, + 232DA3781FB0716B0075F021 /* mutex_unix.c in Sources */, + 232DA3551FB071030075F021 /* backup.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 23E737C91FB168B500EEBC3D /* preprocess */; + targetProxy = 23E737CD1FB1693400EEBC3D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 23121AE61E6FF9110012B45E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7, + arm64, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7, + arm64, + ); + "ARCHS[sdk=macosx*]" = ( + "$(ARCHS_STANDARD)", + x86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + SQLITE_ENABLE_FTS3, + SQLITE_ENABLE_FTS3_PARENTHESIS, + SQLITE_ENABLE_API_ARMOR, + SQLITE_OMIT_BUILTIN_TEST, + SQLITE_OMIT_AUTORESET, + SQLITE_ENABLE_UPDATE_DELETE_LIMIT, + SQLITE_ENABLE_RTREE, + "SQLITE_ENABLE_LOCKING_STYLE=1", + SQLITE_SYSTEM_MALLOC, + SQLITE_OMIT_LOAD_EXTENSION, + SQLITE_CORE, + "SQLITE_THREADSAFE=2", + "SQLITE_DEFAULT_CACHE_SIZE=-2000", + "SQLITE_DEFAULT_PAGE_SIZE=4096", + SQLITE_OMIT_SHARED_CACHE, + SQLITE_HAS_CODEC, + SQLCIPHER_CRYPTO_CC, + "USE_PREAD=1", + "SQLITE_TEMP_STORE=2", + SQLCIPHER_PREPROCESSED, + HAVE_USLEEP, + "SQLITE_MALLOC_SOFT_LIMIT=0", + "SQLITE_WCDB_SIGNAL_RETRY=1", + "SQLITE_DEFAULT_MEMSTATUS=0", + SQLITE_ENABLE_COLUMN_METADATA, + "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", + SQLITE_LIKE_DOESNT_MATCH_BLOBS, + "SQLITE_MAX_EXPR_DEPTH=0", + SQLITE_OMIT_DEPRECATED, + SQLITE_OMIT_PROGRESS_CALLBACK, + SQLITE_OMIT_SHARED_CACHE, + OMIT_CONSTTIME_MEM, + OMIT_MEMLOCK, + SQLITE_ENABLE_FTS3_TOKENIZER, + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = "x86_64 armv7 arm64"; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 23121AE71E6FF9110012B45E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7, + arm64, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7, + arm64, + ); + "ARCHS[sdk=macosx*]" = ( + "$(ARCHS_STANDARD)", + x86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + SQLITE_ENABLE_FTS3, + SQLITE_ENABLE_FTS3_PARENTHESIS, + SQLITE_ENABLE_API_ARMOR, + "$(inherited)", + SQLITE_ENABLE_RTREE, + "SQLITE_ENABLE_LOCKING_STYLE=1", + SQLITE_OMIT_LOAD_EXTENSION, + SQLITE_OMIT_BUILTIN_TEST, + SQLITE_OMIT_SHARED_CACHE, + SQLITE_OMIT_AUTORESET, + SQLITE_ENABLE_UPDATE_DELETE_LIMIT, + SQLITE_SYSTEM_MALLOC, + "SQLITE_THREADSAFE=2", + "SQLITE_DEFAULT_PAGE_SIZE=4096", + "SQLITE_DEFAULT_CACHE_SIZE=-2000", + SQLITE_CORE, + SQLITE_HAS_CODEC, + "SQLITE_TEMP_STORE=2", + SQLCIPHER_CRYPTO_CC, + "USE_PREAD=1", + SQLCIPHER_PREPROCESSED, + HAVE_USLEEP, + "SQLITE_MALLOC_SOFT_LIMIT=0", + "SQLITE_WCDB_SIGNAL_RETRY=1", + "SQLITE_DEFAULT_MEMSTATUS=0", + "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", + SQLITE_LIKE_DOESNT_MATCH_BLOBS, + "SQLITE_MAX_EXPR_DEPTH=0", + SQLITE_OMIT_DEPRECATED, + SQLITE_OMIT_PROGRESS_CALLBACK, + SQLITE_OMIT_SHARED_CACHE, + SQLITE_ENABLE_COLUMN_METADATA, + OMIT_CONSTTIME_MEM, + OMIT_MEMLOCK, + SQLITE_ENABLE_FTS3_TOKENIZER, + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = "x86_64 armv7 arm64"; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 239325CD1E836A7700D677CC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_NAME = sqlcipher; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 239325CE1E836A7700D677CC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_NAME = sqlcipher; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 23E737CB1FB168B500EEBC3D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_STYLE = Automatic; + DEBUGGING_SYMBOLS = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 23E737CC1FB168B500EEBC3D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 23121ADF1E6FF9110012B45E /* Build configuration list for PBXProject "sqlcipher.preprocessed" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23121AE61E6FF9110012B45E /* Debug */, + 23121AE71E6FF9110012B45E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 239325CD1E836A7700D677CC /* Debug */, + 239325CE1E836A7700D677CC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 23E737CA1FB168B500EEBC3D /* Build configuration list for PBXLegacyTarget "preprocess" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23E737CB1FB168B500EEBC3D /* Debug */, + 23E737CC1FB168B500EEBC3D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 23121ADC1E6FF9110012B45E /* Project object */; +} diff --git a/sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme b/sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme new file mode 100644 index 0000000000..4e7fd57850 --- /dev/null +++ b/sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7157289908df99e8482a5135fdc579d04859f304 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 23 Jan 2018 21:01:37 +0800 Subject: [PATCH 74/94] Cocoapods spec --- WCDBOptimizedSQLCipher.podspec | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 WCDBOptimizedSQLCipher.podspec diff --git a/WCDBOptimizedSQLCipher.podspec b/WCDBOptimizedSQLCipher.podspec new file mode 100644 index 0000000000..e2c652dfdb --- /dev/null +++ b/WCDBOptimizedSQLCipher.podspec @@ -0,0 +1,36 @@ +# pod lib lint sqlcipher.podspec --verbose --allow-warnings +# pod trunk push sqlcipher.podspec --verbose --allow-warnings +Pod::Spec.new do |sqlcipher| + sqlcipher.name = "WCDBOptimizedSQLCipher" + sqlcipher.version = "1.1.0" + sqlcipher.summary = "Full Database Encryption for SQLite and optimized by WCDB." + sqlcipher.description = <<-DESC + SQLCipher is an open source extension to SQLite that provides transparent 256-bit AES encryption of database files. + + This is optimized version by WCDB, which is an efficient, complete, easy-to-use mobile database framework. + DESC + sqlcipher.homepage = "https://github.com/Tencent/sqlcipher" + sqlcipher.license = { :type => "BSD", :file => "LICENSE"} + sqlcipher.author = { "sanhuazhang" => "sanhuazhang@tencent.com" } + sqlcipher.source = { :git => "https://github.com/Tencent/sqlcipher.git", :commit => "eeb86f7a5fa48df5e1fbd1cc74a0f06899e1cef7" } + sqlcipher.module_name = "sqlcipher" + sqlcipher.public_header_files = "sqlite3.h", "ext/fts3/fts3_tokenizer.h" + sqlcipher.source_files = "src/callback.c", "src/loadext.c", "src/rowset.c", "src/treeview.c", "ext/userauth.c", "src/vtab.c", "src/btmutex.c", "src/btree.c", "src/btreeInt.h", "src/btree.h", "fts5.c", "fts5.h", "ext/fts3/fts3_aux.c", "ext/fts3/fts3_expr.c", "ext/fts3/fts3_hash.c", "ext/fts3/fts3_hash.h", "ext/fts3/fts3_icu.c", "ext/fts3/fts3_porter.c", "ext/fts3/fts3_snippet.c", "ext/fts3/fts3_tokenize_vtab.c", "ext/fts3/fts3_tokenizer.c", "ext/fts3/fts3_tokenizer1.c", "ext/fts3/fts3_unicode.c", "ext/fts3/fts3_unicode2.c", "ext/fts3/fts3_write.c", "ext/fts3/fts3.c", "ext/fts3/fts3.h", "ext/fts3/fts3Int.h", "src/backup.c", "src/legacy.c", "src/main.c", "src/notify.c", "src/vdbeapi.c", "src/table.c", "src/wal.c", "src/wal.h", "src/status.c", "src/prepare.c", "src/malloc.c", "src/mem0.c", "src/mem1.c", "src/mem2.c", "src/mem3.c", "src/mem5.c", "src/memjournal.c", "src/mutex_unix.c", "src/mutex_noop.c", "src/mutex.c", "src/mutex.h", "src/os_common.h", "src/os_setup.h", "src/os_unix.c", "src/queue.c", "src/queue.h", "src/os_wcdb.c", "src/os_wcdb.h", "src/mutex_wcdb.c", "src/mutex_wcdb.h", "src/os.c", "src/os.h", "src/threads.c", "src/bitvec.c", "src/pager.c", "src/pager.h", "src/pcache.c", "src/pcache.h", "src/pcache1.c", "ext/rtree/rtree.c", "ext/rtree/rtree.h", "ext/rtree/sqlite3rtree.h", "src/complete.c", "src/tokenize.c", "src/resolve.c", "parse.c", "parse.h", "src/analyze.c", "src/func.c", "src/wherecode.c", "src/whereexpr.c", "src/whereInt.h", "src/alter.c", "src/attach.c", "src/auth.c", "src/build.c", "src/delete.c", "src/expr.c", "src/insert.c", "src/pragma.c", "src/pragma.h", "src/select.c", "src/trigger.c", "src/update.c", "src/vacuum.c", "src/walker.c", "src/where.c", "opcodes.c", "opcodes.h", "src/sqlcipher.h", "sqlite3.h", "ext/rbu/sqlite3rbu.c", "ext/rbu/sqlite3rbu.h", "ext/userauth/sqlite3userauth.h", "ext/misu/json1.c", "ext/icu/icu.c", "ext/icu/sqliteicu.h", "src/global.c", "src/ctime.c", "src/hwtime.h", "src/date.c", "src/dbstat.c", "src/fault.c", "src/fkey.c", "src/sqliteInt.h", "src/sqliteLimit.h", "src/sqlite3ext.h", "src/hash.c", "src/hash.h", "src/printf.c", "src/random.c", "src/utf.c", "src/util.c", "src/crypto_cc.c", "src/crypto_impl.c", "src/crypto_libtomcrypt.c", "src/crypto.c", "src/crypto.h", "src/vdbe.c", "src/vdbe.h", "src/vdbeaux.c", "src/vdbeblob.c", "src/vdbeInt.h", "src/vdbemem.c", "src/vdbesort.c", "src/vdbetrace.c", "src/msvc.h", "src/vxworks.h", "ext/fts3/fts3_tokenizer.h", "keywordhash.h" + sqlcipher.ios.deployment_target = "8.0" + sqlcipher.osx.deployment_target = "10.9" + sqlcipher.watchos.deployment_target = "2.0" + sqlcipher.tvos.deployment_target = "9.0" + sqlcipher.frameworks = "Security", "Foundation" + sqlcipher.requires_arc = false + sqlcipher.prepare_command = "make -f Makefile.preprocessed;" + sqlcipher.xcconfig = { + "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_API_ARMOR SQLITE_OMIT_BUILTIN_TEST SQLITE_OMIT_AUTORESET SQLITE_ENABLE_UPDATE_DELETE_LIMIT SQLITE_ENABLE_RTREE SQLITE_ENABLE_LOCKING_STYLE=1 SQLITE_SYSTEM_MALLOC SQLITE_OMIT_LOAD_EXTENSION SQLITE_CORE SQLITE_THREADSAFE=2 SQLITE_DEFAULT_CACHE_SIZE=250 SQLITE_DEFAULT_CKPTFULLFSYNC=1 SQLITE_DEFAULT_PAGE_SIZE=4096 SQLITE_OMIT_SHARED_CACHE SQLITE_HAS_CODEC SQLCIPHER_CRYPTO_CC USE_PREAD=1 SQLITE_TEMP_STORE=2 SQLCIPHER_PREPROCESSED HAVE_USLEEP SQLITE_MALLOC_SOFT_LIMIT=0 SQLITE_WCDB_SIGNAL_RETRY=1 SQLITE_DEFAULT_MEMSTATUS=0 SQLITE_ENABLE_COLUMN_METADATA SQLITE_DEFAULT_WAL_SYNCHRONOUS=1 SQLITE_LIKE_DOESNT_MATCH_BLOBS SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_DEPRECATED SQLITE_OMIT_PROGRESS_CALLBACK SQLITE_OMIT_SHARED_CACHE OMIT_CONSTTIME_MEM OMIT_MEMLOCK", + "CLANG_WARN_CONSTANT_CONVERSION" => "YES", + "GCC_WARN_64_TO_32_BIT_CONVERSION" => "NO", + "CLANG_WARN_UNREACHABLE_CODE" => "NO", + "GCC_WARN_UNUSED_FUNCTION" => "NO", + "GCC_WARN_UNUSED_VARIABLE" => "NO", + "CLANG_WARN_COMMA" => "NO", + "CLANG_WARN_STRICT_PROTOTYPES" => "NO", + } +end From 90942f4ca3208ccbe5051cf6822309c7e6a478de Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 24 Jan 2018 10:33:57 +0800 Subject: [PATCH 75/94] Rename sqlcipher.podspec to WCDBOptimizedSQLCipher.podspec in comment --- WCDBOptimizedSQLCipher.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WCDBOptimizedSQLCipher.podspec b/WCDBOptimizedSQLCipher.podspec index e2c652dfdb..eed186512b 100644 --- a/WCDBOptimizedSQLCipher.podspec +++ b/WCDBOptimizedSQLCipher.podspec @@ -1,5 +1,5 @@ -# pod lib lint sqlcipher.podspec --verbose --allow-warnings -# pod trunk push sqlcipher.podspec --verbose --allow-warnings +# pod lib lint WCDBOptimizedSQLCipher.podspec --verbose --allow-warnings +# pod trunk push WCDBOptimizedSQLCipher.podspec --verbose --allow-warnings Pod::Spec.new do |sqlcipher| sqlcipher.name = "WCDBOptimizedSQLCipher" sqlcipher.version = "1.1.0" From f6cc95dac5393fde2ca8a0e7adeeca442c083a40 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 18 Apr 2018 17:12:33 +0800 Subject: [PATCH 76/94] Set mach-o to static --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 9e2862b5bc..0c8a9e2094 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -881,6 +881,7 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_NAME = sqlcipher; @@ -903,6 +904,7 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_NAME = sqlcipher; From 5224a99f5c5f74b5c4a23deaff15af7229244255 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 19 Apr 2018 12:08:54 +0800 Subject: [PATCH 77/94] Update macho-o type --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 0c8a9e2094..9e2862b5bc 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -881,7 +881,6 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = staticlib; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_NAME = sqlcipher; @@ -904,7 +903,6 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = staticlib; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_NAME = sqlcipher; From 06448106258ce49df36f2cd6f2c487b7ef6e3f01 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Thu, 19 Apr 2018 15:52:18 +0800 Subject: [PATCH 78/94] A seperated target for testing --- .../project.pbxproj | 327 ++++++++++++++++++ .../xcshareddata/xcschemes/sqlcipher.xcscheme | 82 ----- 2 files changed, 327 insertions(+), 82 deletions(-) delete mode 100644 sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 9e2862b5bc..a269c61d3f 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -110,6 +110,109 @@ 2384AB4E1EDBFDE0007369FF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; 23E737C71FB1689500EEBC3D /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA3CF1FB082C70075F021 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23E737C81FB1689A00EEBC3D /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA34A1FB070F00075F021 /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 23F5BBD320887FAB000CCD37 /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BB1FB082A80075F021 /* auth.c */; }; + 23F5BBD420887FAB000CCD37 /* vdbetrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3DC1FB083670075F021 /* vdbetrace.c */; }; + 23F5BBD520887FAB000CCD37 /* status.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3631FB071310075F021 /* status.c */; }; + 23F5BBD620887FAB000CCD37 /* rowset.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3251FB070180075F021 /* rowset.c */; }; + 23F5BBD720887FAB000CCD37 /* trigger.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BA1FB082A80075F021 /* trigger.c */; }; + 23F5BBD820887FAB000CCD37 /* analyze.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A51FB082380075F021 /* analyze.c */; }; + 23F5BBD920887FAB000CCD37 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A21FB0822A0075F021 /* parse.c */; }; + 23F5BBDA20887FAB000CCD37 /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E71FB0836A0075F021 /* date.c */; }; + 23F5BBDB20887FAB000CCD37 /* fts3_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA34B1FB070F10075F021 /* fts3_unicode.c */; }; + 23F5BBDC20887FAB000CCD37 /* mutex_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3871FB071870075F021 /* mutex_wcdb.c */; }; + 23F5BBDD20887FAB000CCD37 /* sqlite3rbu.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D11FB082DA0075F021 /* sqlite3rbu.c */; }; + 23F5BBDE20887FAB000CCD37 /* fts3_tokenizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3451FB070EF0075F021 /* fts3_tokenizer.c */; }; + 23F5BBDF20887FAB000CCD37 /* fts3_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3491FB070F00075F021 /* fts3_write.c */; }; + 23F5BBE020887FAB000CCD37 /* mem3.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3691FB071450075F021 /* mem3.c */; }; + 23F5BBE120887FAB000CCD37 /* fault.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3F41FB0836E0075F021 /* fault.c */; }; + 23F5BBE220887FAB000CCD37 /* wal.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3601FB071290075F021 /* wal.c */; }; + 23F5BBE320887FAB000CCD37 /* fts3_porter.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA33F1FB070D60075F021 /* fts3_porter.c */; }; + 23F5BBE420887FAB000CCD37 /* memjournal.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3761FB0716A0075F021 /* memjournal.c */; }; + 23F5BBE520887FAB000CCD37 /* os_wcdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA37E1FB071780075F021 /* os_wcdb.c */; }; + 23F5BBE620887FAB000CCD37 /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA38A1FB0718E0075F021 /* os.c */; }; + 23F5BBE720887FAB000CCD37 /* vdbeaux.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D91FB083660075F021 /* vdbeaux.c */; }; + 23F5BBE820887FAB000CCD37 /* mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3751FB0716A0075F021 /* mutex.c */; }; + 23F5BBE920887FAB000CCD37 /* mem0.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3671FB071440075F021 /* mem0.c */; }; + 23F5BBEA20887FAB000CCD37 /* crypto_libtomcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E01FB083680075F021 /* crypto_libtomcrypt.c */; }; + 23F5BBEB20887FAB000CCD37 /* vacuum.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B51FB082A60075F021 /* vacuum.c */; }; + 23F5BBEC20887FAB000CCD37 /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E31FB083690075F021 /* hash.c */; }; + 23F5BBED20887FAB000CCD37 /* complete.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA39C1FB081F90075F021 /* complete.c */; }; + 23F5BBEE20887FAB000CCD37 /* fkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E61FB0836A0075F021 /* fkey.c */; }; + 23F5BBEF20887FAB000CCD37 /* vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA32B1FB070530075F021 /* vtab.c */; }; + 23F5BBF020887FAB000CCD37 /* expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B41FB082A60075F021 /* expr.c */; }; + 23F5BBF120887FAB000CCD37 /* rtree.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3991FB081D90075F021 /* rtree.c */; }; + 23F5BBF220887FAB000CCD37 /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA35E1FB071230075F021 /* table.c */; }; + 23F5BBF320887FAB000CCD37 /* wherecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3AA1FB0824C0075F021 /* wherecode.c */; }; + 23F5BBF420887FAB000CCD37 /* fts3_icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA33D1FB070CD0075F021 /* fts3_icu.c */; }; + 23F5BBF520887FAB000CCD37 /* vdbeblob.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3ED1FB0836C0075F021 /* vdbeblob.c */; }; + 23F5BBF620887FAB000CCD37 /* vdbeapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA35C1FB0711D0075F021 /* vdbeapi.c */; }; + 23F5BBF720887FAB000CCD37 /* walker.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BF1FB082A90075F021 /* walker.c */; }; + 23F5BBF820887FAB000CCD37 /* fts3_unicode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA34C1FB070F10075F021 /* fts3_unicode2.c */; }; + 23F5BBF920887FAB000CCD37 /* mutex_noop.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3771FB0716A0075F021 /* mutex_noop.c */; }; + 23F5BBFA20887FAB000CCD37 /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A71FB0823F0075F021 /* func.c */; }; + 23F5BBFB20887FAB000CCD37 /* fts3_aux.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3361FB070BB0075F021 /* fts3_aux.c */; }; + 23F5BBFC20887FAB000CCD37 /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3291FB0703C0075F021 /* userauth.c */; }; + 23F5BBFD20887FAB000CCD37 /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA36A1FB071450075F021 /* malloc.c */; }; + 23F5BBFE20887FAB000CCD37 /* insert.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BE1FB082A90075F021 /* insert.c */; }; + 23F5BBFF20887FAB000CCD37 /* pcache.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3931FB071AB0075F021 /* pcache.c */; }; + 23F5BC0020887FAB000CCD37 /* dbstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3EA1FB0836B0075F021 /* dbstat.c */; }; + 23F5BC0120887FAB000CCD37 /* fts3_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA33B1FB070C50075F021 /* fts3_hash.c */; }; + 23F5BC0220887FAB000CCD37 /* where.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3AE1FB082530075F021 /* where.c */; }; + 23F5BC0320887FAB000CCD37 /* alter.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B01FB0825E0075F021 /* alter.c */; }; + 23F5BC0420887FAB000CCD37 /* treeview.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3271FB070210075F021 /* treeview.c */; }; + 23F5BC0520887FAB000CCD37 /* fts3_tokenize_vtab.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3431FB070EF0075F021 /* fts3_tokenize_vtab.c */; }; + 23F5BC0620887FAB000CCD37 /* fts3_snippet.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3411FB070DA0075F021 /* fts3_snippet.c */; }; + 23F5BC0720887FAB000CCD37 /* pragma.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B81FB082A70075F021 /* pragma.c */; }; + 23F5BC0820887FAB000CCD37 /* whereexpr.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3AB1FB0824C0075F021 /* whereexpr.c */; }; + 23F5BC0920887FAB000CCD37 /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B11FB0825E0075F021 /* attach.c */; }; + 23F5BC0A20887FAB000CCD37 /* mem2.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA36B1FB071460075F021 /* mem2.c */; }; + 23F5BC0B20887FAB000CCD37 /* pcache1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3951FB071AB0075F021 /* pcache1.c */; }; + 23F5BC0C20887FAB000CCD37 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3581FB0710C0075F021 /* main.c */; }; + 23F5BC0D20887FAB000CCD37 /* icu.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D61FB082FA0075F021 /* icu.c */; }; + 23F5BC0E20887FAB000CCD37 /* loadext.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3231FB070110075F021 /* loadext.c */; }; + 23F5BC0F20887FAB000CCD37 /* vdbemem.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3EB1FB0836B0075F021 /* vdbemem.c */; }; + 23F5BC1020887FAB000CCD37 /* utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3DE1FB083680075F021 /* utf.c */; }; + 23F5BC1120887FAB000CCD37 /* callback.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3211FB070090075F021 /* callback.c */; }; + 23F5BC1220887FAB000CCD37 /* fts3_expr.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3381FB070C00075F021 /* fts3_expr.c */; }; + 23F5BC1320887FAB000CCD37 /* tokenize.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA39E1FB082030075F021 /* tokenize.c */; }; + 23F5BC1420887FAB000CCD37 /* pager.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3901FB071A60075F021 /* pager.c */; }; + 23F5BC1520887FAB000CCD37 /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3841FB0717D0075F021 /* queue.c */; }; + 23F5BC1620887FAB000CCD37 /* update.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BC1FB082A80075F021 /* update.c */; }; + 23F5BC1720887FAB000CCD37 /* ctime.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E51FB083690075F021 /* ctime.c */; }; + 23F5BC1820887FAB000CCD37 /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3CB1FB082B30075F021 /* opcodes.c */; }; + 23F5BC1920887FAB000CCD37 /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3F01FB0836D0075F021 /* crypto.c */; }; + 23F5BC1A20887FAB000CCD37 /* build.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B91FB082A70075F021 /* build.c */; }; + 23F5BC1B20887FAB000CCD37 /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E81FB0836A0075F021 /* printf.c */; }; + 23F5BC1C20887FAB000CCD37 /* fts3_tokenizer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3461FB070EF0075F021 /* fts3_tokenizer1.c */; }; + 23F5BC1D20887FAB000CCD37 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E21FB083690075F021 /* util.c */; }; + 23F5BC1E20887FAB000CCD37 /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E41FB083690075F021 /* global.c */; }; + 23F5BC1F20887FAB000CCD37 /* legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3561FB071070075F021 /* legacy.c */; }; + 23F5BC2020887FAB000CCD37 /* fts5.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3331FB0708E0075F021 /* fts5.c */; }; + 23F5BC2120887FAB000CCD37 /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3B61FB082A70075F021 /* select.c */; }; + 23F5BC2220887FAB000CCD37 /* crypto_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E11FB083680075F021 /* crypto_impl.c */; }; + 23F5BC2320887FAB000CCD37 /* btmutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA32D1FB070640075F021 /* btmutex.c */; }; + 23F5BC2420887FAB000CCD37 /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA35A1FB071110075F021 /* notify.c */; }; + 23F5BC2520887FAB000CCD37 /* json1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3D41FB082F30075F021 /* json1.c */; }; + 23F5BC2620887FAB000CCD37 /* mem1.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3681FB071450075F021 /* mem1.c */; }; + 23F5BC2720887FAB000CCD37 /* mem5.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA36C1FB071460075F021 /* mem5.c */; }; + 23F5BC2820887FAB000CCD37 /* vdbe.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3DF1FB083680075F021 /* vdbe.c */; }; + 23F5BC2920887FAB000CCD37 /* delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3BD1FB082A80075F021 /* delete.c */; }; + 23F5BC2A20887FAB000CCD37 /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3A01FB082090075F021 /* resolve.c */; }; + 23F5BC2B20887FAB000CCD37 /* crypto_cc.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3F31FB0836E0075F021 /* crypto_cc.c */; }; + 23F5BC2C20887FAB000CCD37 /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA38C1FB071970075F021 /* threads.c */; }; + 23F5BC2D20887FAB000CCD37 /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3E91FB0836B0075F021 /* random.c */; }; + 23F5BC2E20887FAB000CCD37 /* prepare.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3651FB071380075F021 /* prepare.c */; }; + 23F5BC2F20887FAB000CCD37 /* os_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA37F1FB071780075F021 /* os_unix.c */; }; + 23F5BC3020887FAB000CCD37 /* vdbesort.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3EF1FB0836C0075F021 /* vdbesort.c */; }; + 23F5BC3120887FAB000CCD37 /* bitvec.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA38E1FB0719E0075F021 /* bitvec.c */; }; + 23F5BC3220887FAB000CCD37 /* fts3.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3481FB070F00075F021 /* fts3.c */; }; + 23F5BC3320887FAB000CCD37 /* btree.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA32F1FB0706B0075F021 /* btree.c */; }; + 23F5BC3420887FAB000CCD37 /* mutex_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3731FB071690075F021 /* mutex_unix.c */; }; + 23F5BC3520887FAB000CCD37 /* backup.c in Sources */ = {isa = PBXBuildFile; fileRef = 232DA3541FB071020075F021 /* backup.c */; }; + 23F5BC3720887FAB000CCD37 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23121C071E6FFA890012B45E /* Security.framework */; }; + 23F5BC3820887FAB000CCD37 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2384AB4C1EDBFD48007369FF /* CoreFoundation.framework */; }; + 23F5BC3A20887FAB000CCD37 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA34A1FB070F00075F021 /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 23F5BC3B20887FAB000CCD37 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA3CF1FB082C70075F021 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -120,6 +223,13 @@ remoteGlobalIDString = 23E737C91FB168B500EEBC3D; remoteInfo = preprocess; }; + 23F5BBD120887FAB000CCD37 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 23E737C91FB168B500EEBC3D; + remoteInfo = preprocess; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -266,6 +376,7 @@ 2384AB511EDBFDF7007369FF /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = usr/lib/system/libcorecrypto.tbd; sourceTree = SDKROOT; }; 239325C81E836A7700D677CC /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 239D64E61ECE9FE8008F5B61 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 23F5BC4020887FAB000CCD37 /* sqlcipher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = sqlcipher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -278,6 +389,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 23F5BC3620887FAB000CCD37 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 23F5BC3720887FAB000CCD37 /* Security.framework in Frameworks */, + 23F5BC3820887FAB000CCD37 /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -295,6 +415,7 @@ isa = PBXGroup; children = ( 239325C81E836A7700D677CC /* sqlcipher.framework */, + 23F5BC4020887FAB000CCD37 /* sqlcipher.framework */, ); name = Products; sourceTree = ""; @@ -474,6 +595,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 23F5BC3920887FAB000CCD37 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 23F5BC3A20887FAB000CCD37 /* fts3_tokenizer.h in Headers */, + 23F5BC3B20887FAB000CCD37 /* sqlite3.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXLegacyTarget section */ @@ -513,6 +643,25 @@ productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; }; + 23F5BBCF20887FAB000CCD37 /* sqlcipher static */ = { + isa = PBXNativeTarget; + buildConfigurationList = 23F5BC3D20887FAB000CCD37 /* Build configuration list for PBXNativeTarget "sqlcipher static" */; + buildPhases = ( + 23F5BBD220887FAB000CCD37 /* Sources */, + 23F5BC3620887FAB000CCD37 /* Frameworks */, + 23F5BC3920887FAB000CCD37 /* Headers */, + 23F5BC3C20887FAB000CCD37 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 23F5BBD020887FAB000CCD37 /* PBXTargetDependency */, + ); + name = "sqlcipher static"; + productName = sqlcipher; + productReference = 23F5BC4020887FAB000CCD37 /* sqlcipher.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -545,6 +694,7 @@ projectRoot = ""; targets = ( 239325C71E836A7700D677CC /* sqlcipher */, + 23F5BBCF20887FAB000CCD37 /* sqlcipher static */, 23E737C91FB168B500EEBC3D /* preprocess */, ); }; @@ -558,6 +708,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 23F5BC3C20887FAB000CCD37 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -667,6 +824,112 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 23F5BBD220887FAB000CCD37 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 23F5BBD320887FAB000CCD37 /* auth.c in Sources */, + 23F5BBD420887FAB000CCD37 /* vdbetrace.c in Sources */, + 23F5BBD520887FAB000CCD37 /* status.c in Sources */, + 23F5BBD620887FAB000CCD37 /* rowset.c in Sources */, + 23F5BBD720887FAB000CCD37 /* trigger.c in Sources */, + 23F5BBD820887FAB000CCD37 /* analyze.c in Sources */, + 23F5BBD920887FAB000CCD37 /* parse.c in Sources */, + 23F5BBDA20887FAB000CCD37 /* date.c in Sources */, + 23F5BBDB20887FAB000CCD37 /* fts3_unicode.c in Sources */, + 23F5BBDC20887FAB000CCD37 /* mutex_wcdb.c in Sources */, + 23F5BBDD20887FAB000CCD37 /* sqlite3rbu.c in Sources */, + 23F5BBDE20887FAB000CCD37 /* fts3_tokenizer.c in Sources */, + 23F5BBDF20887FAB000CCD37 /* fts3_write.c in Sources */, + 23F5BBE020887FAB000CCD37 /* mem3.c in Sources */, + 23F5BBE120887FAB000CCD37 /* fault.c in Sources */, + 23F5BBE220887FAB000CCD37 /* wal.c in Sources */, + 23F5BBE320887FAB000CCD37 /* fts3_porter.c in Sources */, + 23F5BBE420887FAB000CCD37 /* memjournal.c in Sources */, + 23F5BBE520887FAB000CCD37 /* os_wcdb.c in Sources */, + 23F5BBE620887FAB000CCD37 /* os.c in Sources */, + 23F5BBE720887FAB000CCD37 /* vdbeaux.c in Sources */, + 23F5BBE820887FAB000CCD37 /* mutex.c in Sources */, + 23F5BBE920887FAB000CCD37 /* mem0.c in Sources */, + 23F5BBEA20887FAB000CCD37 /* crypto_libtomcrypt.c in Sources */, + 23F5BBEB20887FAB000CCD37 /* vacuum.c in Sources */, + 23F5BBEC20887FAB000CCD37 /* hash.c in Sources */, + 23F5BBED20887FAB000CCD37 /* complete.c in Sources */, + 23F5BBEE20887FAB000CCD37 /* fkey.c in Sources */, + 23F5BBEF20887FAB000CCD37 /* vtab.c in Sources */, + 23F5BBF020887FAB000CCD37 /* expr.c in Sources */, + 23F5BBF120887FAB000CCD37 /* rtree.c in Sources */, + 23F5BBF220887FAB000CCD37 /* table.c in Sources */, + 23F5BBF320887FAB000CCD37 /* wherecode.c in Sources */, + 23F5BBF420887FAB000CCD37 /* fts3_icu.c in Sources */, + 23F5BBF520887FAB000CCD37 /* vdbeblob.c in Sources */, + 23F5BBF620887FAB000CCD37 /* vdbeapi.c in Sources */, + 23F5BBF720887FAB000CCD37 /* walker.c in Sources */, + 23F5BBF820887FAB000CCD37 /* fts3_unicode2.c in Sources */, + 23F5BBF920887FAB000CCD37 /* mutex_noop.c in Sources */, + 23F5BBFA20887FAB000CCD37 /* func.c in Sources */, + 23F5BBFB20887FAB000CCD37 /* fts3_aux.c in Sources */, + 23F5BBFC20887FAB000CCD37 /* userauth.c in Sources */, + 23F5BBFD20887FAB000CCD37 /* malloc.c in Sources */, + 23F5BBFE20887FAB000CCD37 /* insert.c in Sources */, + 23F5BBFF20887FAB000CCD37 /* pcache.c in Sources */, + 23F5BC0020887FAB000CCD37 /* dbstat.c in Sources */, + 23F5BC0120887FAB000CCD37 /* fts3_hash.c in Sources */, + 23F5BC0220887FAB000CCD37 /* where.c in Sources */, + 23F5BC0320887FAB000CCD37 /* alter.c in Sources */, + 23F5BC0420887FAB000CCD37 /* treeview.c in Sources */, + 23F5BC0520887FAB000CCD37 /* fts3_tokenize_vtab.c in Sources */, + 23F5BC0620887FAB000CCD37 /* fts3_snippet.c in Sources */, + 23F5BC0720887FAB000CCD37 /* pragma.c in Sources */, + 23F5BC0820887FAB000CCD37 /* whereexpr.c in Sources */, + 23F5BC0920887FAB000CCD37 /* attach.c in Sources */, + 23F5BC0A20887FAB000CCD37 /* mem2.c in Sources */, + 23F5BC0B20887FAB000CCD37 /* pcache1.c in Sources */, + 23F5BC0C20887FAB000CCD37 /* main.c in Sources */, + 23F5BC0D20887FAB000CCD37 /* icu.c in Sources */, + 23F5BC0E20887FAB000CCD37 /* loadext.c in Sources */, + 23F5BC0F20887FAB000CCD37 /* vdbemem.c in Sources */, + 23F5BC1020887FAB000CCD37 /* utf.c in Sources */, + 23F5BC1120887FAB000CCD37 /* callback.c in Sources */, + 23F5BC1220887FAB000CCD37 /* fts3_expr.c in Sources */, + 23F5BC1320887FAB000CCD37 /* tokenize.c in Sources */, + 23F5BC1420887FAB000CCD37 /* pager.c in Sources */, + 23F5BC1520887FAB000CCD37 /* queue.c in Sources */, + 23F5BC1620887FAB000CCD37 /* update.c in Sources */, + 23F5BC1720887FAB000CCD37 /* ctime.c in Sources */, + 23F5BC1820887FAB000CCD37 /* opcodes.c in Sources */, + 23F5BC1920887FAB000CCD37 /* crypto.c in Sources */, + 23F5BC1A20887FAB000CCD37 /* build.c in Sources */, + 23F5BC1B20887FAB000CCD37 /* printf.c in Sources */, + 23F5BC1C20887FAB000CCD37 /* fts3_tokenizer1.c in Sources */, + 23F5BC1D20887FAB000CCD37 /* util.c in Sources */, + 23F5BC1E20887FAB000CCD37 /* global.c in Sources */, + 23F5BC1F20887FAB000CCD37 /* legacy.c in Sources */, + 23F5BC2020887FAB000CCD37 /* fts5.c in Sources */, + 23F5BC2120887FAB000CCD37 /* select.c in Sources */, + 23F5BC2220887FAB000CCD37 /* crypto_impl.c in Sources */, + 23F5BC2320887FAB000CCD37 /* btmutex.c in Sources */, + 23F5BC2420887FAB000CCD37 /* notify.c in Sources */, + 23F5BC2520887FAB000CCD37 /* json1.c in Sources */, + 23F5BC2620887FAB000CCD37 /* mem1.c in Sources */, + 23F5BC2720887FAB000CCD37 /* mem5.c in Sources */, + 23F5BC2820887FAB000CCD37 /* vdbe.c in Sources */, + 23F5BC2920887FAB000CCD37 /* delete.c in Sources */, + 23F5BC2A20887FAB000CCD37 /* resolve.c in Sources */, + 23F5BC2B20887FAB000CCD37 /* crypto_cc.c in Sources */, + 23F5BC2C20887FAB000CCD37 /* threads.c in Sources */, + 23F5BC2D20887FAB000CCD37 /* random.c in Sources */, + 23F5BC2E20887FAB000CCD37 /* prepare.c in Sources */, + 23F5BC2F20887FAB000CCD37 /* os_unix.c in Sources */, + 23F5BC3020887FAB000CCD37 /* vdbesort.c in Sources */, + 23F5BC3120887FAB000CCD37 /* bitvec.c in Sources */, + 23F5BC3220887FAB000CCD37 /* fts3.c in Sources */, + 23F5BC3320887FAB000CCD37 /* btree.c in Sources */, + 23F5BC3420887FAB000CCD37 /* mutex_unix.c in Sources */, + 23F5BC3520887FAB000CCD37 /* backup.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -675,6 +938,11 @@ target = 23E737C91FB168B500EEBC3D /* preprocess */; targetProxy = 23E737CD1FB1693400EEBC3D /* PBXContainerItemProxy */; }; + 23F5BBD020887FAB000CCD37 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 23E737C91FB168B500EEBC3D /* preprocess */; + targetProxy = 23F5BBD120887FAB000CCD37 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -883,6 +1151,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -905,6 +1174,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -969,6 +1239,54 @@ }; name = Release; }; + 23F5BC3E20887FAB000CCD37 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_MODULE_NAME = sqlcipher; + PRODUCT_NAME = sqlcipher; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 23F5BC3F20887FAB000CCD37 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_MODULE_NAME = sqlcipher; + PRODUCT_NAME = sqlcipher; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -999,6 +1317,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 23F5BC3D20887FAB000CCD37 /* Build configuration list for PBXNativeTarget "sqlcipher static" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23F5BC3E20887FAB000CCD37 /* Debug */, + 23F5BC3F20887FAB000CCD37 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 23121ADC1E6FF9110012B45E /* Project object */; diff --git a/sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme b/sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme deleted file mode 100644 index 4e7fd57850..0000000000 --- a/sqlcipher.preprocessed.xcodeproj/xcshareddata/xcschemes/sqlcipher.xcscheme +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From e60fd4462179ca605aefef141d20bf82c31becbf Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 20 Apr 2018 20:57:55 +0800 Subject: [PATCH 79/94] Force disable bitcode --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index a269c61d3f..cfdf7f4071 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1145,6 +1145,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1168,6 +1169,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1248,6 +1250,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1272,6 +1275,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From 3bef01f4607617bec469172338887af21770fc13 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Fri, 20 Apr 2018 21:04:09 +0800 Subject: [PATCH 80/94] Strip non global --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index cfdf7f4071..77f9cb5a52 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1142,6 +1142,7 @@ CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; + DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1155,6 +1156,8 @@ PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1166,6 +1169,7 @@ CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; + DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1179,6 +1183,8 @@ PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From 9dfd356a66f12edb9947def71f9b4646c3de077f Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 10:40:03 +0800 Subject: [PATCH 81/94] Tests for opti size --- .../project.pbxproj | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 77f9cb5a52..8909b8c9fa 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1253,6 +1253,8 @@ CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1262,11 +1264,16 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "-fno-profile-instr-generate", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1278,6 +1285,8 @@ CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1287,11 +1296,16 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "-fno-profile-instr-generate", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From 5fcaafb0dd86e8b8b5497ba21034eba0d791f10a Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 17:41:13 +0800 Subject: [PATCH 82/94] Revert "Tests for opti size" This reverts commit 9dfd356a66f12edb9947def71f9b4646c3de077f. --- .../project.pbxproj | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 8909b8c9fa..77f9cb5a52 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1253,8 +1253,6 @@ CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1264,16 +1262,11 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; - OTHER_CFLAGS = ( - "-Wno-shorten-64-to-32", - "-fno-profile-instr-generate", - ); + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; - STRIP_INSTALLED_PRODUCT = YES; - STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1285,8 +1278,6 @@ CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1296,16 +1287,11 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; - OTHER_CFLAGS = ( - "-Wno-shorten-64-to-32", - "-fno-profile-instr-generate", - ); + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; - STRIP_INSTALLED_PRODUCT = YES; - STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From 6fe3ee080faa791e4308cdd657aaea166641a2b3 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 18:02:06 +0800 Subject: [PATCH 83/94] Accept no code coverage and no profile generate --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 77f9cb5a52..01706aa5de 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1250,6 +1250,7 @@ 23F5BC3E20887FAB000CCD37 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -1262,7 +1263,10 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "-fno-profile-instr-generate", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; @@ -1275,6 +1279,7 @@ 23F5BC3F20887FAB000CCD37 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -1287,7 +1292,10 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "-fno-profile-instr-generate", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; From ee856b2f70a1de5949d40e0e12bb58d9f6f25d84 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 22:59:18 +0800 Subject: [PATCH 84/94] Strip symbol and revert bitcode --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 01706aa5de..0c8e48d846 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1253,11 +1253,14 @@ CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; + ENABLE_BITCODE = YES; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1271,6 +1274,8 @@ PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1282,11 +1287,14 @@ CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; + ENABLE_BITCODE = YES; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1300,6 +1308,8 @@ PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From 82134e5a2879e6ea5c78f0f7a4b583fe9f49f24e Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 23:03:32 +0800 Subject: [PATCH 85/94] Target renaming --- .../project.pbxproj | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 0c8e48d846..de5815045a 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -624,9 +624,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 239325C71E836A7700D677CC /* sqlcipher */ = { + 239325C71E836A7700D677CC /* sqlcipher for Test */ = { isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Test" */; buildPhases = ( 239325C31E836A7700D677CC /* Sources */, 239325C41E836A7700D677CC /* Frameworks */, @@ -638,14 +638,14 @@ dependencies = ( 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */, ); - name = sqlcipher; + name = "sqlcipher for Test"; productName = sqlcipher; productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; }; - 23F5BBCF20887FAB000CCD37 /* sqlcipher static */ = { + 23F5BBCF20887FAB000CCD37 /* sqlcipher */ = { isa = PBXNativeTarget; - buildConfigurationList = 23F5BC3D20887FAB000CCD37 /* Build configuration list for PBXNativeTarget "sqlcipher static" */; + buildConfigurationList = 23F5BC3D20887FAB000CCD37 /* Build configuration list for PBXNativeTarget "sqlcipher" */; buildPhases = ( 23F5BBD220887FAB000CCD37 /* Sources */, 23F5BC3620887FAB000CCD37 /* Frameworks */, @@ -657,7 +657,7 @@ dependencies = ( 23F5BBD020887FAB000CCD37 /* PBXTargetDependency */, ); - name = "sqlcipher static"; + name = sqlcipher; productName = sqlcipher; productReference = 23F5BC4020887FAB000CCD37 /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; @@ -693,8 +693,8 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 239325C71E836A7700D677CC /* sqlcipher */, - 23F5BBCF20887FAB000CCD37 /* sqlcipher static */, + 23F5BBCF20887FAB000CCD37 /* sqlcipher */, + 239325C71E836A7700D677CC /* sqlcipher for Test */, 23E737C91FB168B500EEBC3D /* preprocess */, ); }; @@ -1327,7 +1327,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Test" */ = { isa = XCConfigurationList; buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, @@ -1345,7 +1345,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 23F5BC3D20887FAB000CCD37 /* Build configuration list for PBXNativeTarget "sqlcipher static" */ = { + 23F5BC3D20887FAB000CCD37 /* Build configuration list for PBXNativeTarget "sqlcipher" */ = { isa = XCConfigurationList; buildConfigurations = ( 23F5BC3E20887FAB000CCD37 /* Debug */, From 3fe52ef68dd160701c0cdc7d05bb4bd6e8e1095b Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 23:05:24 +0800 Subject: [PATCH 86/94] Addtion configuration for non-bitcode --- .../project.pbxproj | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index de5815045a..e77dc2c3c2 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1190,6 +1190,185 @@ }; name = Release; }; + 23A2C8B8208CDBDF00C6BB6B /* WithoutBitcode */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "ARCHS[sdk=iphoneos*]" = ( + "$(ARCHS_STANDARD)", + armv7, + arm64, + ); + "ARCHS[sdk=iphonesimulator*]" = ( + "$(ARCHS_STANDARD)", + armv7, + arm64, + ); + "ARCHS[sdk=macosx*]" = ( + "$(ARCHS_STANDARD)", + x86_64, + ); + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + SQLITE_ENABLE_FTS3, + SQLITE_ENABLE_FTS3_PARENTHESIS, + SQLITE_ENABLE_API_ARMOR, + "$(inherited)", + SQLITE_ENABLE_RTREE, + "SQLITE_ENABLE_LOCKING_STYLE=1", + SQLITE_OMIT_LOAD_EXTENSION, + SQLITE_OMIT_BUILTIN_TEST, + SQLITE_OMIT_SHARED_CACHE, + SQLITE_OMIT_AUTORESET, + SQLITE_ENABLE_UPDATE_DELETE_LIMIT, + SQLITE_SYSTEM_MALLOC, + "SQLITE_THREADSAFE=2", + "SQLITE_DEFAULT_PAGE_SIZE=4096", + "SQLITE_DEFAULT_CACHE_SIZE=-2000", + SQLITE_CORE, + SQLITE_HAS_CODEC, + "SQLITE_TEMP_STORE=2", + SQLCIPHER_CRYPTO_CC, + "USE_PREAD=1", + SQLCIPHER_PREPROCESSED, + HAVE_USLEEP, + "SQLITE_MALLOC_SOFT_LIMIT=0", + "SQLITE_WCDB_SIGNAL_RETRY=1", + "SQLITE_DEFAULT_MEMSTATUS=0", + "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", + SQLITE_LIKE_DOESNT_MATCH_BLOBS, + "SQLITE_MAX_EXPR_DEPTH=0", + SQLITE_OMIT_DEPRECATED, + SQLITE_OMIT_PROGRESS_CALLBACK, + SQLITE_OMIT_SHARED_CACHE, + SQLITE_ENABLE_COLUMN_METADATA, + OMIT_CONSTTIME_MEM, + OMIT_MEMLOCK, + SQLITE_ENABLE_FTS3_TOKENIZER, + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALID_ARCHS = "x86_64 armv7 arm64"; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = WithoutBitcode; + }; + 23A2C8B9208CDBDF00C6BB6B /* WithoutBitcode */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_CODE_COVERAGE = NO; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEPLOYMENT_POSTPROCESSING = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "-fno-profile-instr-generate", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_MODULE_NAME = sqlcipher; + PRODUCT_NAME = sqlcipher; + SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = WithoutBitcode; + }; + 23A2C8BA208CDBDF00C6BB6B /* WithoutBitcode */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEPLOYMENT_POSTPROCESSING = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; + PRODUCT_MODULE_NAME = sqlcipher; + PRODUCT_NAME = sqlcipher; + SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = YES; + STRIP_STYLE = "non-global"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = WithoutBitcode; + }; + 23A2C8BB208CDBDF00C6BB6B /* WithoutBitcode */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = WithoutBitcode; + }; 23E737CB1FB168B500EEBC3D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1323,6 +1502,7 @@ buildConfigurations = ( 23121AE61E6FF9110012B45E /* Debug */, 23121AE71E6FF9110012B45E /* Release */, + 23A2C8B8208CDBDF00C6BB6B /* WithoutBitcode */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1332,6 +1512,7 @@ buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, 239325CE1E836A7700D677CC /* Release */, + 23A2C8BA208CDBDF00C6BB6B /* WithoutBitcode */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1341,6 +1522,7 @@ buildConfigurations = ( 23E737CB1FB168B500EEBC3D /* Debug */, 23E737CC1FB168B500EEBC3D /* Release */, + 23A2C8BB208CDBDF00C6BB6B /* WithoutBitcode */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1350,6 +1532,7 @@ buildConfigurations = ( 23F5BC3E20887FAB000CCD37 /* Debug */, 23F5BC3F20887FAB000CCD37 /* Release */, + 23A2C8B9208CDBDF00C6BB6B /* WithoutBitcode */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; From 0d7fa90f585f978bff05736ebe606e08e1d8b342 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Sun, 22 Apr 2018 23:45:27 +0800 Subject: [PATCH 87/94] Target renaming and bitcode iOS only --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index e77dc2c3c2..52837a9c6a 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -624,9 +624,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 239325C71E836A7700D677CC /* sqlcipher for Test */ = { + 239325C71E836A7700D677CC /* sqlcipher for Coverage and Benchmark */ = { isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Test" */; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Coverage and Benchmark" */; buildPhases = ( 239325C31E836A7700D677CC /* Sources */, 239325C41E836A7700D677CC /* Frameworks */, @@ -638,7 +638,7 @@ dependencies = ( 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */, ); - name = "sqlcipher for Test"; + name = "sqlcipher for Coverage and Benchmark"; productName = sqlcipher; productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; @@ -694,7 +694,7 @@ projectRoot = ""; targets = ( 23F5BBCF20887FAB000CCD37 /* sqlcipher */, - 239325C71E836A7700D677CC /* sqlcipher for Test */, + 239325C71E836A7700D677CC /* sqlcipher for Coverage and Benchmark */, 23E737C91FB168B500EEBC3D /* preprocess */, ); }; @@ -1439,7 +1439,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = YES; + ENABLE_BITCODE = NO; + "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1473,7 +1474,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = YES; + ENABLE_BITCODE = NO; + "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1507,7 +1509,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Test" */ = { + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Coverage and Benchmark" */ = { isa = XCConfigurationList; buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, From 34b444d54a751737fd2c360ad0ff9d8ac338a92d Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 23 Apr 2018 11:42:36 +0800 Subject: [PATCH 88/94] Symbol hidden by default --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 52837a9c6a..37c52059a1 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1298,6 +1298,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; @@ -1442,6 +1443,7 @@ ENABLE_BITCODE = NO; "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; @@ -1477,6 +1479,7 @@ ENABLE_BITCODE = NO; "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; From 436e1da8748fc3c989068bf210f34939c0038cf6 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 23 Apr 2018 17:31:40 +0800 Subject: [PATCH 89/94] No strip when debug --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 37c52059a1..13968451af 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1433,17 +1433,17 @@ CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = YES; + COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEPLOYMENT_POSTPROCESSING = YES; + DEAD_CODE_STRIPPING = NO; + DEPLOYMENT_POSTPROCESSING = NO; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; @@ -1456,8 +1456,8 @@ PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; SKIP_INSTALL = YES; - STRIP_INSTALLED_PRODUCT = YES; - STRIP_STYLE = "non-global"; + STRIP_INSTALLED_PRODUCT = NO; + STRIP_STYLE = debugging; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From b24bca354e415830a7b7ecd3f5c7280fd16ccb5f Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 25 Apr 2018 17:49:13 +0800 Subject: [PATCH 90/94] Add -Wglobal-constructor --- .../project.pbxproj | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 13968451af..d0c3d53fcb 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1034,6 +1034,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = "-Wglobal-constructors"; SDKROOT = macosx; STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; @@ -1127,6 +1128,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = "-Wglobal-constructors"; SDKROOT = macosx; STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; @@ -1151,7 +1153,10 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "$(inherited)", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; @@ -1178,7 +1183,10 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "$(inherited)", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; @@ -1274,6 +1282,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = "-Wglobal-constructors"; SDKROOT = macosx; STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator"; @@ -1306,6 +1315,7 @@ OTHER_CFLAGS = ( "-Wno-shorten-64-to-32", "-fno-profile-instr-generate", + "$(inherited)", ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; @@ -1333,7 +1343,10 @@ INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - OTHER_CFLAGS = "-Wno-shorten-64-to-32"; + OTHER_CFLAGS = ( + "-Wno-shorten-64-to-32", + "$(inherited)", + ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; PRODUCT_NAME = sqlcipher; @@ -1451,6 +1464,7 @@ OTHER_CFLAGS = ( "-Wno-shorten-64-to-32", "-fno-profile-instr-generate", + "$(inherited)", ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; @@ -1487,6 +1501,7 @@ OTHER_CFLAGS = ( "-Wno-shorten-64-to-32", "-fno-profile-instr-generate", + "$(inherited)", ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; PRODUCT_MODULE_NAME = sqlcipher; From 16de63ca07473c5603091c4964eb66c781d2ba79 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Tue, 8 May 2018 17:56:11 +0800 Subject: [PATCH 91/94] Enable dbStat Vtab --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index d0c3d53fcb..616a37b780 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -1026,6 +1026,7 @@ OMIT_CONSTTIME_MEM, OMIT_MEMLOCK, SQLITE_ENABLE_FTS3_TOKENIZER, + SQLITE_ENABLE_DBSTAT_VTAB, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -1121,6 +1122,7 @@ OMIT_CONSTTIME_MEM, OMIT_MEMLOCK, SQLITE_ENABLE_FTS3_TOKENIZER, + SQLITE_ENABLE_DBSTAT_VTAB, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -1275,6 +1277,7 @@ OMIT_CONSTTIME_MEM, OMIT_MEMLOCK, SQLITE_ENABLE_FTS3_TOKENIZER, + SQLITE_ENABLE_DBSTAT_VTAB, ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; From efacb9f233752df6a87840b1dc097b88691f9457 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 9 May 2018 16:59:13 +0800 Subject: [PATCH 92/94] Update built setting 1. make code coverage and prfile instr auto 2. rename target --- .../project.pbxproj | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 616a37b780..b12e28ac9a 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -624,9 +624,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 239325C71E836A7700D677CC /* sqlcipher for Coverage and Benchmark */ = { + 239325C71E836A7700D677CC /* sqlcipher for Coverage */ = { isa = PBXNativeTarget; - buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Coverage and Benchmark" */; + buildConfigurationList = 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Coverage" */; buildPhases = ( 239325C31E836A7700D677CC /* Sources */, 239325C41E836A7700D677CC /* Frameworks */, @@ -638,7 +638,7 @@ dependencies = ( 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */, ); - name = "sqlcipher for Coverage and Benchmark"; + name = "sqlcipher for Coverage"; productName = sqlcipher; productReference = 239325C81E836A7700D677CC /* sqlcipher.framework */; productType = "com.apple.product-type.framework"; @@ -694,7 +694,7 @@ projectRoot = ""; targets = ( 23F5BBCF20887FAB000CCD37 /* sqlcipher */, - 239325C71E836A7700D677CC /* sqlcipher for Coverage and Benchmark */, + 239325C71E836A7700D677CC /* sqlcipher for Coverage */, 23E737C91FB168B500EEBC3D /* preprocess */, ); }; @@ -1150,7 +1150,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1180,7 +1179,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1298,7 +1296,6 @@ 23A2C8B9208CDBDF00C6BB6B /* WithoutBitcode */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; @@ -1317,7 +1314,6 @@ MACH_O_TYPE = staticlib; OTHER_CFLAGS = ( "-Wno-shorten-64-to-32", - "-fno-profile-instr-generate", "$(inherited)", ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; @@ -1341,7 +1337,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1446,7 +1441,6 @@ 23F5BC3E20887FAB000CCD37 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; @@ -1466,7 +1460,6 @@ MACH_O_TYPE = staticlib; OTHER_CFLAGS = ( "-Wno-shorten-64-to-32", - "-fno-profile-instr-generate", "$(inherited)", ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; @@ -1483,7 +1476,6 @@ 23F5BC3F20887FAB000CCD37 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_CODE_COVERAGE = NO; CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; @@ -1503,7 +1495,6 @@ MACH_O_TYPE = staticlib; OTHER_CFLAGS = ( "-Wno-shorten-64-to-32", - "-fno-profile-instr-generate", "$(inherited)", ); PRODUCT_BUNDLE_IDENTIFIER = com.Tencent.WCDB.sqlcipher; @@ -1530,7 +1521,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Coverage and Benchmark" */ = { + 239325CF1E836A7700D677CC /* Build configuration list for PBXNativeTarget "sqlcipher for Coverage" */ = { isa = XCConfigurationList; buildConfigurations = ( 239325CD1E836A7700D677CC /* Debug */, From 6dea5c11db9707b83c33ca4b83834ecaa5d119e4 Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Wed, 9 May 2018 20:12:50 +0800 Subject: [PATCH 93/94] Update config for bitcode --- sqlcipher.preprocessed.xcodeproj/project.pbxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index b12e28ac9a..8a21aea117 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -983,6 +983,8 @@ CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_BITCODE = NO; + "ENABLE_BITCODE[sdk=iphoneos*]" = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1082,6 +1084,8 @@ CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_BITCODE = NO; + "ENABLE_BITCODE[sdk=iphoneos*]" = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1235,6 +1239,7 @@ CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_BITCODE = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1305,7 +1310,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; @@ -1450,8 +1454,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; - "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; @@ -1485,8 +1487,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; - "ENABLE_BITCODE[sdk=iphoneos*]" = YES; FRAMEWORK_VERSION = A; GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/macosx/Info.plist"; From fd62c20888596684aabcff6320892c5ace5c68bc Mon Sep 17 00:00:00 2001 From: sanhuazhang Date: Mon, 21 May 2018 10:13:37 +0800 Subject: [PATCH 94/94] Force add preprocessed file and remove target --- fts5.c | 20982 ++++++++++++++++ fts5.h | 579 + keywordhash.h | 285 + opcodes.c | 179 + opcodes.h | 206 + parse.c | 4215 ++++ parse.h | 170 + .../project.pbxproj | 32 - sqlite3.h | 10371 ++++++++ 9 files changed, 36987 insertions(+), 32 deletions(-) create mode 100644 fts5.c create mode 100644 fts5.h create mode 100644 keywordhash.h create mode 100644 opcodes.c create mode 100644 opcodes.h create mode 100644 parse.c create mode 100644 parse.h create mode 100644 sqlite3.h diff --git a/fts5.c b/fts5.c new file mode 100644 index 0000000000..747ec89e8c --- /dev/null +++ b/fts5.c @@ -0,0 +1,20982 @@ + + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) + +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif +#if defined(NDEBUG) && defined(SQLITE_DEBUG) +# undef NDEBUG +#endif + +#line 1 "fts5.h" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Interfaces to extend FTS5. Using the interfaces defined in this file, +** FTS5 may be extended with: +** +** * custom tokenizers, and +** * custom auxiliary functions. +*/ + + +#ifndef _FTS5_H +#define _FTS5_H + +#include "sqlite3.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************* +** CUSTOM AUXILIARY FUNCTIONS +** +** Virtual table implementations may overload SQL functions by implementing +** the sqlite3_module.xFindFunction() method. +*/ + +typedef struct Fts5ExtensionApi Fts5ExtensionApi; +typedef struct Fts5Context Fts5Context; +typedef struct Fts5PhraseIter Fts5PhraseIter; + +typedef void (*fts5_extension_function)( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +); + +struct Fts5PhraseIter { + const unsigned char *a; + const unsigned char *b; +}; + +/* +** EXTENSION API FUNCTIONS +** +** xUserData(pFts): +** Return a copy of the context pointer the extension function was +** registered with. +** +** xColumnTotalSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the FTS5 table. Or, if iCol is +** non-negative but less than the number of columns in the table, return +** the total number of tokens in column iCol, considering all rows in +** the FTS5 table. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** xColumnCount(pFts): +** Return the number of columns in the table. +** +** xColumnSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the current row. Or, if iCol is +** non-negative but less than the number of columns in the table, set +** *pnToken to the number of tokens in column iCol of the current row. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** +** xColumnText: +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer +** containing the text in utf-8 encoding, (*pn) is set to the size in bytes +** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, +** if an error occurs, an SQLite error code is returned and the final values +** of (*pz) and (*pn) are undefined. +** +** xPhraseCount: +** Returns the number of phrases in the current query expression. +** +** xPhraseSize: +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. +** +** xInstCount: +** Set *pnInst to the total number of occurrences of all phrases within +** the query within the current row. Return SQLITE_OK if successful, or +** an error code (i.e. SQLITE_NOMEM) if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** +** xInst: +** Query for the details of phrase match iIdx within the current row. +** Phrase matches are numbered starting from zero, so the iIdx argument +** should be greater than or equal to zero and smaller than the value +** output by xInstCount(). +** +** Usually, output parameter *piPhrase is set to the phrase number, *piCol +** to the column in which it occurs and *piOff the token offset of the +** first token of the phrase. The exception is if the table was created +** with the offsets=0 option specified. In this case *piOff is always +** set to -1. +** +** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) +** if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** +** xRowid: +** Returns the rowid of the current row. +** +** xTokenize: +** Tokenize text using the tokenizer belonging to the FTS5 table. +** +** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): +** This API function is used to query the FTS table for phrase iPhrase +** of the current query. Specifically, a query equivalent to: +** +** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid +** +** with $p set to a phrase equivalent to the phrase iPhrase of the +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. +** +** If the callback function returns any value other than SQLITE_OK, the +** query is abandoned and the xQueryPhrase function returns immediately. +** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. +** Otherwise, the error code is propagated upwards. +** +** If the query runs to completion without incident, SQLITE_OK is returned. +** Or, if some error occurs before the query completes or is aborted by +** the callback, an SQLite error code is returned. +** +** +** xSetAuxdata(pFts5, pAux, xDelete) +** +** Save the pointer passed as the second argument as the extension functions +** "auxiliary data". The pointer may then be retrieved by the current or any +** future invocation of the same fts5 extension function made as part of +** of the same MATCH query using the xGetAuxdata() API. +** +** Each extension function is allocated a single auxiliary data slot for +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a +** single auxiliary data context. +** +** If there is already an auxiliary data pointer when this function is +** invoked, then it is replaced by the new pointer. If an xDelete callback +** was specified along with the original pointer, it is invoked at this +** point. +** +** The xDelete callback, if one is specified, is also invoked on the +** auxiliary data pointer after the FTS5 query has finished. +** +** If an error (e.g. an OOM condition) occurs within this function, an +** the auxiliary data is set to NULL and an error code returned. If the +** xDelete parameter was not NULL, it is invoked on the auxiliary data +** pointer before returning. +** +** +** xGetAuxdata(pFts5, bClear) +** +** Returns the current auxiliary data pointer for the fts5 extension +** function. See the xSetAuxdata() method for details. +** +** If the bClear argument is non-zero, then the auxiliary data is cleared +** (set to NULL) before this function returns. In this case the xDelete, +** if any, is not invoked. +** +** +** xRowCount(pFts5, pnRow) +** +** This function is used to retrieve the total number of rows in the table. +** In other words, the same value that would be returned by: +** +** SELECT count(*) FROM ftstable; +** +** xPhraseFirst() +** This function is used, along with type Fts5PhraseIter and the xPhraseNext +** method, to iterate through all instances of a single query phrase within +** the current row. This is the same information as is accessible via the +** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient +** to use, this API may be faster under some circumstances. To iterate +** through instances of phrase iPhrase, use the following code: +** +** Fts5PhraseIter iter; +** int iCol, iOff; +** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); +** iCol>=0; +** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) +** ){ +** // An instance of phrase iPhrase at offset iOff of column iCol +** } +** +** The Fts5PhraseIter structure is defined above. Applications should not +** modify this structure directly - it should only be used as shown above +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). +** +** xPhraseNext() +** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. +*/ +struct Fts5ExtensionApi { + int iVersion; /* Currently always set to 3 */ + + void *(*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); +}; + +/* +** CUSTOM AUXILIARY FUNCTIONS +*************************************************************************/ + +/************************************************************************* +** CUSTOM TOKENIZERS +** +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the +** following structure. All structure methods must be defined, setting +** any member of the fts5_tokenizer struct to NULL leads to undefined +** behaviour. The structure methods are expected to function as follows: +** +** xCreate: +** This function is used to allocate and initialize a tokenizer instance. +** A tokenizer instance is required to actually tokenize text. +** +** The first argument passed to this function is a copy of the (void*) +** pointer provided by the application when the fts5_tokenizer object +** was registered with FTS5 (the third argument to xCreateTokenizer()). +** The second and third arguments are an array of nul-terminated strings +** containing the tokenizer arguments, if any, specified following the +** tokenizer name as part of the CREATE VIRTUAL TABLE statement used +** to create the FTS5 table. +** +** The final argument is an output variable. If successful, (*ppOut) +** should be set to point to the new tokenizer handle and SQLITE_OK +** returned. If an error occurs, some value other than SQLITE_OK should +** be returned. In this case, fts5 assumes that the final value of *ppOut +** is undefined. +** +** xDelete: +** This function is invoked to delete a tokenizer handle previously +** allocated using xCreate(). Fts5 guarantees that this function will +** be invoked exactly once for each successful call to xCreate(). +** +** xTokenize: +** This function is expected to tokenize the nText byte string indicated +** by argument pText. pText may or may not be nul-terminated. The first +** argument passed to this function is a pointer to an Fts5Tokenizer object +** returned by an earlier call to xCreate(). +** +** The second argument indicates the reason that FTS5 is requesting +** tokenization of the supplied text. This is always one of the following +** four values: +** +**
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into +** or removed from the FTS table. The tokenizer is being invoked to +** determine the set of tokens to add to (or delete from) the +** FTS index. +** +**
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize +** a bareword or quoted string specified as part of the query. +** +**
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as +** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is +** followed by a "*" character, indicating that the last token +** returned by the tokenizer will be treated as a token prefix. +** +**
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +** satisfy an fts5_api.xTokenize() request made by an auxiliary +** function. Or an fts5_api.xColumnSize() request made by the same +** on a columnsize=0 database. +**
+** +** For each token in the input string, the supplied callback xToken() must +** be invoked. The first argument to it should be a copy of the pointer +** passed as the second argument to xTokenize(). The third and fourth +** arguments are a pointer to a buffer containing the token text, and the +** size of the token in bytes. The 4th and 5th arguments are the byte offsets +** of the first byte of and first byte immediately following the text from +** which the token is derived within the input. +** +** The second argument passed to the xToken() callback ("tflags") should +** normally be set to 0. The exception is if the tokenizer supports +** synonyms. In this case see the discussion below for details. +** +** FTS5 assumes the xToken() callback is invoked for each token in the +** order that they occur within the input text. +** +** If an xToken() callback returns any value other than SQLITE_OK, then +** the tokenization should be abandoned and the xTokenize() method should +** immediately return a copy of the xToken() return value. Or, if the +** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, +** if an error occurs with the xTokenize() implementation itself, it +** may abandon the tokenization and return any error code other than +** SQLITE_OK or SQLITE_DONE. +** +** SYNONYM SUPPORT +** +** Custom tokenizers may also support synonyms. Consider a case in which a +** user wishes to query for a phrase such as "first place". Using the +** built-in tokenizers, the FTS5 query 'first + place' will match instances +** of "first place" within the document set, but not alternative forms +** such as "1st place". In some applications, it would be better to match +** all instances of "first place" or "1st place" regardless of which form +** the user specified in the MATCH query text. +** +** There are several ways to approach this in FTS5: +** +**
  1. By mapping all synonyms to a single token. In this case, the +** In the above example, this means that the tokenizer returns the +** same token for inputs "first" and "1st". Say that token is in +** fact "first", so that when the user inserts the document "I won +** 1st place" entries are added to the index for tokens "i", "won", +** "first" and "place". If the user then queries for '1st + place', +** the tokenizer substitutes "first" for "1st" and the query works +** as expected. +** +**
  2. By adding multiple synonyms for a single term to the FTS index. +** In this case, when tokenizing query text, the tokenizer may +** provide multiple synonyms for a single term within the document. +** FTS5 then queries the index for each synonym individually. For +** example, faced with the query: +** +** +** ... MATCH 'first place' +** +** the tokenizer offers both "1st" and "first" as synonyms for the +** first token in the MATCH query and FTS5 effectively runs a query +** similar to: +** +** +** ... MATCH '(first OR 1st) place' +** +** except that, for the purposes of auxiliary functions, the query +** still appears to contain just two phrases - "(first OR 1st)" +** being treated as a single phrase. +** +**
  3. By adding multiple synonyms for a single term to the FTS index. +** Using this method, when tokenizing document text, the tokenizer +** provides multiple synonyms for each token. So that when a +** document such as "I won first place" is tokenized, entries are +** added to the FTS index for "i", "won", "first", "1st" and +** "place". +** +** This way, even if the tokenizer does not provide synonyms +** when tokenizing query text (it should not - to do would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entires in the +** FTS index corresponding to both forms of the first token. +**
+** +** Whether it is parsing document or query text, any call to xToken that +** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit +** is considered to supply a synonym for the previous token. For example, +** when parsing the document "I won first place", a tokenizer that supports +** synonyms would call xToken() 5 times, as follows: +** +** +** xToken(pCtx, 0, "i", 1, 0, 1); +** xToken(pCtx, 0, "won", 3, 2, 5); +** xToken(pCtx, 0, "first", 5, 6, 11); +** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); +** xToken(pCtx, 0, "place", 5, 12, 17); +** +** +** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time +** xToken() is called. Multiple synonyms may be specified for a single token +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** There is no limit to the number of synonyms that may be provided for a +** single token. +** +** In many cases, method (1) above is the best approach. It does not add +** extra data to the FTS index or require FTS5 to query for multiple terms, +** so it is efficient in terms of disk space and query speed. However, it +** does not support prefix queries very well. If, as suggested above, the +** token "first" is subsituted for "1st" by the tokenizer, then the query: +** +** +** ... MATCH '1s*' +** +** will not match documents that contain the token "1st" (as the tokenizer +** will probably not map "1s" to any prefix of "first"). +** +** For full prefix support, method (3) may be preferred. In this case, +** because the index contains entries for both "first" and "1st", prefix +** queries such as 'fi*' or '1s*' will match correctly. However, because +** extra entries are added to the FTS index, this method uses more space +** within the database. +** +** Method (2) offers a midpoint between (1) and (3). Using this method, +** a query such as '1s*' will match documents that contain the literal +** token "1st", but not "first" (assuming the tokenizer is not able to +** provide synonyms for prefixes). However, a non-prefix query like '1st' +** will match against "1st" and "first". This method does not require +** extra disk space, as no extra entries are added to the FTS index. +** On the other hand, it may require more CPU cycles to run MATCH queries, +** as separate queries of the FTS index are required for each synonym. +** +** When using methods (2) or (3), it is important that the tokenizer only +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is +** inefficient. +*/ +typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer fts5_tokenizer; +struct fts5_tokenizer { + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* Flags that may be passed as the third argument to xTokenize() */ +#define FTS5_TOKENIZE_QUERY 0x0001 +#define FTS5_TOKENIZE_PREFIX 0x0002 +#define FTS5_TOKENIZE_DOCUMENT 0x0004 +#define FTS5_TOKENIZE_AUX 0x0008 + +/* Flags that may be passed by the tokenizer implementation back to FTS5 +** as the third argument to the supplied xToken callback. */ +#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ + +/* +** END OF CUSTOM TOKENIZERS +*************************************************************************/ + +/************************************************************************* +** FTS5 EXTENSION REGISTRATION API +*/ +typedef struct fts5_api fts5_api; +struct fts5_api { + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + /* Create a new auxiliary function */ + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); +}; + +/* +** END OF REGISTRATION API +*************************************************************************/ + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* _FTS5_H */ + +#line 1 "fts5Int.h" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ +#ifndef _FTS5INT_H +#define _FTS5INT_H + +/* #include "fts5.h" */ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 + +#include +#include + +#ifndef SQLITE_AMALGAMATION + +typedef unsigned char u8; +typedef unsigned int u32; +typedef unsigned short u16; +typedef short i16; +typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; + +#define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) + +#define testcase(x) +#define ALWAYS(x) 1 +#define NEVER(x) 0 + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +/* +** Constants for the largest and smallest possible 64-bit signed integers. +*/ +# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) +# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) + +#endif + +/* Truncate very long tokens to this many bytes. Hard limit is +** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset +** field that occurs at the start of each leaf page (see fts5_index.c). */ +#define FTS5_MAX_TOKEN_SIZE 32768 + +/* +** Maximum number of prefix indexes on single FTS5 table. This must be +** less than 32. If it is set to anything large than that, an #error +** directive in fts5_index.c will cause the build to fail. +*/ +#define FTS5_MAX_PREFIX_INDEXES 31 + +#define FTS5_DEFAULT_NEARDIST 10 +#define FTS5_DEFAULT_RANK "bm25" + +/* Name of rank and rowid columns */ +#define FTS5_RANK_NAME "rank" +#define FTS5_ROWID_NAME "rowid" + +#ifdef SQLITE_DEBUG +# define FTS5_CORRUPT sqlite3Fts5Corrupt() +static int sqlite3Fts5Corrupt(void); +#else +# define FTS5_CORRUPT SQLITE_CORRUPT_VTAB +#endif + +/* +** The assert_nc() macro is similar to the assert() macro, except that it +** is used for assert() conditions that are true only if it can be +** guranteed that the database is not corrupt. +*/ +#ifdef SQLITE_DEBUG +extern int sqlite3_fts5_may_be_corrupt; +# define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x)) +#else +# define assert_nc(x) assert(x) +#endif + +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAM +# define UNUSED_PARAM(X) (void)(X) +#endif + +#ifndef UNUSED_PARAM2 +# define UNUSED_PARAM2(X, Y) (void)(X), (void)(Y) +#endif + +typedef struct Fts5Global Fts5Global; +typedef struct Fts5Colset Fts5Colset; + +/* If a NEAR() clump or phrase may only match a specific set of columns, +** then an object of the following type is used to record the set of columns. +** Each entry in the aiCol[] array is a column that may be matched. +** +** This object is used by fts5_expr.c and fts5_index.c. +*/ +struct Fts5Colset { + int nCol; + int aiCol[1]; +}; + + + +/************************************************************************** +** Interface to code in fts5_config.c. fts5_config.c contains contains code +** to parse the arguments passed to the CREATE VIRTUAL TABLE statement. +*/ + +typedef struct Fts5Config Fts5Config; + +/* +** An instance of the following structure encodes all information that can +** be gleaned from the CREATE VIRTUAL TABLE statement. +** +** And all information loaded from the %_config table. +** +** nAutomerge: +** The minimum number of segments that an auto-merge operation should +** attempt to merge together. A value of 1 sets the object to use the +** compile time default. Zero disables auto-merge altogether. +** +** zContent: +** +** zContentRowid: +** The value of the content_rowid= option, if one was specified. Or +** the string "rowid" otherwise. This text is not quoted - if it is +** used as part of an SQL statement it needs to be quoted appropriately. +** +** zContentExprlist: +** +** pzErrmsg: +** This exists in order to allow the fts5_index.c module to return a +** decent error message if it encounters a file-format version it does +** not understand. +** +** bColumnsize: +** True if the %_docsize table is created. +** +** bPrefixIndex: +** This is only used for debugging. If set to false, any prefix indexes +** are ignored. This value is configured using: +** +** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex); +** +*/ +struct Fts5Config { + sqlite3 *db; /* Database handle */ + char *zDb; /* Database holding FTS index (e.g. "main") */ + char *zName; /* Name of FTS index */ + int nCol; /* Number of columns */ + char **azCol; /* Column names */ + u8 *abUnindexed; /* True for unindexed columns */ + int nPrefix; /* Number of prefix indexes */ + int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */ + int eContent; /* An FTS5_CONTENT value */ + char *zContent; /* content table */ + char *zContentRowid; /* "content_rowid=" option value */ + int bColumnsize; /* "columnsize=" option value (dflt==1) */ + int eDetail; /* FTS5_DETAIL_XXX value */ + char *zContentExprlist; + Fts5Tokenizer *pTok; + fts5_tokenizer *pTokApi; + + /* Values loaded from the %_config table */ + int iCookie; /* Incremented when %_config is modified */ + int pgsz; /* Approximate page size used in %_data */ + int nAutomerge; /* 'automerge' setting */ + int nCrisisMerge; /* Maximum allowed segments per level */ + int nUsermerge; /* 'usermerge' setting */ + int nHashSize; /* Bytes of memory for in-memory hash */ + char *zRank; /* Name of rank function */ + char *zRankArgs; /* Arguments to rank function */ + + /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */ + char **pzErrmsg; + +#ifdef SQLITE_DEBUG + int bPrefixIndex; /* True to use prefix-indexes */ +#endif +}; + +/* Current expected value of %_config table 'version' field */ +#define FTS5_CURRENT_VERSION 4 + +#define FTS5_CONTENT_NORMAL 0 +#define FTS5_CONTENT_NONE 1 +#define FTS5_CONTENT_EXTERNAL 2 + +#define FTS5_DETAIL_FULL 0 +#define FTS5_DETAIL_NONE 1 +#define FTS5_DETAIL_COLUMNS 2 + + + +static int sqlite3Fts5ConfigParse( + Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** +); +static void sqlite3Fts5ConfigFree(Fts5Config*); + +static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig); + +static int sqlite3Fts5Tokenize( + Fts5Config *pConfig, /* FTS5 Configuration object */ + int flags, /* FTS5_TOKENIZE_* flags */ + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ +); + +static void sqlite3Fts5Dequote(char *z); + +/* Load the contents of the %_config table */ +static int sqlite3Fts5ConfigLoad(Fts5Config*, int); + +/* Set the value of a single config attribute */ +static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*); + +static int sqlite3Fts5ConfigParseRank(const char*, char**, char**); + +/* +** End of interface to code in fts5_config.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_buffer.c. +*/ + +/* +** Buffer object for the incremental building of string data. +*/ +typedef struct Fts5Buffer Fts5Buffer; +struct Fts5Buffer { + u8 *p; + int n; + int nSpace; +}; + +static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32); +static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64); +static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*); +static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*); +static void sqlite3Fts5BufferFree(Fts5Buffer*); +static void sqlite3Fts5BufferZero(Fts5Buffer*); +static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*); +static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...); + +static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); + +#define fts5BufferZero(x) sqlite3Fts5BufferZero(x) +#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c) +#define fts5BufferFree(a) sqlite3Fts5BufferFree(a) +#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d) +#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d) + +#define fts5BufferGrow(pRc,pBuf,nn) ( \ + (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \ + sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \ +) + +/* Write and decode big-endian 32-bit integer values */ +static void sqlite3Fts5Put32(u8*, int); +static int sqlite3Fts5Get32(const u8*); + +#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) +#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF) + +typedef struct Fts5PoslistReader Fts5PoslistReader; +struct Fts5PoslistReader { + /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */ + const u8 *a; /* Position list to iterate through */ + int n; /* Size of buffer at a[] in bytes */ + int i; /* Current offset in a[] */ + + u8 bFlag; /* For client use (any custom purpose) */ + + /* Output variables */ + u8 bEof; /* Set to true at EOF */ + i64 iPos; /* (iCol<<32) + iPos */ +}; +static int sqlite3Fts5PoslistReaderInit( + const u8 *a, int n, /* Poslist buffer to iterate through */ + Fts5PoslistReader *pIter /* Iterator object to initialize */ +); +static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*); + +typedef struct Fts5PoslistWriter Fts5PoslistWriter; +struct Fts5PoslistWriter { + i64 iPrev; +}; +static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64); +static void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64); + +static int sqlite3Fts5PoslistNext64( + const u8 *a, int n, /* Buffer containing poslist */ + int *pi, /* IN/OUT: Offset within a[] */ + i64 *piOff /* IN/OUT: Current offset */ +); + +/* Malloc utility */ +static void *sqlite3Fts5MallocZero(int *pRc, int nByte); +static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); + +/* Character set tests (like isspace(), isalpha() etc.) */ +static int sqlite3Fts5IsBareword(char t); + + +/* Bucket of terms object used by the integrity-check in offsets=0 mode. */ +typedef struct Fts5Termset Fts5Termset; +static int sqlite3Fts5TermsetNew(Fts5Termset**); +static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent); +static void sqlite3Fts5TermsetFree(Fts5Termset*); + +/* +** End of interface to code in fts5_buffer.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_index.c. fts5_index.c contains contains code +** to access the data stored in the %_data table. +*/ + +typedef struct Fts5Index Fts5Index; +typedef struct Fts5IndexIter Fts5IndexIter; + +struct Fts5IndexIter { + i64 iRowid; + const u8 *pData; + int nData; + u8 bEof; +}; + +#define sqlite3Fts5IterEof(x) ((x)->bEof) + +/* +** Values used as part of the flags argument passed to IndexQuery(). +*/ +#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ +#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ +#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ +#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ + +/* The following are used internally by the fts5_index.c module. They are +** defined here only to make it easier to avoid clashes with the flags +** above. */ +#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 +#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 + +/* +** Create/destroy an Fts5Index object. +*/ +static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); +static int sqlite3Fts5IndexClose(Fts5Index *p); + +/* +** Return a simple checksum value based on the arguments. +*/ +static u64 sqlite3Fts5IndexEntryCksum( + i64 iRowid, + int iCol, + int iPos, + int iIdx, + const char *pTerm, + int nTerm +); + +/* +** Argument p points to a buffer containing utf-8 text that is n bytes in +** size. Return the number of bytes in the nChar character prefix of the +** buffer, or 0 if there are less than nChar characters in total. +*/ +static int sqlite3Fts5IndexCharlenToBytelen( + const char *p, + int nByte, + int nChar +); + +/* +** Open a new iterator to iterate though all rowids that match the +** specified token or token prefix. +*/ +static int sqlite3Fts5IndexQuery( + Fts5Index *p, /* FTS index to query */ + const char *pToken, int nToken, /* Token (or prefix) to query for */ + int flags, /* Mask of FTS5INDEX_QUERY_X flags */ + Fts5Colset *pColset, /* Match these columns only */ + Fts5IndexIter **ppIter /* OUT: New iterator object */ +); + +/* +** The various operations on open token or token prefix iterators opened +** using sqlite3Fts5IndexQuery(). +*/ +static int sqlite3Fts5IterNext(Fts5IndexIter*); +static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); + +/* +** Close an iterator opened by sqlite3Fts5IndexQuery(). +*/ +static void sqlite3Fts5IterClose(Fts5IndexIter*); + +/* +** This interface is used by the fts5vocab module. +*/ +static const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*); +static int sqlite3Fts5IterNextScan(Fts5IndexIter*); + + +/* +** Insert or remove data to or from the index. Each time a document is +** added to or removed from the index, this function is called one or more +** times. +** +** For an insert, it must be called once for each token in the new document. +** If the operation is a delete, it must be called (at least) once for each +** unique token in the document with an iCol value less than zero. The iPos +** argument is ignored for a delete. +*/ +static int sqlite3Fts5IndexWrite( + Fts5Index *p, /* Index to write to */ + int iCol, /* Column token appears in (-ve -> delete) */ + int iPos, /* Position of token within column */ + const char *pToken, int nToken /* Token to add or remove to or from index */ +); + +/* +** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to +** document iDocid. +*/ +static int sqlite3Fts5IndexBeginWrite( + Fts5Index *p, /* Index to write to */ + int bDelete, /* True if current operation is a delete */ + i64 iDocid /* Docid to add or remove data from */ +); + +/* +** Flush any data stored in the in-memory hash tables to the database. +** If the bCommit flag is true, also close any open blob handles. +*/ +static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit); + +/* +** Discard any data stored in the in-memory hash tables. Do not write it +** to the database. Additionally, assume that the contents of the %_data +** table may have changed on disk. So any in-memory caches of %_data +** records must be invalidated. +*/ +static int sqlite3Fts5IndexRollback(Fts5Index *p); + +/* +** Get or set the "averages" values. +*/ +static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize); +static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); + +/* +** Functions called by the storage module as part of integrity-check. +*/ +static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); + +/* +** Called during virtual module initialization to register UDF +** fts5_decode() with SQLite +*/ +static int sqlite3Fts5IndexInit(sqlite3*); + +static int sqlite3Fts5IndexSetCookie(Fts5Index*, int); + +/* +** Return the total number of entries read from the %_data table by +** this connection since it was created. +*/ +static int sqlite3Fts5IndexReads(Fts5Index *p); + +static int sqlite3Fts5IndexReinit(Fts5Index *p); +static int sqlite3Fts5IndexOptimize(Fts5Index *p); +static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge); +static int sqlite3Fts5IndexReset(Fts5Index *p); + +static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); + +/* +** End of interface to code in fts5_index.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_varint.c. +*/ +static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v); +static int sqlite3Fts5GetVarintLen(u32 iVal); +static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*); +static int sqlite3Fts5PutVarint(unsigned char *p, u64 v); + +#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b) +#define fts5GetVarint sqlite3Fts5GetVarint + +#define fts5FastGetVarint32(a, iOff, nVal) { \ + nVal = (a)[iOff++]; \ + if( nVal & 0x80 ){ \ + iOff--; \ + iOff += fts5GetVarint32(&(a)[iOff], nVal); \ + } \ +} + + +/* +** End of interface to code in fts5_varint.c. +**************************************************************************/ + + +/************************************************************************** +** Interface to code in fts5.c. +*/ + +static int sqlite3Fts5GetTokenizer( + Fts5Global*, + const char **azArg, + int nArg, + Fts5Tokenizer**, + fts5_tokenizer**, + char **pzErr +); + +static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **); + +/* +** End of interface to code in fts5.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_hash.c. +*/ +typedef struct Fts5Hash Fts5Hash; + +/* +** Create a hash table, free a hash table. +*/ +static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize); +static void sqlite3Fts5HashFree(Fts5Hash*); + +static int sqlite3Fts5HashWrite( + Fts5Hash*, + i64 iRowid, /* Rowid for this entry */ + int iCol, /* Column token appears in (-ve -> delete) */ + int iPos, /* Position of token within column */ + char bByte, + const char *pToken, int nToken /* Token to add or remove to or from index */ +); + +/* +** Empty (but do not delete) a hash table. +*/ +static void sqlite3Fts5HashClear(Fts5Hash*); + +static int sqlite3Fts5HashQuery( + Fts5Hash*, /* Hash table to query */ + const char *pTerm, int nTerm, /* Query term */ + const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + int *pnDoclist /* OUT: Size of doclist in bytes */ +); + +static int sqlite3Fts5HashScanInit( + Fts5Hash*, /* Hash table to query */ + const char *pTerm, int nTerm /* Query prefix */ +); +static void sqlite3Fts5HashScanNext(Fts5Hash*); +static int sqlite3Fts5HashScanEof(Fts5Hash*); +static void sqlite3Fts5HashScanEntry(Fts5Hash *, + const char **pzTerm, /* OUT: term (nul-terminated) */ + const u8 **ppDoclist, /* OUT: pointer to doclist */ + int *pnDoclist /* OUT: size of doclist in bytes */ +); + + +/* +** End of interface to code in fts5_hash.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_storage.c. fts5_storage.c contains contains +** code to access the data stored in the %_content and %_docsize tables. +*/ + +#define FTS5_STMT_SCAN_ASC 0 /* SELECT rowid, * FROM ... ORDER BY 1 ASC */ +#define FTS5_STMT_SCAN_DESC 1 /* SELECT rowid, * FROM ... ORDER BY 1 DESC */ +#define FTS5_STMT_LOOKUP 2 /* SELECT rowid, * FROM ... WHERE rowid=? */ + +typedef struct Fts5Storage Fts5Storage; + +static int sqlite3Fts5StorageOpen(Fts5Config*, Fts5Index*, int, Fts5Storage**, char**); +static int sqlite3Fts5StorageClose(Fts5Storage *p); +static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); + +static int sqlite3Fts5DropAll(Fts5Config*); +static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); + +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); +static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); +static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); + +static int sqlite3Fts5StorageIntegrity(Fts5Storage *p); + +static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**); +static void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*); + +static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); +static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg); +static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow); + +static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit); +static int sqlite3Fts5StorageRollback(Fts5Storage *p); + +static int sqlite3Fts5StorageConfigValue( + Fts5Storage *p, const char*, sqlite3_value*, int +); + +static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p); +static int sqlite3Fts5StorageRebuild(Fts5Storage *p); +static int sqlite3Fts5StorageOptimize(Fts5Storage *p); +static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); +static int sqlite3Fts5StorageReset(Fts5Storage *p); + +/* +** End of interface to code in fts5_storage.c. +**************************************************************************/ + + +/************************************************************************** +** Interface to code in fts5_expr.c. +*/ +typedef struct Fts5Expr Fts5Expr; +typedef struct Fts5ExprNode Fts5ExprNode; +typedef struct Fts5Parse Fts5Parse; +typedef struct Fts5Token Fts5Token; +typedef struct Fts5ExprPhrase Fts5ExprPhrase; +typedef struct Fts5ExprNearset Fts5ExprNearset; + +struct Fts5Token { + const char *p; /* Token text (not NULL terminated) */ + int n; /* Size of buffer p in bytes */ +}; + +/* Parse a MATCH expression. */ +static int sqlite3Fts5ExprNew( + Fts5Config *pConfig, + const char *zExpr, + Fts5Expr **ppNew, + char **pzErr +); + +/* +** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); +** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr); +** rc = sqlite3Fts5ExprNext(pExpr) +** ){ +** // The document with rowid iRowid matches the expression! +** i64 iRowid = sqlite3Fts5ExprRowid(pExpr); +** } +*/ +static int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc); +static int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax); +static int sqlite3Fts5ExprEof(Fts5Expr*); +static i64 sqlite3Fts5ExprRowid(Fts5Expr*); + +static void sqlite3Fts5ExprFree(Fts5Expr*); + +/* Called during startup to register a UDF with SQLite */ +static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*); + +static int sqlite3Fts5ExprPhraseCount(Fts5Expr*); +static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase); +static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **); + +typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; +static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); +static int sqlite3Fts5ExprPopulatePoslists( + Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int +); +static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); + +static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); + +static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); + +/******************************************* +** The fts5_expr.c API above this point is used by the other hand-written +** C code in this module. The interfaces below this point are called by +** the parser code in fts5parse.y. */ + +static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...); + +static Fts5ExprNode *sqlite3Fts5ParseNode( + Fts5Parse *pParse, + int eType, + Fts5ExprNode *pLeft, + Fts5ExprNode *pRight, + Fts5ExprNearset *pNear +); + +static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( + Fts5Parse *pParse, + Fts5ExprNode *pLeft, + Fts5ExprNode *pRight +); + +static Fts5ExprPhrase *sqlite3Fts5ParseTerm( + Fts5Parse *pParse, + Fts5ExprPhrase *pPhrase, + Fts5Token *pToken, + int bPrefix +); + +static Fts5ExprNearset *sqlite3Fts5ParseNearset( + Fts5Parse*, + Fts5ExprNearset*, + Fts5ExprPhrase* +); + +static Fts5Colset *sqlite3Fts5ParseColset( + Fts5Parse*, + Fts5Colset*, + Fts5Token * +); + +static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*); +static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); +static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); + +static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); +static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); +static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*); +static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); +static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); + +/* +** End of interface to code in fts5_expr.c. +**************************************************************************/ + + + +/************************************************************************** +** Interface to code in fts5_aux.c. +*/ + +static int sqlite3Fts5AuxInit(fts5_api*); +/* +** End of interface to code in fts5_aux.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_tokenizer.c. +*/ + +static int sqlite3Fts5TokenizerInit(fts5_api*); +/* +** End of interface to code in fts5_tokenizer.c. +**************************************************************************/ + +/************************************************************************** +** Interface to code in fts5_vocab.c. +*/ + +static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*); + +/* +** End of interface to code in fts5_vocab.c. +**************************************************************************/ + + +/************************************************************************** +** Interface to automatically generated code in fts5_unicode2.c. +*/ +static int sqlite3Fts5UnicodeIsalnum(int c); +static int sqlite3Fts5UnicodeIsdiacritic(int c); +static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); +/* +** End of interface to code in fts5_unicode2.c. +**************************************************************************/ + +#endif + +#line 1 "fts5parse.h" +#define FTS5_OR 1 +#define FTS5_AND 2 +#define FTS5_NOT 3 +#define FTS5_TERM 4 +#define FTS5_COLON 5 +#define FTS5_LP 6 +#define FTS5_RP 7 +#define FTS5_MINUS 8 +#define FTS5_LCP 9 +#define FTS5_RCP 10 +#define FTS5_STRING 11 +#define FTS5_COMMA 12 +#define FTS5_PLUS 13 +#define FTS5_STAR 14 + +#line 1 "fts5parse.c" +/* +** 2000-05-29 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Driver template for the LEMON parser generator. +** +** The "lemon" program processes an LALR(1) input grammar file, then uses +** this template to construct a parser. The "lemon" program inserts text +** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** interstitial "-" characters) contained in this template is changed into +** the value of the %name directive from the grammar. Otherwise, the content +** of this template is copied straight through into the generate parser +** source file. +** +** The following is the concatenation of all %include directives from the +** input grammar file: +*/ +#include +/************ Begin %include sections from the grammar ************************/ +#line 47 "fts5parse.y" + +/* #include "fts5Int.h" */ +/* #include "fts5parse.h" */ + +/* +** Disable all error recovery processing in the parser push-down +** automaton. +*/ +#define fts5YYNOERRORRECOVERY 1 + +/* +** Make fts5yytestcase() the same as testcase() +*/ +#define fts5yytestcase(X) testcase(X) + +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define fts5YYPARSEFREENOTNULL 1 + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define fts5YYMALLOCARGTYPE u64 + +#line 56 "fts5parse.c" +/**************** End of %include directives **********************************/ +/* These constants specify the various numeric values for terminal symbols +** in a format understandable to "makeheaders". This section is blank unless +** "lemon" is run with the "-m" command-line option. +***************** Begin makeheaders token definitions *************************/ +/**************** End makeheaders token definitions ***************************/ + +/* The next sections is a series of control #defines. +** various aspects of the generated parser. +** fts5YYCODETYPE is the data type used to store the integer codes +** that represent terminal and non-terminal symbols. +** "unsigned char" is used if there are fewer than +** 256 symbols. Larger types otherwise. +** fts5YYNOCODE is a number of type fts5YYCODETYPE that is not used for +** any terminal or nonterminal symbol. +** fts5YYFALLBACK If defined, this indicates that one or more tokens +** (also known as: "terminal symbols") have fall-back +** values which should be used if the original symbol +** would not parse. This permits keywords to sometimes +** be used as identifiers, for example. +** fts5YYACTIONTYPE is the data type used for "action codes" - numbers +** that indicate what to do in response to the next +** token. +** sqlite3Fts5ParserFTS5TOKENTYPE is the data type used for minor type for terminal +** symbols. Background: A "minor type" is a semantic +** value associated with a terminal or non-terminal +** symbols. For example, for an "ID" terminal symbol, +** the minor type might be the name of the identifier. +** Each non-terminal can have a different minor type. +** Terminal symbols all have the same minor type, though. +** This macros defines the minor type for terminal +** symbols. +** fts5YYMINORTYPE is the data type used for all minor types. +** This is typically a union of many types, one of +** which is sqlite3Fts5ParserFTS5TOKENTYPE. The entry in the union +** for terminal symbols is called "fts5yy0". +** fts5YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** sqlite3Fts5ParserARG_SDECL A static variable declaration for the %extra_argument +** sqlite3Fts5ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser +** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser +** fts5YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +** fts5YYNSTATE the combined number of states. +** fts5YYNRULE the number of rules in the grammar +** fts5YY_MAX_SHIFT Maximum value for shift actions +** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions +** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions +** fts5YY_MIN_REDUCE Maximum value for reduce actions +** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error +** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept +** fts5YY_NO_ACTION The fts5yy_action[] code for no-op +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ +#define fts5YYCODETYPE unsigned char +#define fts5YYNOCODE 28 +#define fts5YYACTIONTYPE unsigned char +#define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token +typedef union { + int fts5yyinit; + sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0; + int fts5yy4; + Fts5Colset* fts5yy11; + Fts5ExprNode* fts5yy24; + Fts5ExprNearset* fts5yy46; + Fts5ExprPhrase* fts5yy53; +} fts5YYMINORTYPE; +#ifndef fts5YYSTACKDEPTH +#define fts5YYSTACKDEPTH 100 +#endif +#define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse; +#define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse +#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse +#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse +#define fts5YYNSTATE 29 +#define fts5YYNRULE 26 +#define fts5YY_MAX_SHIFT 28 +#define fts5YY_MIN_SHIFTREDUCE 45 +#define fts5YY_MAX_SHIFTREDUCE 70 +#define fts5YY_MIN_REDUCE 71 +#define fts5YY_MAX_REDUCE 96 +#define fts5YY_ERROR_ACTION 97 +#define fts5YY_ACCEPT_ACTION 98 +#define fts5YY_NO_ACTION 99 +/************* End control #defines *******************************************/ + +/* Define the fts5yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define fts5yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the fts5yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef fts5yytestcase +# define fts5yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N <= fts5YY_MAX_SHIFT Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** N between fts5YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and fts5YY_MAX_SHIFTREDUCE reduce by rule N-fts5YY_MIN_SHIFTREDUCE. +** +** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE +** and fts5YY_MAX_REDUCE +** +** N == fts5YY_ERROR_ACTION A syntax error has occurred. +** +** N == fts5YY_ACCEPT_ACTION The parser accepts its input. +** +** N == fts5YY_NO_ACTION No such action. Denotes unused +** slots in the fts5yy_action[] table. +** +** The action table is constructed as a single large table named fts5yy_action[]. +** Given state S and lookahead X, the action is computed as either: +** +** (A) N = fts5yy_action[ fts5yy_shift_ofst[S] + X ] +** (B) N = fts5yy_default[S] +** +** The (A) formula is preferred. The B formula is used instead if: +** (1) The fts5yy_shift_ofst[S]+X value is out of range, or +** (2) fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X, or +** (3) fts5yy_shift_ofst[S] equal fts5YY_SHIFT_USE_DFLT. +** (Implementation note: fts5YY_SHIFT_USE_DFLT is chosen so that +** fts5YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) +** +** The formulas above are for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of +** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of +** fts5YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** fts5yy_action[] A single table containing all actions. +** fts5yy_lookahead[] A table containing the lookahead for each entry in +** fts5yy_action. Used to detect hash collisions. +** fts5yy_shift_ofst[] For each state, the offset into fts5yy_action for +** shifting terminals. +** fts5yy_reduce_ofst[] For each state, the offset into fts5yy_action for +** shifting non-terminals after a reduce. +** fts5yy_default[] Default action for each state. +** +*********** Begin parsing tables **********************************************/ +#define fts5YY_ACTTAB_COUNT (85) +static const fts5YYACTIONTYPE fts5yy_action[] = { + /* 0 */ 98, 16, 51, 5, 53, 27, 83, 7, 26, 15, + /* 10 */ 51, 5, 53, 27, 13, 69, 26, 48, 51, 5, + /* 20 */ 53, 27, 19, 11, 26, 9, 20, 51, 5, 53, + /* 30 */ 27, 13, 22, 26, 28, 51, 5, 53, 27, 68, + /* 40 */ 1, 26, 19, 11, 17, 9, 52, 10, 53, 27, + /* 50 */ 23, 24, 26, 54, 3, 4, 2, 26, 6, 21, + /* 60 */ 49, 71, 3, 4, 2, 7, 56, 59, 55, 59, + /* 70 */ 4, 2, 12, 69, 58, 60, 18, 67, 62, 69, + /* 80 */ 25, 66, 8, 14, 2, +}; +static const fts5YYCODETYPE fts5yy_lookahead[] = { + /* 0 */ 16, 17, 18, 19, 20, 21, 5, 6, 24, 17, + /* 10 */ 18, 19, 20, 21, 11, 14, 24, 17, 18, 19, + /* 20 */ 20, 21, 8, 9, 24, 11, 17, 18, 19, 20, + /* 30 */ 21, 11, 12, 24, 17, 18, 19, 20, 21, 26, + /* 40 */ 6, 24, 8, 9, 22, 11, 18, 11, 20, 21, + /* 50 */ 24, 25, 24, 20, 1, 2, 3, 24, 23, 24, + /* 60 */ 7, 0, 1, 2, 3, 6, 10, 11, 10, 11, + /* 70 */ 2, 3, 9, 14, 11, 11, 22, 26, 7, 14, + /* 80 */ 13, 11, 5, 11, 3, +}; +#define fts5YY_SHIFT_USE_DFLT (85) +#define fts5YY_SHIFT_COUNT (28) +#define fts5YY_SHIFT_MIN (0) +#define fts5YY_SHIFT_MAX (81) +static const unsigned char fts5yy_shift_ofst[] = { + /* 0 */ 34, 34, 34, 34, 34, 14, 20, 3, 36, 1, + /* 10 */ 59, 64, 64, 65, 65, 53, 61, 56, 58, 63, + /* 20 */ 68, 67, 70, 67, 71, 72, 67, 77, 81, +}; +#define fts5YY_REDUCE_USE_DFLT (-17) +#define fts5YY_REDUCE_COUNT (14) +#define fts5YY_REDUCE_MIN (-16) +#define fts5YY_REDUCE_MAX (54) +static const signed char fts5yy_reduce_ofst[] = { + /* 0 */ -16, -8, 0, 9, 17, 28, 26, 35, 33, 13, + /* 10 */ 13, 22, 54, 13, 51, +}; +static const fts5YYACTIONTYPE fts5yy_default[] = { + /* 0 */ 97, 97, 97, 97, 97, 76, 91, 97, 97, 96, + /* 10 */ 96, 97, 97, 96, 96, 97, 97, 97, 97, 97, + /* 20 */ 73, 89, 97, 90, 97, 97, 87, 97, 72, +}; +/********** End of lemon-generated parsing tables *****************************/ + +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +** +** This feature can be used, for example, to cause some keywords in a language +** to revert to identifiers if they keyword does not apply in the context where +** it appears. +*/ +#ifdef fts5YYFALLBACK +static const fts5YYCODETYPE fts5yyFallback[] = { +}; +#endif /* fts5YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +** +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. +*/ +struct fts5yyStackEntry { + fts5YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ + fts5YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + fts5YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct fts5yyStackEntry fts5yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct fts5yyParser { + fts5yyStackEntry *fts5yytos; /* Pointer to top element of the stack */ +#ifdef fts5YYTRACKMAXSTACKDEPTH + int fts5yyhwm; /* High-water mark of the stack */ +#endif +#ifndef fts5YYNOERRORRECOVERY + int fts5yyerrcnt; /* Shifts left before out of the error */ +#endif + sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ +#if fts5YYSTACKDEPTH<=0 + int fts5yystksz; /* Current side of the stack */ + fts5yyStackEntry *fts5yystack; /* The parser's stack */ + fts5yyStackEntry fts5yystk0; /* First stack entry */ +#else + fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */ +#endif +}; +typedef struct fts5yyParser fts5yyParser; + +#ifndef NDEBUG +#include +static FILE *fts5yyTraceFILE = 0; +static char *fts5yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** Outputs: +** None. +*/ +static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){ + fts5yyTraceFILE = TraceFILE; + fts5yyTracePrompt = zTracePrompt; + if( fts5yyTraceFILE==0 ) fts5yyTracePrompt = 0; + else if( fts5yyTracePrompt==0 ) fts5yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const fts5yyTokenName[] = { + "$", "OR", "AND", "NOT", + "TERM", "COLON", "LP", "RP", + "MINUS", "LCP", "RCP", "STRING", + "COMMA", "PLUS", "STAR", "error", + "input", "expr", "cnearset", "exprlist", + "nearset", "colset", "colsetlist", "nearphrases", + "phrase", "neardist_opt", "star_opt", +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const fts5yyRuleName[] = { + /* 0 */ "input ::= expr", + /* 1 */ "expr ::= expr AND expr", + /* 2 */ "expr ::= expr OR expr", + /* 3 */ "expr ::= expr NOT expr", + /* 4 */ "expr ::= LP expr RP", + /* 5 */ "expr ::= exprlist", + /* 6 */ "exprlist ::= cnearset", + /* 7 */ "exprlist ::= exprlist cnearset", + /* 8 */ "cnearset ::= nearset", + /* 9 */ "cnearset ::= colset COLON nearset", + /* 10 */ "colset ::= MINUS LCP colsetlist RCP", + /* 11 */ "colset ::= LCP colsetlist RCP", + /* 12 */ "colset ::= STRING", + /* 13 */ "colset ::= MINUS STRING", + /* 14 */ "colsetlist ::= colsetlist STRING", + /* 15 */ "colsetlist ::= STRING", + /* 16 */ "nearset ::= phrase", + /* 17 */ "nearset ::= STRING LP nearphrases neardist_opt RP", + /* 18 */ "nearphrases ::= phrase", + /* 19 */ "nearphrases ::= nearphrases phrase", + /* 20 */ "neardist_opt ::=", + /* 21 */ "neardist_opt ::= COMMA STRING", + /* 22 */ "phrase ::= phrase PLUS STRING star_opt", + /* 23 */ "phrase ::= STRING star_opt", + /* 24 */ "star_opt ::= STAR", + /* 25 */ "star_opt ::=", +}; +#endif /* NDEBUG */ + + +#if fts5YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. +*/ +static int fts5yyGrowStack(fts5yyParser *p){ + int newSize; + int idx; + fts5yyStackEntry *pNew; + + newSize = p->fts5yystksz*2 + 100; + idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0; + if( p->fts5yystack==&p->fts5yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->fts5yystk0; + }else{ + pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); + } + if( pNew ){ + p->fts5yystack = pNew; + p->fts5yytos = &p->fts5yystack[idx]; +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", + fts5yyTracePrompt, p->fts5yystksz, newSize); + } +#endif + p->fts5yystksz = newSize; + } + return pNew==0; +} +#endif + +/* Datatype of the argument to the memory allocated passed as the +** second argument to sqlite3Fts5ParserAlloc() below. This can be changed by +** putting an appropriate #define in the %include section of the input +** grammar. +*/ +#ifndef fts5YYMALLOCARGTYPE +# define fts5YYMALLOCARGTYPE size_t +#endif + +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to sqlite3Fts5Parser and sqlite3Fts5ParserFree. +*/ +static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){ + fts5yyParser *pParser; + pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); + if( pParser ){ +#ifdef fts5YYTRACKMAXSTACKDEPTH + pParser->fts5yyhwm = 0; +#endif +#if fts5YYSTACKDEPTH<=0 + pParser->fts5yytos = NULL; + pParser->fts5yystack = NULL; + pParser->fts5yystksz = 0; + if( fts5yyGrowStack(pParser) ){ + pParser->fts5yystack = &pParser->fts5yystk0; + pParser->fts5yystksz = 1; + } +#endif +#ifndef fts5YYNOERRORRECOVERY + pParser->fts5yyerrcnt = -1; +#endif + pParser->fts5yytos = pParser->fts5yystack; + pParser->fts5yystack[0].stateno = 0; + pParser->fts5yystack[0].major = 0; + } + return pParser; +} + +/* The following function deletes the "minor type" or semantic value +** associated with a symbol. The symbol can be either a terminal +** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is +** a pointer to the value to be deleted. The code used to do the +** deletions is derived from the %destructor and/or %token_destructor +** directives of the input grammar. +*/ +static void fts5yy_destructor( + fts5yyParser *fts5yypParser, /* The parser */ + fts5YYCODETYPE fts5yymajor, /* Type code for object to destroy */ + fts5YYMINORTYPE *fts5yypminor /* The object to be destroyed */ +){ + sqlite3Fts5ParserARG_FETCH; + switch( fts5yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are *not* used + ** inside the C code. + */ +/********* Begin destructor definitions ***************************************/ + case 16: /* input */ +{ +#line 83 "fts5parse.y" + (void)pParse; +#line 517 "fts5parse.c" +} + break; + case 17: /* expr */ + case 18: /* cnearset */ + case 19: /* exprlist */ +{ +#line 89 "fts5parse.y" + sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24)); +#line 526 "fts5parse.c" +} + break; + case 20: /* nearset */ + case 23: /* nearphrases */ +{ +#line 143 "fts5parse.y" + sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46)); +#line 534 "fts5parse.c" +} + break; + case 21: /* colset */ + case 22: /* colsetlist */ +{ +#line 119 "fts5parse.y" + sqlite3_free((fts5yypminor->fts5yy11)); +#line 542 "fts5parse.c" +} + break; + case 24: /* phrase */ +{ +#line 174 "fts5parse.y" + sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53)); +#line 549 "fts5parse.c" +} + break; +/********* End destructor definitions *****************************************/ + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +*/ +static void fts5yy_pop_parser_stack(fts5yyParser *pParser){ + fts5yyStackEntry *fts5yytos; + assert( pParser->fts5yytos!=0 ); + assert( pParser->fts5yytos > pParser->fts5yystack ); + fts5yytos = pParser->fts5yytos--; +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sPopping %s\n", + fts5yyTracePrompt, + fts5yyTokenName[fts5yytos->major]); + } +#endif + fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor); +} + +/* +** Deallocate and destroy a parser. Destructors are called for +** all stack elements before shutting the parser down. +** +** If the fts5YYPARSEFREENEVERNULL macro exists (for example because it +** is defined in a %include section of the input grammar) then it is +** assumed that the input pointer is never NULL. +*/ +static void sqlite3Fts5ParserFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ + fts5yyParser *pParser = (fts5yyParser*)p; +#ifndef fts5YYPARSEFREENEVERNULL + if( pParser==0 ) return; +#endif + while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser); +#if fts5YYSTACKDEPTH<=0 + if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack); +#endif + (*freeProc)((void*)pParser); +} + +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef fts5YYTRACKMAXSTACKDEPTH +static int sqlite3Fts5ParserStackPeak(void *p){ + fts5yyParser *pParser = (fts5yyParser*)p; + return pParser->fts5yyhwm; +} +#endif + +/* +** Find the appropriate action for a parser given the terminal +** look-ahead token iLookAhead. +*/ +static unsigned int fts5yy_find_shift_action( + fts5yyParser *pParser, /* The parser */ + fts5YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; + int stateno = pParser->fts5yytos->stateno; + + if( stateno>=fts5YY_MIN_REDUCE ) return stateno; + assert( stateno <= fts5YY_SHIFT_COUNT ); + do{ + i = fts5yy_shift_ofst[stateno]; + assert( iLookAhead!=fts5YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){ +#ifdef fts5YYFALLBACK + fts5YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead %s\n", + fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]); + } +#endif + assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#endif +#ifdef fts5YYWILDCARD + { + int j = i - iLookAhead + fts5YYWILDCARD; + if( +#if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0 + j>=0 && +#endif +#if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT + j0 + ){ +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n", + fts5yyTracePrompt, fts5yyTokenName[iLookAhead], + fts5yyTokenName[fts5YYWILDCARD]); + } +#endif /* NDEBUG */ + return fts5yy_action[j]; + } + } +#endif /* fts5YYWILDCARD */ + return fts5yy_default[stateno]; + }else{ + return fts5yy_action[i]; + } + }while(1); +} + +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +*/ +static int fts5yy_find_reduce_action( + int stateno, /* Current state number */ + fts5YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef fts5YYERRORSYMBOL + if( stateno>fts5YY_REDUCE_COUNT ){ + return fts5yy_default[stateno]; + } +#else + assert( stateno<=fts5YY_REDUCE_COUNT ); +#endif + i = fts5yy_reduce_ofst[stateno]; + assert( i!=fts5YY_REDUCE_USE_DFLT ); + assert( iLookAhead!=fts5YYNOCODE ); + i += iLookAhead; +#ifdef fts5YYERRORSYMBOL + if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){ + return fts5yy_default[stateno]; + } +#else + assert( i>=0 && ifts5yytos--; +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt); + } +#endif + while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +/******** Begin %stack_overflow code ******************************************/ +#line 36 "fts5parse.y" + + sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); +#line 723 "fts5parse.c" +/******** End %stack_overflow code ********************************************/ + sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ +} + +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){ + if( fts5yyTraceFILE ){ + if( fts5yyNewStatefts5yytos->major], + fts5yyNewState); + }else{ + fprintf(fts5yyTraceFILE,"%sShift '%s'\n", + fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major]); + } + } +} +#else +# define fts5yyTraceShift(X,Y) +#endif + +/* +** Perform a shift action. +*/ +static void fts5yy_shift( + fts5yyParser *fts5yypParser, /* The parser to be shifted */ + int fts5yyNewState, /* The new state to shift in */ + int fts5yyMajor, /* The major token to shift in */ + sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */ +){ + fts5yyStackEntry *fts5yytos; + fts5yypParser->fts5yytos++; +#ifdef fts5YYTRACKMAXSTACKDEPTH + if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) ); + } +#endif +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH] ){ + fts5yyStackOverflow(fts5yypParser); + return; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){ + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yyStackOverflow(fts5yypParser); + return; + } + } +#endif + if( fts5yyNewState > fts5YY_MAX_SHIFT ){ + fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; + } + fts5yytos = fts5yypParser->fts5yytos; + fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState; + fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor; + fts5yytos->minor.fts5yy0 = fts5yyMinor; + fts5yyTraceShift(fts5yypParser, fts5yyNewState); +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static const struct { + fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} fts5yyRuleInfo[] = { + { 16, 1 }, + { 17, 3 }, + { 17, 3 }, + { 17, 3 }, + { 17, 3 }, + { 17, 1 }, + { 19, 1 }, + { 19, 2 }, + { 18, 1 }, + { 18, 3 }, + { 21, 4 }, + { 21, 3 }, + { 21, 1 }, + { 21, 2 }, + { 22, 2 }, + { 22, 1 }, + { 20, 1 }, + { 20, 5 }, + { 23, 1 }, + { 23, 2 }, + { 25, 0 }, + { 25, 2 }, + { 24, 4 }, + { 24, 2 }, + { 26, 1 }, + { 26, 0 }, +}; + +static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void fts5yy_reduce( + fts5yyParser *fts5yypParser, /* The parser */ + unsigned int fts5yyruleno /* Number of the rule by which to reduce */ +){ + int fts5yygoto; /* The next state */ + int fts5yyact; /* The next action */ + fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */ + int fts5yysize; /* Amount to pop the stack */ + sqlite3Fts5ParserARG_FETCH; + fts5yymsp = fts5yypParser->fts5yytos; +#ifndef NDEBUG + if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ + fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; + fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt, + fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno); + } +#endif /* NDEBUG */ + + /* Check that the stack is large enough to grow by a single entry + ** if the RHS of the rule is empty. This ensures that there is room + ** enough on the stack to push the LHS value */ + if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){ +#ifdef fts5YYTRACKMAXSTACKDEPTH + if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)); + } +#endif +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1] ){ + fts5yyStackOverflow(fts5yypParser); + return; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yyStackOverflow(fts5yypParser); + return; + } + fts5yymsp = fts5yypParser->fts5yytos; + } +#endif + } + + switch( fts5yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ +/********** Begin reduce actions **********************************************/ + fts5YYMINORTYPE fts5yylhsminor; + case 0: /* input ::= expr */ +#line 82 "fts5parse.y" +{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); } +#line 887 "fts5parse.c" + break; + case 1: /* expr ::= expr AND expr */ +#line 92 "fts5parse.y" +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); +} +#line 894 "fts5parse.c" + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 2: /* expr ::= expr OR expr */ +#line 95 "fts5parse.y" +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); +} +#line 902 "fts5parse.c" + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 3: /* expr ::= expr NOT expr */ +#line 98 "fts5parse.y" +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); +} +#line 910 "fts5parse.c" + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 4: /* expr ::= LP expr RP */ +#line 102 "fts5parse.y" +{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;} +#line 916 "fts5parse.c" + break; + case 5: /* expr ::= exprlist */ + case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6); +#line 103 "fts5parse.y" +{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;} +#line 922 "fts5parse.c" + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 7: /* exprlist ::= exprlist cnearset */ +#line 106 "fts5parse.y" +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24); +} +#line 930 "fts5parse.c" + fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 8: /* cnearset ::= nearset */ +#line 110 "fts5parse.y" +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); +} +#line 938 "fts5parse.c" + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 9: /* cnearset ::= colset COLON nearset */ +#line 113 "fts5parse.y" +{ + sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy46, fts5yymsp[-2].minor.fts5yy11); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); +} +#line 947 "fts5parse.c" + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 10: /* colset ::= MINUS LCP colsetlist RCP */ +#line 123 "fts5parse.y" +{ + fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); +} +#line 955 "fts5parse.c" + break; + case 11: /* colset ::= LCP colsetlist RCP */ +#line 126 "fts5parse.y" +{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; } +#line 960 "fts5parse.c" + break; + case 12: /* colset ::= STRING */ +#line 127 "fts5parse.y" +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} +#line 967 "fts5parse.c" + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 13: /* colset ::= MINUS STRING */ +#line 130 "fts5parse.y" +{ + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); +} +#line 976 "fts5parse.c" + break; + case 14: /* colsetlist ::= colsetlist STRING */ +#line 135 "fts5parse.y" +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); } +#line 982 "fts5parse.c" + fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 15: /* colsetlist ::= STRING */ +#line 137 "fts5parse.y" +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} +#line 990 "fts5parse.c" + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 16: /* nearset ::= phrase */ +#line 146 "fts5parse.y" +{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } +#line 996 "fts5parse.c" + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 17: /* nearset ::= STRING LP nearphrases neardist_opt RP */ +#line 147 "fts5parse.y" +{ + sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0); + sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0); + fts5yylhsminor.fts5yy46 = fts5yymsp[-2].minor.fts5yy46; +} +#line 1006 "fts5parse.c" + fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 18: /* nearphrases ::= phrase */ +#line 153 "fts5parse.y" +{ + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); +} +#line 1014 "fts5parse.c" + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 19: /* nearphrases ::= nearphrases phrase */ +#line 156 "fts5parse.y" +{ + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53); +} +#line 1022 "fts5parse.c" + fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 20: /* neardist_opt ::= */ +#line 163 "fts5parse.y" +{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; } +#line 1028 "fts5parse.c" + break; + case 21: /* neardist_opt ::= COMMA STRING */ +#line 164 "fts5parse.y" +{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; } +#line 1033 "fts5parse.c" + break; + case 22: /* phrase ::= phrase PLUS STRING star_opt */ +#line 176 "fts5parse.y" +{ + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); +} +#line 1040 "fts5parse.c" + fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53; + break; + case 23: /* phrase ::= STRING star_opt */ +#line 179 "fts5parse.y" +{ + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); +} +#line 1048 "fts5parse.c" + fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53; + break; + case 24: /* star_opt ::= STAR */ +#line 188 "fts5parse.y" +{ fts5yymsp[0].minor.fts5yy4 = 1; } +#line 1054 "fts5parse.c" + break; + case 25: /* star_opt ::= */ +#line 189 "fts5parse.y" +{ fts5yymsp[1].minor.fts5yy4 = 0; } +#line 1059 "fts5parse.c" + break; + default: + break; +/********** End reduce actions ************************************************/ + }; + assert( fts5yyrulenofts5YY_MAX_SHIFT ){ + fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; + } + fts5yymsp -= fts5yysize-1; + fts5yypParser->fts5yytos = fts5yymsp; + fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; + fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; + fts5yyTraceShift(fts5yypParser, fts5yyact); + }else{ + assert( fts5yyact == fts5YY_ACCEPT_ACTION ); + fts5yypParser->fts5yytos -= fts5yysize; + fts5yy_accept(fts5yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +#ifndef fts5YYNOERRORRECOVERY +static void fts5yy_parse_failed( + fts5yyParser *fts5yypParser /* The parser */ +){ + sqlite3Fts5ParserARG_FETCH; +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt); + } +#endif + while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ +/************ Begin %parse_failure code ***************************************/ +/************ End %parse_failure code *****************************************/ + sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} +#endif /* fts5YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void fts5yy_syntax_error( + fts5yyParser *fts5yypParser, /* The parser */ + int fts5yymajor, /* The major type of the error token */ + sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */ +){ + sqlite3Fts5ParserARG_FETCH; +#define FTS5TOKEN fts5yyminor +/************ Begin %syntax_error code ****************************************/ +#line 30 "fts5parse.y" + + UNUSED_PARAM(fts5yymajor); /* Silence a compiler warning */ + sqlite3Fts5ParseError( + pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p + ); +#line 1124 "fts5parse.c" +/************ End %syntax_error code ******************************************/ + sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void fts5yy_accept( + fts5yyParser *fts5yypParser /* The parser */ +){ + sqlite3Fts5ParserARG_FETCH; +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt); + } +#endif +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif + assert( fts5yypParser->fts5yytos==fts5yypParser->fts5yystack ); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +/*********** Begin %parse_accept code *****************************************/ +/*********** End %parse_accept code *******************************************/ + sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "sqlite3Fts5ParserAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** Outputs: +** None. +*/ +static void sqlite3Fts5Parser( + void *fts5yyp, /* The parser */ + int fts5yymajor, /* The major token code number */ + sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The value for the token */ + sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */ +){ + fts5YYMINORTYPE fts5yyminorunion; + unsigned int fts5yyact; /* The parser action. */ +#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) + int fts5yyendofinput; /* True if we are at the end of input */ +#endif +#ifdef fts5YYERRORSYMBOL + int fts5yyerrorhit = 0; /* True if fts5yymajor has invoked an error */ +#endif + fts5yyParser *fts5yypParser; /* The parser */ + + fts5yypParser = (fts5yyParser*)fts5yyp; + assert( fts5yypParser->fts5yytos!=0 ); +#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) + fts5yyendofinput = (fts5yymajor==0); +#endif + sqlite3Fts5ParserARG_STORE; + +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sInput '%s'\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]); + } +#endif + + do{ + fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor); + if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ + fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt--; +#endif + fts5yymajor = fts5YYNOCODE; + }else if( fts5yyact <= fts5YY_MAX_REDUCE ){ + fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE); + }else{ + assert( fts5yyact == fts5YY_ERROR_ACTION ); + fts5yyminorunion.fts5yy0 = fts5yyminor; +#ifdef fts5YYERRORSYMBOL + int fts5yymx; +#endif +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sSyntax Error!\n",fts5yyTracePrompt); + } +#endif +#ifdef fts5YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( fts5yypParser->fts5yyerrcnt<0 ){ + fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor); + } + fts5yymx = fts5yypParser->fts5yytos->major; + if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){ +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sDiscard input token %s\n", + fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]); + } +#endif + fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion); + fts5yymajor = fts5YYNOCODE; + }else{ + while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack + && fts5yymx != fts5YYERRORSYMBOL + && (fts5yyact = fts5yy_find_reduce_action( + fts5yypParser->fts5yytos->stateno, + fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE + ){ + fts5yy_pop_parser_stack(fts5yypParser); + } + if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){ + fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); + fts5yy_parse_failed(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif + fts5yymajor = fts5YYNOCODE; + }else if( fts5yymx!=fts5YYERRORSYMBOL ){ + fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor); + } + } + fts5yypParser->fts5yyerrcnt = 3; + fts5yyerrorhit = 1; +#elif defined(fts5YYNOERRORRECOVERY) + /* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor); + fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); + fts5yymajor = fts5YYNOCODE; + +#else /* fts5YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( fts5yypParser->fts5yyerrcnt<=0 ){ + fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor); + } + fts5yypParser->fts5yyerrcnt = 3; + fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); + if( fts5yyendofinput ){ + fts5yy_parse_failed(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif + } + fts5yymajor = fts5YYNOCODE; +#endif + } + }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ); +#ifndef NDEBUG + if( fts5yyTraceFILE ){ + fts5yyStackEntry *i; + char cDiv = '['; + fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt); + for(i=&fts5yypParser->fts5yystack[1]; i<=fts5yypParser->fts5yytos; i++){ + fprintf(fts5yyTraceFILE,"%c%s", cDiv, fts5yyTokenName[i->major]); + cDiv = ' '; + } + fprintf(fts5yyTraceFILE,"]\n"); + } +#endif + return; +} + +#line 1 "fts5_aux.c" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +*/ + + +/* #include "fts5Int.h" */ +#include /* amalgamator: keep */ + +/* +** Object used to iterate through all "coalesced phrase instances" in +** a single column of the current row. If the phrase instances in the +** column being considered do not overlap, this object simply iterates +** through them. Or, if they do overlap (share one or more tokens in +** common), each set of overlapping instances is treated as a single +** match. See documentation for the highlight() auxiliary function for +** details. +** +** Usage is: +** +** for(rc = fts5CInstIterNext(pApi, pFts, iCol, &iter); +** (rc==SQLITE_OK && 0==fts5CInstIterEof(&iter); +** rc = fts5CInstIterNext(&iter) +** ){ +** printf("instance starts at %d, ends at %d\n", iter.iStart, iter.iEnd); +** } +** +*/ +typedef struct CInstIter CInstIter; +struct CInstIter { + const Fts5ExtensionApi *pApi; /* API offered by current FTS version */ + Fts5Context *pFts; /* First arg to pass to pApi functions */ + int iCol; /* Column to search */ + int iInst; /* Next phrase instance index */ + int nInst; /* Total number of phrase instances */ + + /* Output variables */ + int iStart; /* First token in coalesced phrase instance */ + int iEnd; /* Last token in coalesced phrase instance */ +}; + +/* +** Advance the iterator to the next coalesced phrase instance. Return +** an SQLite error code if an error occurs, or SQLITE_OK otherwise. +*/ +static int fts5CInstIterNext(CInstIter *pIter){ + int rc = SQLITE_OK; + pIter->iStart = -1; + pIter->iEnd = -1; + + while( rc==SQLITE_OK && pIter->iInstnInst ){ + int ip; int ic; int io; + rc = pIter->pApi->xInst(pIter->pFts, pIter->iInst, &ip, &ic, &io); + if( rc==SQLITE_OK ){ + if( ic==pIter->iCol ){ + int iEnd = io - 1 + pIter->pApi->xPhraseSize(pIter->pFts, ip); + if( pIter->iStart<0 ){ + pIter->iStart = io; + pIter->iEnd = iEnd; + }else if( io<=pIter->iEnd ){ + if( iEnd>pIter->iEnd ) pIter->iEnd = iEnd; + }else{ + break; + } + } + pIter->iInst++; + } + } + + return rc; +} + +/* +** Initialize the iterator object indicated by the final parameter to +** iterate through coalesced phrase instances in column iCol. +*/ +static int fts5CInstIterInit( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + int iCol, + CInstIter *pIter +){ + int rc; + + memset(pIter, 0, sizeof(CInstIter)); + pIter->pApi = pApi; + pIter->pFts = pFts; + pIter->iCol = iCol; + rc = pApi->xInstCount(pFts, &pIter->nInst); + + if( rc==SQLITE_OK ){ + rc = fts5CInstIterNext(pIter); + } + + return rc; +} + + + +/************************************************************************* +** Start of highlight() implementation. +*/ +typedef struct HighlightContext HighlightContext; +struct HighlightContext { + CInstIter iter; /* Coalesced Instance Iterator */ + int iPos; /* Current token offset in zIn[] */ + int iRangeStart; /* First token to include */ + int iRangeEnd; /* If non-zero, last token to include */ + const char *zOpen; /* Opening highlight */ + const char *zClose; /* Closing highlight */ + const char *zIn; /* Input text */ + int nIn; /* Size of input text in bytes */ + int iOff; /* Current offset within zIn[] */ + char *zOut; /* Output value */ +}; + +/* +** Append text to the HighlightContext output string - p->zOut. Argument +** z points to a buffer containing n bytes of text to append. If n is +** negative, everything up until the first '\0' is appended to the output. +** +** If *pRc is set to any value other than SQLITE_OK when this function is +** called, it is a no-op. If an error (i.e. an OOM condition) is encountered, +** *pRc is set to an error code before returning. +*/ +static void fts5HighlightAppend( + int *pRc, + HighlightContext *p, + const char *z, int n +){ + if( *pRc==SQLITE_OK ){ + if( n<0 ) n = (int)strlen(z); + p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z); + if( p->zOut==0 ) *pRc = SQLITE_NOMEM; + } +} + +/* +** Tokenizer callback used by implementation of highlight() function. +*/ +static int fts5HighlightCb( + void *pContext, /* Pointer to HighlightContext object */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStartOff, /* Start offset of token */ + int iEndOff /* End offset of token */ +){ + HighlightContext *p = (HighlightContext*)pContext; + int rc = SQLITE_OK; + int iPos; + + UNUSED_PARAM2(pToken, nToken); + + if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK; + iPos = p->iPos++; + + if( p->iRangeEnd>0 ){ + if( iPosiRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK; + if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff; + } + + if( iPos==p->iter.iStart ){ + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff); + fts5HighlightAppend(&rc, p, p->zOpen, -1); + p->iOff = iStartOff; + } + + if( iPos==p->iter.iEnd ){ + if( p->iRangeEnd && p->iter.iStartiRangeStart ){ + fts5HighlightAppend(&rc, p, p->zOpen, -1); + } + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); + fts5HighlightAppend(&rc, p, p->zClose, -1); + p->iOff = iEndOff; + if( rc==SQLITE_OK ){ + rc = fts5CInstIterNext(&p->iter); + } + } + + if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); + p->iOff = iEndOff; + if( iPos>=p->iter.iStart && iPositer.iEnd ){ + fts5HighlightAppend(&rc, p, p->zClose, -1); + } + } + + return rc; +} + +/* +** Implementation of highlight() function. +*/ +static void fts5HighlightFunction( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + HighlightContext ctx; + int rc; + int iCol; + + if( nVal!=3 ){ + const char *zErr = "wrong number of arguments to function highlight()"; + sqlite3_result_error(pCtx, zErr, -1); + return; + } + + iCol = sqlite3_value_int(apVal[0]); + memset(&ctx, 0, sizeof(HighlightContext)); + ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); + ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); + rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); + + if( ctx.zIn ){ + if( rc==SQLITE_OK ){ + rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); + } + + if( rc==SQLITE_OK ){ + rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); + } + fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); + + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); + } + sqlite3_free(ctx.zOut); + } + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + } +} +/* +** End of highlight() implementation. +**************************************************************************/ + +/* +** Context object passed to the fts5SentenceFinderCb() function. +*/ +typedef struct Fts5SFinder Fts5SFinder; +struct Fts5SFinder { + int iPos; /* Current token position */ + int nFirstAlloc; /* Allocated size of aFirst[] */ + int nFirst; /* Number of entries in aFirst[] */ + int *aFirst; /* Array of first token in each sentence */ + const char *zDoc; /* Document being tokenized */ +}; + +/* +** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if +** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an +** error occurs. +*/ +static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ + if( p->nFirstAlloc==p->nFirst ){ + int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; + int *aNew; + + aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int)); + if( aNew==0 ) return SQLITE_NOMEM; + p->aFirst = aNew; + p->nFirstAlloc = nNew; + } + p->aFirst[p->nFirst++] = iAdd; + return SQLITE_OK; +} + +/* +** This function is an xTokenize() callback used by the auxiliary snippet() +** function. Its job is to identify tokens that are the first in a sentence. +** For each such token, an entry is added to the SFinder.aFirst[] array. +*/ +static int fts5SentenceFinderCb( + void *pContext, /* Pointer to HighlightContext object */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStartOff, /* Start offset of token */ + int iEndOff /* End offset of token */ +){ + int rc = SQLITE_OK; + + UNUSED_PARAM2(pToken, nToken); + UNUSED_PARAM(iEndOff); + + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ + Fts5SFinder *p = (Fts5SFinder*)pContext; + if( p->iPos>0 ){ + int i; + char c = 0; + for(i=iStartOff-1; i>=0; i--){ + c = p->zDoc[i]; + if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) break; + } + if( i!=iStartOff-1 && (c=='.' || c==':') ){ + rc = fts5SentenceFinderAdd(p, p->iPos); + } + }else{ + rc = fts5SentenceFinderAdd(p, 0); + } + p->iPos++; + } + return rc; +} + +static int fts5SnippetScore( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + int nDocsize, /* Size of column in tokens */ + unsigned char *aSeen, /* Array with one element per query phrase */ + int iCol, /* Column to score */ + int iPos, /* Starting offset to score */ + int nToken, /* Max tokens per snippet */ + int *pnScore, /* OUT: Score */ + int *piPos /* OUT: Adjusted offset */ +){ + int rc; + int i; + int ip = 0; + int ic = 0; + int iOff = 0; + int iFirst = -1; + int nInst; + int nScore = 0; + int iLast = 0; + + rc = pApi->xInstCount(pFts, &nInst); + for(i=0; ixInst(pFts, i, &ip, &ic, &iOff); + if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){ + nScore += (aSeen[ip] ? 1 : 1000); + aSeen[ip] = 1; + if( iFirst<0 ) iFirst = iOff; + iLast = iOff + pApi->xPhraseSize(pFts, ip); + } + } + + *pnScore = nScore; + if( piPos ){ + int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2; + if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken; + if( iAdj<0 ) iAdj = 0; + *piPos = iAdj; + } + + return rc; +} + +/* +** Implementation of snippet() function. +*/ +static void fts5SnippetFunction( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + HighlightContext ctx; + int rc = SQLITE_OK; /* Return code */ + int iCol; /* 1st argument to snippet() */ + const char *zEllips; /* 4th argument to snippet() */ + int nToken; /* 5th argument to snippet() */ + int nInst = 0; /* Number of instance matches this row */ + int i; /* Used to iterate through instances */ + int nPhrase; /* Number of phrases in query */ + unsigned char *aSeen; /* Array of "seen instance" flags */ + int iBestCol; /* Column containing best snippet */ + int iBestStart = 0; /* First token of best snippet */ + int nBestScore = 0; /* Score of best snippet */ + int nColSize = 0; /* Total size of iBestCol in tokens */ + Fts5SFinder sFinder; /* Used to find the beginnings of sentences */ + int nCol; + + if( nVal!=5 ){ + const char *zErr = "wrong number of arguments to function snippet()"; + sqlite3_result_error(pCtx, zErr, -1); + return; + } + + nCol = pApi->xColumnCount(pFts); + memset(&ctx, 0, sizeof(HighlightContext)); + iCol = sqlite3_value_int(apVal[0]); + ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); + ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); + zEllips = (const char*)sqlite3_value_text(apVal[3]); + nToken = sqlite3_value_int(apVal[4]); + + iBestCol = (iCol>=0 ? iCol : 0); + nPhrase = pApi->xPhraseCount(pFts); + aSeen = sqlite3_malloc(nPhrase); + if( aSeen==0 ){ + rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + rc = pApi->xInstCount(pFts, &nInst); + } + + memset(&sFinder, 0, sizeof(Fts5SFinder)); + for(i=0; ixColumnText(pFts, i, &sFinder.zDoc, &nDoc); + if( rc!=SQLITE_OK ) break; + rc = pApi->xTokenize(pFts, + sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb + ); + if( rc!=SQLITE_OK ) break; + rc = pApi->xColumnSize(pFts, i, &nDocsize); + if( rc!=SQLITE_OK ) break; + + for(ii=0; rc==SQLITE_OK && iixInst(pFts, ii, &ip, &ic, &io); + if( ic!=i || rc!=SQLITE_OK ) continue; + memset(aSeen, 0, nPhrase); + rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, + io, nToken, &nScore, &iAdj + ); + if( rc==SQLITE_OK && nScore>nBestScore ){ + nBestScore = nScore; + iBestCol = i; + iBestStart = iAdj; + nColSize = nDocsize; + } + + if( rc==SQLITE_OK && sFinder.nFirst && nDocsize>nToken ){ + for(jj=0; jj<(sFinder.nFirst-1); jj++){ + if( sFinder.aFirst[jj+1]>io ) break; + } + + if( sFinder.aFirst[jj]nBestScore ){ + nBestScore = nScore; + iBestCol = i; + iBestStart = sFinder.aFirst[jj]; + nColSize = nDocsize; + } + } + } + } + } + } + + if( rc==SQLITE_OK ){ + rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); + } + if( rc==SQLITE_OK && nColSize==0 ){ + rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); + } + if( ctx.zIn ){ + if( rc==SQLITE_OK ){ + rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); + } + + ctx.iRangeStart = iBestStart; + ctx.iRangeEnd = iBestStart + nToken - 1; + + if( iBestStart>0 ){ + fts5HighlightAppend(&rc, &ctx, zEllips, -1); + } + + /* Advance iterator ctx.iter so that it points to the first coalesced + ** phrase instance at or following position iBestStart. */ + while( ctx.iter.iStart>=0 && ctx.iter.iStartxTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); + } + if( ctx.iRangeEnd>=(nColSize-1) ){ + fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); + }else{ + fts5HighlightAppend(&rc, &ctx, zEllips, -1); + } + } + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); + }else{ + sqlite3_result_error_code(pCtx, rc); + } + sqlite3_free(ctx.zOut); + sqlite3_free(aSeen); + sqlite3_free(sFinder.aFirst); +} + +/************************************************************************/ + +/* +** The first time the bm25() function is called for a query, an instance +** of the following structure is allocated and populated. +*/ +typedef struct Fts5Bm25Data Fts5Bm25Data; +struct Fts5Bm25Data { + int nPhrase; /* Number of phrases in query */ + double avgdl; /* Average number of tokens in each row */ + double *aIDF; /* IDF for each phrase */ + double *aFreq; /* Array used to calculate phrase freq. */ +}; + +/* +** Callback used by fts5Bm25GetData() to count the number of rows in the +** table matched by each individual phrase within the query. +*/ +static int fts5CountCb( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + void *pUserData /* Pointer to sqlite3_int64 variable */ +){ + sqlite3_int64 *pn = (sqlite3_int64*)pUserData; + UNUSED_PARAM2(pApi, pFts); + (*pn)++; + return SQLITE_OK; +} + +/* +** Set *ppData to point to the Fts5Bm25Data object for the current query. +** If the object has not already been allocated, allocate and populate it +** now. +*/ +static int fts5Bm25GetData( + const Fts5ExtensionApi *pApi, + Fts5Context *pFts, + Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */ +){ + int rc = SQLITE_OK; /* Return code */ + Fts5Bm25Data *p; /* Object to return */ + + p = pApi->xGetAuxdata(pFts, 0); + if( p==0 ){ + int nPhrase; /* Number of phrases in query */ + sqlite3_int64 nRow = 0; /* Number of rows in table */ + sqlite3_int64 nToken = 0; /* Number of tokens in table */ + int nByte; /* Bytes of space to allocate */ + int i; + + /* Allocate the Fts5Bm25Data object */ + nPhrase = pApi->xPhraseCount(pFts); + nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double); + p = (Fts5Bm25Data*)sqlite3_malloc(nByte); + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(p, 0, nByte); + p->nPhrase = nPhrase; + p->aIDF = (double*)&p[1]; + p->aFreq = &p->aIDF[nPhrase]; + } + + /* Calculate the average document length for this FTS5 table */ + if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow); + if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken); + if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow; + + /* Calculate an IDF for each phrase in the query */ + for(i=0; rc==SQLITE_OK && ixQueryPhrase(pFts, i, (void*)&nHit, fts5CountCb); + if( rc==SQLITE_OK ){ + /* Calculate the IDF (Inverse Document Frequency) for phrase i. + ** This is done using the standard BM25 formula as found on wikipedia: + ** + ** IDF = log( (N - nHit + 0.5) / (nHit + 0.5) ) + ** + ** where "N" is the total number of documents in the set and nHit + ** is the number that contain at least one instance of the phrase + ** under consideration. + ** + ** The problem with this is that if (N < 2*nHit), the IDF is + ** negative. Which is undesirable. So the mimimum allowable IDF is + ** (1e-6) - roughly the same as a term that appears in just over + ** half of set of 5,000,000 documents. */ + double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) ); + if( idf<=0.0 ) idf = 1e-6; + p->aIDF[i] = idf; + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(p); + }else{ + rc = pApi->xSetAuxdata(pFts, p, sqlite3_free); + } + if( rc!=SQLITE_OK ) p = 0; + } + *ppData = p; + return rc; +} + +/* +** Implementation of bm25() function. +*/ +static void fts5Bm25Function( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +){ + const double k1 = 1.2; /* Constant "k1" from BM25 formula */ + const double b = 0.75; /* Constant "b" from BM25 formula */ + int rc = SQLITE_OK; /* Error code */ + double score = 0.0; /* SQL function return value */ + Fts5Bm25Data *pData; /* Values allocated/calculated once only */ + int i; /* Iterator variable */ + int nInst = 0; /* Value returned by xInstCount() */ + double D = 0.0; /* Total number of tokens in row */ + double *aFreq = 0; /* Array of phrase freq. for current row */ + + /* Calculate the phrase frequency (symbol "f(qi,D)" in the documentation) + ** for each phrase in the query for the current row. */ + rc = fts5Bm25GetData(pApi, pFts, &pData); + if( rc==SQLITE_OK ){ + aFreq = pData->aFreq; + memset(aFreq, 0, sizeof(double) * pData->nPhrase); + rc = pApi->xInstCount(pFts, &nInst); + } + for(i=0; rc==SQLITE_OK && ixInst(pFts, i, &ip, &ic, &io); + if( rc==SQLITE_OK ){ + double w = (nVal > ic) ? sqlite3_value_double(apVal[ic]) : 1.0; + aFreq[ip] += w; + } + } + + /* Figure out the total size of the current row in tokens. */ + if( rc==SQLITE_OK ){ + int nTok; + rc = pApi->xColumnSize(pFts, -1, &nTok); + D = (double)nTok; + } + + /* Determine the BM25 score for the current row. */ + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + score += pData->aIDF[i] * ( + ( aFreq[i] * (k1 + 1.0) ) / + ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) + ); + } + + /* If no error has occurred, return the calculated score. Otherwise, + ** throw an SQL exception. */ + if( rc==SQLITE_OK ){ + sqlite3_result_double(pCtx, -1.0 * score); + }else{ + sqlite3_result_error_code(pCtx, rc); + } +} + +static int sqlite3Fts5AuxInit(fts5_api *pApi){ + struct Builtin { + const char *zFunc; /* Function name (nul-terminated) */ + void *pUserData; /* User-data pointer */ + fts5_extension_function xFunc;/* Callback function */ + void (*xDestroy)(void*); /* Destructor function */ + } aBuiltin [] = { + { "snippet", 0, fts5SnippetFunction, 0 }, + { "highlight", 0, fts5HighlightFunction, 0 }, + { "bm25", 0, fts5Bm25Function, 0 }, + }; + int rc = SQLITE_OK; /* Return code */ + int i; /* To iterate through builtin functions */ + + for(i=0; rc==SQLITE_OK && ixCreateFunction(pApi, + aBuiltin[i].zFunc, + aBuiltin[i].pUserData, + aBuiltin[i].xFunc, + aBuiltin[i].xDestroy + ); + } + + return rc; +} + + + +#line 1 "fts5_buffer.c" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +*/ + + + +/* #include "fts5Int.h" */ + +static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ + if( (u32)pBuf->nSpacenSpace ? pBuf->nSpace : 64; + u8 *pNew; + while( nNewp, nNew); + if( pNew==0 ){ + *pRc = SQLITE_NOMEM; + return 1; + }else{ + pBuf->nSpace = nNew; + pBuf->p = pNew; + } + } + return 0; +} + + +/* +** Encode value iVal as an SQLite varint and append it to the buffer object +** pBuf. If an OOM error occurs, set the error code in p. +*/ +static void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){ + if( fts5BufferGrow(pRc, pBuf, 9) ) return; + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iVal); +} + +static void sqlite3Fts5Put32(u8 *aBuf, int iVal){ + aBuf[0] = (iVal>>24) & 0x00FF; + aBuf[1] = (iVal>>16) & 0x00FF; + aBuf[2] = (iVal>> 8) & 0x00FF; + aBuf[3] = (iVal>> 0) & 0x00FF; +} + +static int sqlite3Fts5Get32(const u8 *aBuf){ + return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3]; +} + +/* +** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set +** the error code in p. If an error has already occurred when this function +** is called, it is a no-op. +*/ +static void sqlite3Fts5BufferAppendBlob( + int *pRc, + Fts5Buffer *pBuf, + u32 nData, + const u8 *pData +){ + assert_nc( *pRc || nData>=0 ); + if( fts5BufferGrow(pRc, pBuf, nData) ) return; + memcpy(&pBuf->p[pBuf->n], pData, nData); + pBuf->n += nData; +} + +/* +** Append the nul-terminated string zStr to the buffer pBuf. This function +** ensures that the byte following the buffer data is set to 0x00, even +** though this byte is not included in the pBuf->n count. +*/ +static void sqlite3Fts5BufferAppendString( + int *pRc, + Fts5Buffer *pBuf, + const char *zStr +){ + int nStr = (int)strlen(zStr); + sqlite3Fts5BufferAppendBlob(pRc, pBuf, nStr+1, (const u8*)zStr); + pBuf->n--; +} + +/* +** Argument zFmt is a printf() style format string. This function performs +** the printf() style processing, then appends the results to buffer pBuf. +** +** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte +** following the buffer data is set to 0x00, even though this byte is not +** included in the pBuf->n count. +*/ +static void sqlite3Fts5BufferAppendPrintf( + int *pRc, + Fts5Buffer *pBuf, + char *zFmt, ... +){ + if( *pRc==SQLITE_OK ){ + char *zTmp; + va_list ap; + va_start(ap, zFmt); + zTmp = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + + if( zTmp==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + sqlite3Fts5BufferAppendString(pRc, pBuf, zTmp); + sqlite3_free(zTmp); + } + } +} + +static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + va_start(ap, zFmt); + zRet = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( zRet==0 ){ + *pRc = SQLITE_NOMEM; + } + } + return zRet; +} + + +/* +** Free any buffer allocated by pBuf. Zero the structure before returning. +*/ +static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){ + sqlite3_free(pBuf->p); + memset(pBuf, 0, sizeof(Fts5Buffer)); +} + +/* +** Zero the contents of the buffer object. But do not free the associated +** memory allocation. +*/ +static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){ + pBuf->n = 0; +} + +/* +** Set the buffer to contain nData/pData. If an OOM error occurs, leave an +** the error code in p. If an error has already occurred when this function +** is called, it is a no-op. +*/ +static void sqlite3Fts5BufferSet( + int *pRc, + Fts5Buffer *pBuf, + int nData, + const u8 *pData +){ + pBuf->n = 0; + sqlite3Fts5BufferAppendBlob(pRc, pBuf, nData, pData); +} + +static int sqlite3Fts5PoslistNext64( + const u8 *a, int n, /* Buffer containing poslist */ + int *pi, /* IN/OUT: Offset within a[] */ + i64 *piOff /* IN/OUT: Current offset */ +){ + int i = *pi; + if( i>=n ){ + /* EOF */ + *piOff = -1; + return 1; + }else{ + i64 iOff = *piOff; + int iVal; + fts5FastGetVarint32(a, i, iVal); + if( iVal==1 ){ + fts5FastGetVarint32(a, i, iVal); + iOff = ((i64)iVal) << 32; + fts5FastGetVarint32(a, i, iVal); + } + *piOff = iOff + (iVal-2); + *pi = i; + return 0; + } +} + + +/* +** Advance the iterator object passed as the only argument. Return true +** if the iterator reaches EOF, or false otherwise. +*/ +static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){ + if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) ){ + pIter->bEof = 1; + } + return pIter->bEof; +} + +static int sqlite3Fts5PoslistReaderInit( + const u8 *a, int n, /* Poslist buffer to iterate through */ + Fts5PoslistReader *pIter /* Iterator object to initialize */ +){ + memset(pIter, 0, sizeof(*pIter)); + pIter->a = a; + pIter->n = n; + sqlite3Fts5PoslistReaderNext(pIter); + return pIter->bEof; +} + +/* +** Append position iPos to the position list being accumulated in buffer +** pBuf, which must be already be large enough to hold the new data. +** The previous position written to this list is *piPrev. *piPrev is set +** to iPos before returning. +*/ +static void sqlite3Fts5PoslistSafeAppend( + Fts5Buffer *pBuf, + i64 *piPrev, + i64 iPos +){ + static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; + if( (iPos & colmask) != (*piPrev & colmask) ){ + pBuf->p[pBuf->n++] = 1; + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); + *piPrev = (iPos & colmask); + } + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2); + *piPrev = iPos; +} + +static int sqlite3Fts5PoslistWriterAppend( + Fts5Buffer *pBuf, + Fts5PoslistWriter *pWriter, + i64 iPos +){ + int rc = 0; /* Initialized only to suppress erroneous warning from Clang */ + if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc; + sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos); + return SQLITE_OK; +} + +static void *sqlite3Fts5MallocZero(int *pRc, int nByte){ + void *pRet = 0; + if( *pRc==SQLITE_OK ){ + pRet = sqlite3_malloc(nByte); + if( pRet==0 && nByte>0 ){ + *pRc = SQLITE_NOMEM; + }else{ + memset(pRet, 0, nByte); + } + } + return pRet; +} + +/* +** Return a nul-terminated copy of the string indicated by pIn. If nIn +** is non-negative, then it is the length of the string in bytes. Otherwise, +** the length of the string is determined using strlen(). +** +** It is the responsibility of the caller to eventually free the returned +** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. +*/ +static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ + char *zRet = 0; + if( *pRc==SQLITE_OK ){ + if( nIn<0 ){ + nIn = (int)strlen(pIn); + } + zRet = (char*)sqlite3_malloc(nIn+1); + if( zRet ){ + memcpy(zRet, pIn, nIn); + zRet[nIn] = '\0'; + }else{ + *pRc = SQLITE_NOMEM; + } + } + return zRet; +} + + +/* +** Return true if character 't' may be part of an FTS5 bareword, or false +** otherwise. Characters that may be part of barewords: +** +** * All non-ASCII characters, +** * The 52 upper and lower case ASCII characters, and +** * The 10 integer ASCII characters. +** * The underscore character "_" (0x5F). +** * The unicode "subsitute" character (0x1A). +*/ +static int sqlite3Fts5IsBareword(char t){ + u8 aBareword[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 .. 0x2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30 .. 0x3F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 .. 0x4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50 .. 0x5F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 .. 0x6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70 .. 0x7F */ + }; + + return (t & 0x80) || aBareword[(int)t]; +} + + +/************************************************************************* +*/ +typedef struct Fts5TermsetEntry Fts5TermsetEntry; +struct Fts5TermsetEntry { + char *pTerm; + int nTerm; + int iIdx; /* Index (main or aPrefix[] entry) */ + Fts5TermsetEntry *pNext; +}; + +struct Fts5Termset { + Fts5TermsetEntry *apHash[512]; +}; + +static int sqlite3Fts5TermsetNew(Fts5Termset **pp){ + int rc = SQLITE_OK; + *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset)); + return rc; +} + +static int sqlite3Fts5TermsetAdd( + Fts5Termset *p, + int iIdx, + const char *pTerm, int nTerm, + int *pbPresent +){ + int rc = SQLITE_OK; + *pbPresent = 0; + if( p ){ + int i; + u32 hash = 13; + Fts5TermsetEntry *pEntry; + + /* Calculate a hash value for this term. This is the same hash checksum + ** used by the fts5_hash.c module. This is not important for correct + ** operation of the module, but is necessary to ensure that some tests + ** designed to produce hash table collisions really do work. */ + for(i=nTerm-1; i>=0; i--){ + hash = (hash << 3) ^ hash ^ pTerm[i]; + } + hash = (hash << 3) ^ hash ^ iIdx; + hash = hash % ArraySize(p->apHash); + + for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){ + if( pEntry->iIdx==iIdx + && pEntry->nTerm==nTerm + && memcmp(pEntry->pTerm, pTerm, nTerm)==0 + ){ + *pbPresent = 1; + break; + } + } + + if( pEntry==0 ){ + pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm); + if( pEntry ){ + pEntry->pTerm = (char*)&pEntry[1]; + pEntry->nTerm = nTerm; + pEntry->iIdx = iIdx; + memcpy(pEntry->pTerm, pTerm, nTerm); + pEntry->pNext = p->apHash[hash]; + p->apHash[hash] = pEntry; + } + } + } + + return rc; +} + +static void sqlite3Fts5TermsetFree(Fts5Termset *p){ + if( p ){ + u32 i; + for(i=0; iapHash); i++){ + Fts5TermsetEntry *pEntry = p->apHash[i]; + while( pEntry ){ + Fts5TermsetEntry *pDel = pEntry; + pEntry = pEntry->pNext; + sqlite3_free(pDel); + } + } + sqlite3_free(p); + } +} + +#line 1 "fts5_config.c" +/* +** 2014 Jun 09 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This is an SQLite module implementing full-text search. +*/ + + +/* #include "fts5Int.h" */ + +#define FTS5_DEFAULT_PAGE_SIZE 4050 +#define FTS5_DEFAULT_AUTOMERGE 4 +#define FTS5_DEFAULT_USERMERGE 4 +#define FTS5_DEFAULT_CRISISMERGE 16 +#define FTS5_DEFAULT_HASHSIZE (1024*1024) + +/* Maximum allowed page size */ +#define FTS5_MAX_PAGE_SIZE (128*1024) + +static int fts5_iswhitespace(char x){ + return (x==' '); +} + +static int fts5_isopenquote(char x){ + return (x=='"' || x=='\'' || x=='[' || x=='`'); +} + +/* +** Argument pIn points to a character that is part of a nul-terminated +** string. Return a pointer to the first character following *pIn in +** the string that is not a white-space character. +*/ +static const char *fts5ConfigSkipWhitespace(const char *pIn){ + const char *p = pIn; + if( p ){ + while( fts5_iswhitespace(*p) ){ p++; } + } + return p; +} + +/* +** Argument pIn points to a character that is part of a nul-terminated +** string. Return a pointer to the first character following *pIn in +** the string that is not a "bareword" character. +*/ +static const char *fts5ConfigSkipBareword(const char *pIn){ + const char *p = pIn; + while ( sqlite3Fts5IsBareword(*p) ) p++; + if( p==pIn ) p = 0; + return p; +} + +static int fts5_isdigit(char a){ + return (a>='0' && a<='9'); +} + + + +static const char *fts5ConfigSkipLiteral(const char *pIn){ + const char *p = pIn; + switch( *p ){ + case 'n': case 'N': + if( sqlite3_strnicmp("null", p, 4)==0 ){ + p = &p[4]; + }else{ + p = 0; + } + break; + + case 'x': case 'X': + p++; + if( *p=='\'' ){ + p++; + while( (*p>='a' && *p<='f') + || (*p>='A' && *p<='F') + || (*p>='0' && *p<='9') + ){ + p++; + } + if( *p=='\'' && 0==((p-pIn)%2) ){ + p++; + }else{ + p = 0; + } + }else{ + p = 0; + } + break; + + case '\'': + p++; + while( p ){ + if( *p=='\'' ){ + p++; + if( *p!='\'' ) break; + } + p++; + if( *p==0 ) p = 0; + } + break; + + default: + /* maybe a number */ + if( *p=='+' || *p=='-' ) p++; + while( fts5_isdigit(*p) ) p++; + + /* At this point, if the literal was an integer, the parse is + ** finished. Or, if it is a floating point value, it may continue + ** with either a decimal point or an 'E' character. */ + if( *p=='.' && fts5_isdigit(p[1]) ){ + p += 2; + while( fts5_isdigit(*p) ) p++; + } + if( p==pIn ) p = 0; + + break; + } + + return p; +} + +/* +** The first character of the string pointed to by argument z is guaranteed +** to be an open-quote character (see function fts5_isopenquote()). +** +** This function searches for the corresponding close-quote character within +** the string and, if found, dequotes the string in place and adds a new +** nul-terminator byte. +** +** If the close-quote is found, the value returned is the byte offset of +** the character immediately following it. Or, if the close-quote is not +** found, -1 is returned. If -1 is returned, the buffer is left in an +** undefined state. +*/ +static int fts5Dequote(char *z){ + char q; + int iIn = 1; + int iOut = 0; + q = z[0]; + + /* Set stack variable q to the close-quote character */ + assert( q=='[' || q=='\'' || q=='"' || q=='`' ); + if( q=='[' ) q = ']'; + + while( ALWAYS(z[iIn]) ){ + if( z[iIn]==q ){ + if( z[iIn+1]!=q ){ + /* Character iIn was the close quote. */ + iIn++; + break; + }else{ + /* Character iIn and iIn+1 form an escaped quote character. Skip + ** the input cursor past both and copy a single quote character + ** to the output buffer. */ + iIn += 2; + z[iOut++] = q; + } + }else{ + z[iOut++] = z[iIn++]; + } + } + + z[iOut] = '\0'; + return iIn; +} + +/* +** Convert an SQL-style quoted string into a normal string by removing +** the quote characters. The conversion is done in-place. If the +** input does not begin with a quote character, then this routine +** is a no-op. +** +** Examples: +** +** "abc" becomes abc +** 'xyz' becomes xyz +** [pqr] becomes pqr +** `mno` becomes mno +*/ +static void sqlite3Fts5Dequote(char *z){ + char quote; /* Quote character (if any ) */ + + assert( 0==fts5_iswhitespace(z[0]) ); + quote = z[0]; + if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ + fts5Dequote(z); + } +} + + +struct Fts5Enum { + const char *zName; + int eVal; +}; +typedef struct Fts5Enum Fts5Enum; + +static int fts5ConfigSetEnum( + const Fts5Enum *aEnum, + const char *zEnum, + int *peVal +){ + int nEnum = (int)strlen(zEnum); + int i; + int iVal = -1; + + for(i=0; aEnum[i].zName; i++){ + if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){ + if( iVal>=0 ) return SQLITE_ERROR; + iVal = aEnum[i].eVal; + } + } + + *peVal = iVal; + return iVal<0 ? SQLITE_ERROR : SQLITE_OK; +} + +/* +** Parse a "special" CREATE VIRTUAL TABLE directive and update +** configuration object pConfig as appropriate. +** +** If successful, object pConfig is updated and SQLITE_OK returned. If +** an error occurs, an SQLite error code is returned and an error message +** may be left in *pzErr. It is the responsibility of the caller to +** eventually free any such error message using sqlite3_free(). +*/ +static int fts5ConfigParseSpecial( + Fts5Global *pGlobal, + Fts5Config *pConfig, /* Configuration object to update */ + const char *zCmd, /* Special command to parse */ + const char *zArg, /* Argument to parse */ + char **pzErr /* OUT: Error message */ +){ + int rc = SQLITE_OK; + int nCmd = (int)strlen(zCmd); + if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){ + const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES; + const char *p; + int bFirst = 1; + if( pConfig->aPrefix==0 ){ + pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte); + if( rc ) return rc; + } + + p = zArg; + while( 1 ){ + int nPre = 0; + + while( p[0]==' ' ) p++; + if( bFirst==0 && p[0]==',' ){ + p++; + while( p[0]==' ' ) p++; + }else if( p[0]=='\0' ){ + break; + } + if( p[0]<'0' || p[0]>'9' ){ + *pzErr = sqlite3_mprintf("malformed prefix=... directive"); + rc = SQLITE_ERROR; + break; + } + + if( pConfig->nPrefix==FTS5_MAX_PREFIX_INDEXES ){ + *pzErr = sqlite3_mprintf( + "too many prefix indexes (max %d)", FTS5_MAX_PREFIX_INDEXES + ); + rc = SQLITE_ERROR; + break; + } + + while( p[0]>='0' && p[0]<='9' && nPre<1000 ){ + nPre = nPre*10 + (p[0] - '0'); + p++; + } + + if( nPre<=0 || nPre>=1000 ){ + *pzErr = sqlite3_mprintf("prefix length out of range (max 999)"); + rc = SQLITE_ERROR; + break; + } + + pConfig->aPrefix[pConfig->nPrefix] = nPre; + pConfig->nPrefix++; + bFirst = 0; + } + assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES ); + return rc; + } + + if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ + const char *p = (const char*)zArg; + int nArg = (int)strlen(zArg) + 1; + char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg); + char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2); + char *pSpace = pDel; + + if( azArg && pSpace ){ + if( pConfig->pTok ){ + *pzErr = sqlite3_mprintf("multiple tokenize=... directives"); + rc = SQLITE_ERROR; + }else{ + for(nArg=0; p && *p; nArg++){ + const char *p2 = fts5ConfigSkipWhitespace(p); + if( *p2=='\'' ){ + p = fts5ConfigSkipLiteral(p2); + }else{ + p = fts5ConfigSkipBareword(p2); + } + if( p ){ + memcpy(pSpace, p2, p-p2); + azArg[nArg] = pSpace; + sqlite3Fts5Dequote(pSpace); + pSpace += (p - p2) + 1; + p = fts5ConfigSkipWhitespace(p); + } + } + if( p==0 ){ + *pzErr = sqlite3_mprintf("parse error in tokenize directive"); + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5GetTokenizer(pGlobal, + (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi, + pzErr + ); + } + } + } + + sqlite3_free(azArg); + sqlite3_free(pDel); + return rc; + } + + if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){ + if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ + *pzErr = sqlite3_mprintf("multiple content=... directives"); + rc = SQLITE_ERROR; + }else{ + if( zArg[0] ){ + pConfig->eContent = FTS5_CONTENT_EXTERNAL; + pConfig->zContent = sqlite3Fts5Mprintf(&rc, "%Q.%Q", pConfig->zDb,zArg); + }else{ + pConfig->eContent = FTS5_CONTENT_NONE; + } + } + return rc; + } + + if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){ + if( pConfig->zContentRowid ){ + *pzErr = sqlite3_mprintf("multiple content_rowid=... directives"); + rc = SQLITE_ERROR; + }else{ + pConfig->zContentRowid = sqlite3Fts5Strndup(&rc, zArg, -1); + } + return rc; + } + + if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){ + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ + *pzErr = sqlite3_mprintf("malformed columnsize=... directive"); + rc = SQLITE_ERROR; + }else{ + pConfig->bColumnsize = (zArg[0]=='1'); + } + return rc; + } + + if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ + const Fts5Enum aDetail[] = { + { "none", FTS5_DETAIL_NONE }, + { "full", FTS5_DETAIL_FULL }, + { "columns", FTS5_DETAIL_COLUMNS }, + { 0, 0 } + }; + + if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ + *pzErr = sqlite3_mprintf("malformed detail=... directive"); + } + return rc; + } + + *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); + return SQLITE_ERROR; +} + +/* +** Allocate an instance of the default tokenizer ("simple") at +** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error +** code if an error occurs. +*/ +static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ + assert( pConfig->pTok==0 && pConfig->pTokApi==0 ); + return sqlite3Fts5GetTokenizer( + pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0 + ); +} + +/* +** Gobble up the first bareword or quoted word from the input buffer zIn. +** Return a pointer to the character immediately following the last in +** the gobbled word if successful, or a NULL pointer otherwise (failed +** to find close-quote character). +** +** Before returning, set pzOut to point to a new buffer containing a +** nul-terminated, dequoted copy of the gobbled word. If the word was +** quoted, *pbQuoted is also set to 1 before returning. +** +** If *pRc is other than SQLITE_OK when this function is called, it is +** a no-op (NULL is returned). Otherwise, if an OOM occurs within this +** function, *pRc is set to SQLITE_NOMEM before returning. *pRc is *not* +** set if a parse error (failed to find close quote) occurs. +*/ +static const char *fts5ConfigGobbleWord( + int *pRc, /* IN/OUT: Error code */ + const char *zIn, /* Buffer to gobble string/bareword from */ + char **pzOut, /* OUT: malloc'd buffer containing str/bw */ + int *pbQuoted /* OUT: Set to true if dequoting required */ +){ + const char *zRet = 0; + + int nIn = (int)strlen(zIn); + char *zOut = sqlite3_malloc(nIn+1); + + assert( *pRc==SQLITE_OK ); + *pbQuoted = 0; + *pzOut = 0; + + if( zOut==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + memcpy(zOut, zIn, nIn+1); + if( fts5_isopenquote(zOut[0]) ){ + int ii = fts5Dequote(zOut); + zRet = &zIn[ii]; + *pbQuoted = 1; + }else{ + zRet = fts5ConfigSkipBareword(zIn); + if( zRet ){ + zOut[zRet-zIn] = '\0'; + } + } + } + + if( zRet==0 ){ + sqlite3_free(zOut); + }else{ + *pzOut = zOut; + } + + return zRet; +} + +static int fts5ConfigParseColumn( + Fts5Config *p, + char *zCol, + char *zArg, + char **pzErr +){ + int rc = SQLITE_OK; + if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) + || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME) + ){ + *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol); + rc = SQLITE_ERROR; + }else if( zArg ){ + if( 0==sqlite3_stricmp(zArg, "unindexed") ){ + p->abUnindexed[p->nCol] = 1; + }else{ + *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg); + rc = SQLITE_ERROR; + } + } + + p->azCol[p->nCol++] = zCol; + return rc; +} + +/* +** Populate the Fts5Config.zContentExprlist string. +*/ +static int fts5ConfigMakeExprlist(Fts5Config *p){ + int i; + int rc = SQLITE_OK; + Fts5Buffer buf = {0, 0, 0}; + + sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid); + if( p->eContent!=FTS5_CONTENT_NONE ){ + for(i=0; inCol; i++){ + if( p->eContent==FTS5_CONTENT_EXTERNAL ){ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]); + }else{ + sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i); + } + } + } + + assert( p->zContentExprlist==0 ); + p->zContentExprlist = (char*)buf.p; + return rc; +} + +/* +** Arguments nArg/azArg contain the string arguments passed to the xCreate +** or xConnect method of the virtual table. This function attempts to +** allocate an instance of Fts5Config containing the results of parsing +** those arguments. +** +** If successful, SQLITE_OK is returned and *ppOut is set to point to the +** new Fts5Config object. If an error occurs, an SQLite error code is +** returned, *ppOut is set to NULL and an error message may be left in +** *pzErr. It is the responsibility of the caller to eventually free any +** such error message using sqlite3_free(). +*/ +static int sqlite3Fts5ConfigParse( + Fts5Global *pGlobal, + sqlite3 *db, + int nArg, /* Number of arguments */ + const char **azArg, /* Array of nArg CREATE VIRTUAL TABLE args */ + Fts5Config **ppOut, /* OUT: Results of parse */ + char **pzErr /* OUT: Error message */ +){ + int rc = SQLITE_OK; /* Return code */ + Fts5Config *pRet; /* New object to return */ + int i; + int nByte; + + *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); + if( pRet==0 ) return SQLITE_NOMEM; + memset(pRet, 0, sizeof(Fts5Config)); + pRet->db = db; + pRet->iCookie = -1; + + nByte = nArg * (sizeof(char*) + sizeof(u8)); + pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); + pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; + pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); + pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); + pRet->bColumnsize = 1; + pRet->eDetail = FTS5_DETAIL_FULL; +#ifdef SQLITE_DEBUG + pRet->bPrefixIndex = 1; +#endif + if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){ + *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName); + rc = SQLITE_ERROR; + } + + for(i=3; rc==SQLITE_OK && ipTok==0 ){ + rc = fts5ConfigDefaultTokenizer(pGlobal, pRet); + } + + /* If no zContent option was specified, fill in the default values. */ + if( rc==SQLITE_OK && pRet->zContent==0 ){ + const char *zTail = 0; + assert( pRet->eContent==FTS5_CONTENT_NORMAL + || pRet->eContent==FTS5_CONTENT_NONE + ); + if( pRet->eContent==FTS5_CONTENT_NORMAL ){ + zTail = "content"; + }else if( pRet->bColumnsize ){ + zTail = "docsize"; + } + + if( zTail ){ + pRet->zContent = sqlite3Fts5Mprintf( + &rc, "%Q.'%q_%s'", pRet->zDb, pRet->zName, zTail + ); + } + } + + if( rc==SQLITE_OK && pRet->zContentRowid==0 ){ + pRet->zContentRowid = sqlite3Fts5Strndup(&rc, "rowid", -1); + } + + /* Formulate the zContentExprlist text */ + if( rc==SQLITE_OK ){ + rc = fts5ConfigMakeExprlist(pRet); + } + + if( rc!=SQLITE_OK ){ + sqlite3Fts5ConfigFree(pRet); + *ppOut = 0; + } + return rc; +} + +/* +** Free the configuration object passed as the only argument. +*/ +static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){ + if( pConfig ){ + int i; + if( pConfig->pTok ){ + pConfig->pTokApi->xDelete(pConfig->pTok); + } + sqlite3_free(pConfig->zDb); + sqlite3_free(pConfig->zName); + for(i=0; inCol; i++){ + sqlite3_free(pConfig->azCol[i]); + } + sqlite3_free(pConfig->azCol); + sqlite3_free(pConfig->aPrefix); + sqlite3_free(pConfig->zRank); + sqlite3_free(pConfig->zRankArgs); + sqlite3_free(pConfig->zContent); + sqlite3_free(pConfig->zContentRowid); + sqlite3_free(pConfig->zContentExprlist); + sqlite3_free(pConfig); + } +} + +/* +** Call sqlite3_declare_vtab() based on the contents of the configuration +** object passed as the only argument. Return SQLITE_OK if successful, or +** an SQLite error code if an error occurs. +*/ +static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ + int i; + int rc = SQLITE_OK; + char *zSql; + + zSql = sqlite3Fts5Mprintf(&rc, "CREATE TABLE x("); + for(i=0; zSql && inCol; i++){ + const char *zSep = (i==0?"":", "); + zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]); + } + zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", + zSql, pConfig->zName, FTS5_RANK_NAME + ); + + assert( zSql || rc==SQLITE_NOMEM ); + if( zSql ){ + rc = sqlite3_declare_vtab(pConfig->db, zSql); + sqlite3_free(zSql); + } + + return rc; +} + +/* +** Tokenize the text passed via the second and third arguments. +** +** The callback is invoked once for each token in the input text. The +** arguments passed to it are, in order: +** +** void *pCtx // Copy of 4th argument to sqlite3Fts5Tokenize() +** const char *pToken // Pointer to buffer containing token +** int nToken // Size of token in bytes +** int iStart // Byte offset of start of token within input text +** int iEnd // Byte offset of end of token within input text +** int iPos // Position of token in input (first token is 0) +** +** If the callback returns a non-zero value the tokenization is abandoned +** and no further callbacks are issued. +** +** This function returns SQLITE_OK if successful or an SQLite error code +** if an error occurs. If the tokenization was abandoned early because +** the callback returned SQLITE_DONE, this is not an error and this function +** still returns SQLITE_OK. Or, if the tokenization was abandoned early +** because the callback returned another non-zero value, it is assumed +** to be an SQLite error code and returned to the caller. +*/ +static int sqlite3Fts5Tokenize( + Fts5Config *pConfig, /* FTS5 Configuration object */ + int flags, /* FTS5_TOKENIZE_* flags */ + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ +){ + if( pText==0 ) return SQLITE_OK; + return pConfig->pTokApi->xTokenize( + pConfig->pTok, pCtx, flags, pText, nText, xToken + ); +} + +/* +** Argument pIn points to the first character in what is expected to be +** a comma-separated list of SQL literals followed by a ')' character. +** If it actually is this, return a pointer to the ')'. Otherwise, return +** NULL to indicate a parse error. +*/ +static const char *fts5ConfigSkipArgs(const char *pIn){ + const char *p = pIn; + + while( 1 ){ + p = fts5ConfigSkipWhitespace(p); + p = fts5ConfigSkipLiteral(p); + p = fts5ConfigSkipWhitespace(p); + if( p==0 || *p==')' ) break; + if( *p!=',' ){ + p = 0; + break; + } + p++; + } + + return p; +} + +/* +** Parameter zIn contains a rank() function specification. The format of +** this is: +** +** + Bareword (function name) +** + Open parenthesis - "(" +** + Zero or more SQL literals in a comma separated list +** + Close parenthesis - ")" +*/ +static int sqlite3Fts5ConfigParseRank( + const char *zIn, /* Input string */ + char **pzRank, /* OUT: Rank function name */ + char **pzRankArgs /* OUT: Rank function arguments */ +){ + const char *p = zIn; + const char *pRank; + char *zRank = 0; + char *zRankArgs = 0; + int rc = SQLITE_OK; + + *pzRank = 0; + *pzRankArgs = 0; + + if( p==0 ){ + rc = SQLITE_ERROR; + }else{ + p = fts5ConfigSkipWhitespace(p); + pRank = p; + p = fts5ConfigSkipBareword(p); + + if( p ){ + zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank); + if( zRank ) memcpy(zRank, pRank, p-pRank); + }else{ + rc = SQLITE_ERROR; + } + + if( rc==SQLITE_OK ){ + p = fts5ConfigSkipWhitespace(p); + if( *p!='(' ) rc = SQLITE_ERROR; + p++; + } + if( rc==SQLITE_OK ){ + const char *pArgs; + p = fts5ConfigSkipWhitespace(p); + pArgs = p; + if( *p!=')' ){ + p = fts5ConfigSkipArgs(p); + if( p==0 ){ + rc = SQLITE_ERROR; + }else{ + zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs); + if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs); + } + } + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(zRank); + assert( zRankArgs==0 ); + }else{ + *pzRank = zRank; + *pzRankArgs = zRankArgs; + } + return rc; +} + +static int sqlite3Fts5ConfigSetValue( + Fts5Config *pConfig, + const char *zKey, + sqlite3_value *pVal, + int *pbBadkey +){ + int rc = SQLITE_OK; + + if( 0==sqlite3_stricmp(zKey, "pgsz") ){ + int pgsz = 0; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + pgsz = sqlite3_value_int(pVal); + } + if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){ + *pbBadkey = 1; + }else{ + pConfig->pgsz = pgsz; + } + } + + else if( 0==sqlite3_stricmp(zKey, "hashsize") ){ + int nHashSize = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nHashSize = sqlite3_value_int(pVal); + } + if( nHashSize<=0 ){ + *pbBadkey = 1; + }else{ + pConfig->nHashSize = nHashSize; + } + } + + else if( 0==sqlite3_stricmp(zKey, "automerge") ){ + int nAutomerge = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nAutomerge = sqlite3_value_int(pVal); + } + if( nAutomerge<0 || nAutomerge>64 ){ + *pbBadkey = 1; + }else{ + if( nAutomerge==1 ) nAutomerge = FTS5_DEFAULT_AUTOMERGE; + pConfig->nAutomerge = nAutomerge; + } + } + + else if( 0==sqlite3_stricmp(zKey, "usermerge") ){ + int nUsermerge = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nUsermerge = sqlite3_value_int(pVal); + } + if( nUsermerge<2 || nUsermerge>16 ){ + *pbBadkey = 1; + }else{ + pConfig->nUsermerge = nUsermerge; + } + } + + else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){ + int nCrisisMerge = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nCrisisMerge = sqlite3_value_int(pVal); + } + if( nCrisisMerge<0 ){ + *pbBadkey = 1; + }else{ + if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; + pConfig->nCrisisMerge = nCrisisMerge; + } + } + + else if( 0==sqlite3_stricmp(zKey, "rank") ){ + const char *zIn = (const char*)sqlite3_value_text(pVal); + char *zRank; + char *zRankArgs; + rc = sqlite3Fts5ConfigParseRank(zIn, &zRank, &zRankArgs); + if( rc==SQLITE_OK ){ + sqlite3_free(pConfig->zRank); + sqlite3_free(pConfig->zRankArgs); + pConfig->zRank = zRank; + pConfig->zRankArgs = zRankArgs; + }else if( rc==SQLITE_ERROR ){ + rc = SQLITE_OK; + *pbBadkey = 1; + } + }else{ + *pbBadkey = 1; + } + return rc; +} + +/* +** Load the contents of the %_config table into memory. +*/ +static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ + const char *zSelect = "SELECT k, v FROM %Q.'%q_config'"; + char *zSql; + sqlite3_stmt *p = 0; + int rc = SQLITE_OK; + int iVersion = 0; + + /* Set default values */ + pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE; + pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE; + pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE; + pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; + pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE; + + zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName); + if( zSql ){ + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0); + sqlite3_free(zSql); + } + + assert( rc==SQLITE_OK || p==0 ); + if( rc==SQLITE_OK ){ + while( SQLITE_ROW==sqlite3_step(p) ){ + const char *zK = (const char*)sqlite3_column_text(p, 0); + sqlite3_value *pVal = sqlite3_column_value(p, 1); + if( 0==sqlite3_stricmp(zK, "version") ){ + iVersion = sqlite3_value_int(pVal); + }else{ + int bDummy = 0; + sqlite3Fts5ConfigSetValue(pConfig, zK, pVal, &bDummy); + } + } + rc = sqlite3_finalize(p); + } + + if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){ + rc = SQLITE_ERROR; + if( pConfig->pzErrmsg ){ + assert( 0==*pConfig->pzErrmsg ); + *pConfig->pzErrmsg = sqlite3_mprintf( + "invalid fts5 file format (found %d, expected %d) - run 'rebuild'", + iVersion, FTS5_CURRENT_VERSION + ); + } + } + + if( rc==SQLITE_OK ){ + pConfig->iCookie = iCookie; + } + return rc; +} + +#line 1 "fts5_expr.c" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ + + + +/* #include "fts5Int.h" */ +/* #include "fts5parse.h" */ + +/* +** All token types in the generated fts5parse.h file are greater than 0. +*/ +#define FTS5_EOF 0 + +#define FTS5_LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) + +typedef struct Fts5ExprTerm Fts5ExprTerm; + +/* +** Functions generated by lemon from fts5parse.y. +*/ +static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)); +static void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*)); +static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); +#ifndef NDEBUG +#include +static void sqlite3Fts5ParserTrace(FILE*, char*); +#endif + + +struct Fts5Expr { + Fts5Index *pIndex; + Fts5Config *pConfig; + Fts5ExprNode *pRoot; + int bDesc; /* Iterate in descending rowid order */ + int nPhrase; /* Number of phrases in expression */ + Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ +}; + +/* +** eType: +** Expression node type. Always one of: +** +** FTS5_AND (nChild, apChild valid) +** FTS5_OR (nChild, apChild valid) +** FTS5_NOT (nChild, apChild valid) +** FTS5_STRING (pNear valid) +** FTS5_TERM (pNear valid) +*/ +struct Fts5ExprNode { + int eType; /* Node type */ + int bEof; /* True at EOF */ + int bNomatch; /* True if entry is not a match */ + + /* Next method for this node. */ + int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64); + + i64 iRowid; /* Current rowid */ + Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ + + /* Child nodes. For a NOT node, this array always contains 2 entries. For + ** AND or OR nodes, it contains 2 or more entries. */ + int nChild; /* Number of child nodes */ + Fts5ExprNode *apChild[1]; /* Array of child nodes */ +}; + +#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) + +/* +** Invoke the xNext method of an Fts5ExprNode object. This macro should be +** used as if it has the same signature as the xNext() methods themselves. +*/ +#define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d)) + +/* +** An instance of the following structure represents a single search term +** or term prefix. +*/ +struct Fts5ExprTerm { + int bPrefix; /* True for a prefix term */ + char *zTerm; /* nul-terminated term */ + Fts5IndexIter *pIter; /* Iterator for this term */ + Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ +}; + +/* +** A phrase. One or more terms that must appear in a contiguous sequence +** within a document for it to match. +*/ +struct Fts5ExprPhrase { + Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ + Fts5Buffer poslist; /* Current position list */ + int nTerm; /* Number of entries in aTerm[] */ + Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ +}; + +/* +** One or more phrases that must appear within a certain token distance of +** each other within each matching document. +*/ +struct Fts5ExprNearset { + int nNear; /* NEAR parameter */ + Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */ + int nPhrase; /* Number of entries in aPhrase[] array */ + Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */ +}; + + +/* +** Parse context. +*/ +struct Fts5Parse { + Fts5Config *pConfig; + char *zErr; + int rc; + int nPhrase; /* Size of apPhrase array */ + Fts5ExprPhrase **apPhrase; /* Array of all phrases */ + Fts5ExprNode *pExpr; /* Result of a successful parse */ +}; + +static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ + va_list ap; + va_start(ap, zFmt); + if( pParse->rc==SQLITE_OK ){ + pParse->zErr = sqlite3_vmprintf(zFmt, ap); + pParse->rc = SQLITE_ERROR; + } + va_end(ap); +} + +static int fts5ExprIsspace(char t){ + return t==' ' || t=='\t' || t=='\n' || t=='\r'; +} + +/* +** Read the first token from the nul-terminated string at *pz. +*/ +static int fts5ExprGetToken( + Fts5Parse *pParse, + const char **pz, /* IN/OUT: Pointer into buffer */ + Fts5Token *pToken +){ + const char *z = *pz; + int tok; + + /* Skip past any whitespace */ + while( fts5ExprIsspace(*z) ) z++; + + pToken->p = z; + pToken->n = 1; + switch( *z ){ + case '(': tok = FTS5_LP; break; + case ')': tok = FTS5_RP; break; + case '{': tok = FTS5_LCP; break; + case '}': tok = FTS5_RCP; break; + case ':': tok = FTS5_COLON; break; + case ',': tok = FTS5_COMMA; break; + case '+': tok = FTS5_PLUS; break; + case '*': tok = FTS5_STAR; break; + case '-': tok = FTS5_MINUS; break; + case '\0': tok = FTS5_EOF; break; + + case '"': { + const char *z2; + tok = FTS5_STRING; + + for(z2=&z[1]; 1; z2++){ + if( z2[0]=='"' ){ + z2++; + if( z2[0]!='"' ) break; + } + if( z2[0]=='\0' ){ + sqlite3Fts5ParseError(pParse, "unterminated string"); + return FTS5_EOF; + } + } + pToken->n = (z2 - z); + break; + } + + default: { + const char *z2; + if( sqlite3Fts5IsBareword(z[0])==0 ){ + sqlite3Fts5ParseError(pParse, "fts5: syntax error near \"%.1s\"", z); + return FTS5_EOF; + } + tok = FTS5_STRING; + for(z2=&z[1]; sqlite3Fts5IsBareword(*z2); z2++); + pToken->n = (z2 - z); + if( pToken->n==2 && memcmp(pToken->p, "OR", 2)==0 ) tok = FTS5_OR; + if( pToken->n==3 && memcmp(pToken->p, "NOT", 3)==0 ) tok = FTS5_NOT; + if( pToken->n==3 && memcmp(pToken->p, "AND", 3)==0 ) tok = FTS5_AND; + break; + } + } + + *pz = &pToken->p[pToken->n]; + return tok; +} + +static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); } +static void fts5ParseFree(void *p){ sqlite3_free(p); } + +static int sqlite3Fts5ExprNew( + Fts5Config *pConfig, /* FTS5 Configuration */ + const char *zExpr, /* Expression text */ + Fts5Expr **ppNew, + char **pzErr +){ + Fts5Parse sParse; + Fts5Token token; + const char *z = zExpr; + int t; /* Next token type */ + void *pEngine; + Fts5Expr *pNew; + + *ppNew = 0; + *pzErr = 0; + memset(&sParse, 0, sizeof(sParse)); + pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc); + if( pEngine==0 ){ return SQLITE_NOMEM; } + sParse.pConfig = pConfig; + + do { + t = fts5ExprGetToken(&sParse, &z, &token); + sqlite3Fts5Parser(pEngine, t, token, &sParse); + }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); + sqlite3Fts5ParserFree(pEngine, fts5ParseFree); + + assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); + if( sParse.rc==SQLITE_OK ){ + *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); + if( pNew==0 ){ + sParse.rc = SQLITE_NOMEM; + sqlite3Fts5ParseNodeFree(sParse.pExpr); + }else{ + if( !sParse.pExpr ){ + const int nByte = sizeof(Fts5ExprNode); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); + if( pNew->pRoot ){ + pNew->pRoot->bEof = 1; + } + }else{ + pNew->pRoot = sParse.pExpr; + } + pNew->pIndex = 0; + pNew->pConfig = pConfig; + pNew->apExprPhrase = sParse.apPhrase; + pNew->nPhrase = sParse.nPhrase; + sParse.apPhrase = 0; + } + }else{ + sqlite3Fts5ParseNodeFree(sParse.pExpr); + } + + sqlite3_free(sParse.apPhrase); + *pzErr = sParse.zErr; + return sParse.rc; +} + +/* +** Free the expression node object passed as the only argument. +*/ +static void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){ + if( p ){ + int i; + for(i=0; inChild; i++){ + sqlite3Fts5ParseNodeFree(p->apChild[i]); + } + sqlite3Fts5ParseNearsetFree(p->pNear); + sqlite3_free(p); + } +} + +/* +** Free the expression object passed as the only argument. +*/ +static void sqlite3Fts5ExprFree(Fts5Expr *p){ + if( p ){ + sqlite3Fts5ParseNodeFree(p->pRoot); + sqlite3_free(p->apExprPhrase); + sqlite3_free(p); + } +} + +/* +** Argument pTerm must be a synonym iterator. Return the current rowid +** that it points to. +*/ +static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ + i64 iRet = 0; + int bRetValid = 0; + Fts5ExprTerm *p; + + assert( pTerm->pSynonym ); + assert( bDesc==0 || bDesc==1 ); + for(p=pTerm; p; p=p->pSynonym){ + if( 0==sqlite3Fts5IterEof(p->pIter) ){ + i64 iRowid = p->pIter->iRowid; + if( bRetValid==0 || (bDesc!=(iRowidpSynonym ); + for(p=pTerm; p; p=p->pSynonym){ + Fts5IndexIter *pIter = p->pIter; + if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ + if( pIter->nData==0 ) continue; + if( nIter==nAlloc ){ + int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; + Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); + if( aNew==0 ){ + rc = SQLITE_NOMEM; + goto synonym_poslist_out; + } + memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter); + nAlloc = nAlloc*2; + if( aIter!=aStatic ) sqlite3_free(aIter); + aIter = aNew; + } + sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]); + assert( aIter[nIter].bEof==0 ); + nIter++; + } + } + + if( nIter==1 ){ + *pa = (u8*)aIter[0].a; + *pn = aIter[0].n; + }else{ + Fts5PoslistWriter writer = {0}; + i64 iPrev = -1; + fts5BufferZero(pBuf); + while( 1 ){ + int i; + i64 iMin = FTS5_LARGEST_INT64; + for(i=0; ip; + *pn = pBuf->n; + } + } + + synonym_poslist_out: + if( aIter!=aStatic ) sqlite3_free(aIter); + return rc; +} + + +/* +** All individual term iterators in pPhrase are guaranteed to be valid and +** pointing to the same rowid when this function is called. This function +** checks if the current rowid really is a match, and if so populates +** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch +** is set to true if this is really a match, or false otherwise. +** +** SQLITE_OK is returned if an error occurs, or an SQLite error code +** otherwise. It is not considered an error code if the current rowid is +** not a match. +*/ +static int fts5ExprPhraseIsMatch( + Fts5ExprNode *pNode, /* Node pPhrase belongs to */ + Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ + int *pbMatch /* OUT: Set to true if really a match */ +){ + Fts5PoslistWriter writer = {0}; + Fts5PoslistReader aStatic[4]; + Fts5PoslistReader *aIter = aStatic; + int i; + int rc = SQLITE_OK; + + fts5BufferZero(&pPhrase->poslist); + + /* If the aStatic[] array is not large enough, allocate a large array + ** using sqlite3_malloc(). This approach could be improved upon. */ + if( pPhrase->nTerm>ArraySize(aStatic) ){ + int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; + aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); + if( !aIter ) return SQLITE_NOMEM; + } + memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); + + /* Initialize a term iterator for each term in the phrase */ + for(i=0; inTerm; i++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; + int n = 0; + int bFlag = 0; + u8 *a = 0; + if( pTerm->pSynonym ){ + Fts5Buffer buf = {0, 0, 0}; + rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n); + if( rc ){ + sqlite3_free(a); + goto ismatch_out; + } + if( a==buf.p ) bFlag = 1; + }else{ + a = (u8*)pTerm->pIter->pData; + n = pTerm->pIter->nData; + } + sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); + aIter[i].bFlag = (u8)bFlag; + if( aIter[i].bEof ) goto ismatch_out; + } + + while( 1 ){ + int bMatch; + i64 iPos = aIter[0].iPos; + do { + bMatch = 1; + for(i=0; inTerm; i++){ + Fts5PoslistReader *pPos = &aIter[i]; + i64 iAdj = iPos + i; + if( pPos->iPos!=iAdj ){ + bMatch = 0; + while( pPos->iPosiPos>iAdj ) iPos = pPos->iPos-i; + } + } + }while( bMatch==0 ); + + /* Append position iPos to the output */ + rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos); + if( rc!=SQLITE_OK ) goto ismatch_out; + + for(i=0; inTerm; i++){ + if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out; + } + } + + ismatch_out: + *pbMatch = (pPhrase->poslist.n>0); + for(i=0; inTerm; i++){ + if( aIter[i].bFlag ) sqlite3_free((u8*)aIter[i].a); + } + if( aIter!=aStatic ) sqlite3_free(aIter); + return rc; +} + +typedef struct Fts5LookaheadReader Fts5LookaheadReader; +struct Fts5LookaheadReader { + const u8 *a; /* Buffer containing position list */ + int n; /* Size of buffer a[] in bytes */ + int i; /* Current offset in position list */ + i64 iPos; /* Current position */ + i64 iLookahead; /* Next position */ +}; + +#define FTS5_LOOKAHEAD_EOF (((i64)1) << 62) + +static int fts5LookaheadReaderNext(Fts5LookaheadReader *p){ + p->iPos = p->iLookahead; + if( sqlite3Fts5PoslistNext64(p->a, p->n, &p->i, &p->iLookahead) ){ + p->iLookahead = FTS5_LOOKAHEAD_EOF; + } + return (p->iPos==FTS5_LOOKAHEAD_EOF); +} + +static int fts5LookaheadReaderInit( + const u8 *a, int n, /* Buffer to read position list from */ + Fts5LookaheadReader *p /* Iterator object to initialize */ +){ + memset(p, 0, sizeof(Fts5LookaheadReader)); + p->a = a; + p->n = n; + fts5LookaheadReaderNext(p); + return fts5LookaheadReaderNext(p); +} + +typedef struct Fts5NearTrimmer Fts5NearTrimmer; +struct Fts5NearTrimmer { + Fts5LookaheadReader reader; /* Input iterator */ + Fts5PoslistWriter writer; /* Writer context */ + Fts5Buffer *pOut; /* Output poslist */ +}; + +/* +** The near-set object passed as the first argument contains more than +** one phrase. All phrases currently point to the same row. The +** Fts5ExprPhrase.poslist buffers are populated accordingly. This function +** tests if the current row contains instances of each phrase sufficiently +** close together to meet the NEAR constraint. Non-zero is returned if it +** does, or zero otherwise. +** +** If in/out parameter (*pRc) is set to other than SQLITE_OK when this +** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM) +** occurs within this function (*pRc) is set accordingly before returning. +** The return value is undefined in both these cases. +** +** If no error occurs and non-zero (a match) is returned, the position-list +** of each phrase object is edited to contain only those entries that +** meet the constraint before returning. +*/ +static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ + Fts5NearTrimmer aStatic[4]; + Fts5NearTrimmer *a = aStatic; + Fts5ExprPhrase **apPhrase = pNear->apPhrase; + + int i; + int rc = *pRc; + int bMatch; + + assert( pNear->nPhrase>1 ); + + /* If the aStatic[] array is not large enough, allocate a large array + ** using sqlite3_malloc(). This approach could be improved upon. */ + if( pNear->nPhrase>ArraySize(aStatic) ){ + int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; + a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); + }else{ + memset(aStatic, 0, sizeof(aStatic)); + } + if( rc!=SQLITE_OK ){ + *pRc = rc; + return 0; + } + + /* Initialize a lookahead iterator for each phrase. After passing the + ** buffer and buffer size to the lookaside-reader init function, zero + ** the phrase poslist buffer. The new poslist for the phrase (containing + ** the same entries as the original with some entries removed on account + ** of the NEAR constraint) is written over the original even as it is + ** being read. This is safe as the entries for the new poslist are a + ** subset of the old, so it is not possible for data yet to be read to + ** be overwritten. */ + for(i=0; inPhrase; i++){ + Fts5Buffer *pPoslist = &apPhrase[i]->poslist; + fts5LookaheadReaderInit(pPoslist->p, pPoslist->n, &a[i].reader); + pPoslist->n = 0; + a[i].pOut = pPoslist; + } + + while( 1 ){ + int iAdv; + i64 iMin; + i64 iMax; + + /* This block advances the phrase iterators until they point to a set of + ** entries that together comprise a match. */ + iMax = a[0].reader.iPos; + do { + bMatch = 1; + for(i=0; inPhrase; i++){ + Fts5LookaheadReader *pPos = &a[i].reader; + iMin = iMax - pNear->apPhrase[i]->nTerm - pNear->nNear; + if( pPos->iPosiPos>iMax ){ + bMatch = 0; + while( pPos->iPosiPos>iMax ) iMax = pPos->iPos; + } + } + }while( bMatch==0 ); + + /* Add an entry to each output position list */ + for(i=0; inPhrase; i++){ + i64 iPos = a[i].reader.iPos; + Fts5PoslistWriter *pWriter = &a[i].writer; + if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){ + sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos); + } + } + + iAdv = 0; + iMin = a[0].reader.iLookahead; + for(i=0; inPhrase; i++){ + if( a[i].reader.iLookahead < iMin ){ + iMin = a[i].reader.iLookahead; + iAdv = i; + } + } + if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out; + } + + ismatch_out: { + int bRet = a[0].pOut->n>0; + *pRc = rc; + if( a!=aStatic ) sqlite3_free(a); + return bRet; + } +} + +/* +** Advance iterator pIter until it points to a value equal to or laster +** than the initial value of *piLast. If this means the iterator points +** to a value laster than *piLast, update *piLast to the new lastest value. +** +** If the iterator reaches EOF, set *pbEof to true before returning. If +** an error occurs, set *pRc to an error code. If either *pbEof or *pRc +** are set, return a non-zero value. Otherwise, return zero. +*/ +static int fts5ExprAdvanceto( + Fts5IndexIter *pIter, /* Iterator to advance */ + int bDesc, /* True if iterator is "rowid DESC" */ + i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ + int *pRc, /* OUT: Error code */ + int *pbEof /* OUT: Set to true if EOF */ +){ + i64 iLast = *piLast; + i64 iRowid; + + iRowid = pIter->iRowid; + if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastiRowid; + assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) ); + } + *piLast = iRowid; + + return 0; +} + +static int fts5ExprSynonymAdvanceto( + Fts5ExprTerm *pTerm, /* Term iterator to advance */ + int bDesc, /* True if iterator is "rowid DESC" */ + i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ + int *pRc /* OUT: Error code */ +){ + int rc = SQLITE_OK; + i64 iLast = *piLast; + Fts5ExprTerm *p; + int bEof = 0; + + for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){ + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + i64 iRowid = p->pIter->iRowid; + if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastpIter, iLast); + } + } + } + + if( rc!=SQLITE_OK ){ + *pRc = rc; + bEof = 1; + }else{ + *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof); + } + return bEof; +} + + +static int fts5ExprNearTest( + int *pRc, + Fts5Expr *pExpr, /* Expression that pNear is a part of */ + Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ +){ + Fts5ExprNearset *pNear = pNode->pNear; + int rc = *pRc; + + if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5ExprTerm *pTerm; + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + pPhrase->poslist.n = 0; + for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + Fts5IndexIter *pIter = pTerm->pIter; + if( sqlite3Fts5IterEof(pIter)==0 ){ + if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){ + pPhrase->poslist.n = 1; + } + } + } + return pPhrase->poslist.n; + }else{ + int i; + + /* Check that each phrase in the nearset matches the current row. + ** Populate the pPhrase->poslist buffers at the same time. If any + ** phrase is not a match, break out of the loop early. */ + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ + int bMatch = 0; + rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch); + if( bMatch==0 ) break; + }else{ + Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; + fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData); + } + } + + *pRc = rc; + if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ + return 1; + } + return 0; + } +} + + +/* +** Initialize all term iterators in the pNear object. If any term is found +** to match no documents at all, return immediately without initializing any +** further iterators. +*/ +static int fts5ExprNearInitAll( + Fts5Expr *pExpr, + Fts5ExprNode *pNode +){ + Fts5ExprNearset *pNear = pNode->pNear; + int i, j; + int rc = SQLITE_OK; + int bEof = 1; + + assert( pNode->bNomatch==0 ); + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + for(j=0; jnTerm; j++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; + Fts5ExprTerm *p; + + for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){ + if( p->pIter ){ + sqlite3Fts5IterClose(p->pIter); + p->pIter = 0; + } + rc = sqlite3Fts5IndexQuery( + pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), + (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | + (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), + pNear->pColset, + &p->pIter + ); + assert( rc==SQLITE_OK || p->pIter==0 ); + if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){ + bEof = 0; + } + } + + if( bEof ) break; + } + if( bEof ) break; + } + + pNode->bEof = bEof; + return rc; +} + +/* +** If pExpr is an ASC iterator, this function returns a value with the +** same sign as: +** +** (iLhs - iRhs) +** +** Otherwise, if this is a DESC iterator, the opposite is returned: +** +** (iRhs - iLhs) +*/ +static int fts5RowidCmp( + Fts5Expr *pExpr, + i64 iLhs, + i64 iRhs +){ + assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); + if( pExpr->bDesc==0 ){ + if( iLhs iRhs); + }else{ + if( iLhs>iRhs ) return -1; + return (iLhs < iRhs); + } +} + +static void fts5ExprSetEof(Fts5ExprNode *pNode){ + int i; + pNode->bEof = 1; + pNode->bNomatch = 0; + for(i=0; inChild; i++){ + fts5ExprSetEof(pNode->apChild[i]); + } +} + +static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ + if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pNode->pNear; + int i; + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + pPhrase->poslist.n = 0; + } + }else{ + int i; + for(i=0; inChild; i++){ + fts5ExprNodeZeroPoslist(pNode->apChild[i]); + } + } +} + + + +/* +** Compare the values currently indicated by the two nodes as follows: +** +** res = (*p1) - (*p2) +** +** Nodes that point to values that come later in the iteration order are +** considered to be larger. Nodes at EOF are the largest of all. +** +** This means that if the iteration order is ASC, then numerically larger +** rowids are considered larger. Or if it is the default DESC, numerically +** smaller rowids are larger. +*/ +static int fts5NodeCompare( + Fts5Expr *pExpr, + Fts5ExprNode *p1, + Fts5ExprNode *p2 +){ + if( p2->bEof ) return -1; + if( p1->bEof ) return +1; + return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid); +} + +/* +** All individual term iterators in pNear are guaranteed to be valid when +** this function is called. This function checks if all term iterators +** point to the same rowid, and if not, advances them until they do. +** If an EOF is reached before this happens, *pbEof is set to true before +** returning. +** +** SQLITE_OK is returned if an error occurs, or an SQLite error code +** otherwise. It is not considered an error code if an iterator reaches +** EOF. +*/ +static int fts5ExprNodeTest_STRING( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode +){ + Fts5ExprNearset *pNear = pNode->pNear; + Fts5ExprPhrase *pLeft = pNear->apPhrase[0]; + int rc = SQLITE_OK; + i64 iLast; /* Lastest rowid any iterator points to */ + int i, j; /* Phrase and token index, respectively */ + int bMatch; /* True if all terms are at the same rowid */ + const int bDesc = pExpr->bDesc; + + /* Check that this node should not be FTS5_TERM */ + assert( pNear->nPhrase>1 + || pNear->apPhrase[0]->nTerm>1 + || pNear->apPhrase[0]->aTerm[0].pSynonym + ); + + /* Initialize iLast, the "lastest" rowid any iterator points to. If the + ** iterator skips through rowids in the default ascending order, this means + ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it + ** means the minimum rowid. */ + if( pLeft->aTerm[0].pSynonym ){ + iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0); + }else{ + iLast = pLeft->aTerm[0].pIter->iRowid; + } + + do { + bMatch = 1; + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + for(j=0; jnTerm; j++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; + if( pTerm->pSynonym ){ + i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0); + if( iRowid==iLast ) continue; + bMatch = 0; + if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){ + pNode->bNomatch = 0; + pNode->bEof = 1; + return rc; + } + }else{ + Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; + if( pIter->iRowid==iLast || pIter->bEof ) continue; + bMatch = 0; + if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ + return rc; + } + } + } + } + }while( bMatch==0 ); + + pNode->iRowid = iLast; + pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK); + assert( pNode->bEof==0 || pNode->bNomatch==0 ); + + return rc; +} + +/* +** Advance the first term iterator in the first phrase of pNear. Set output +** variable *pbEof to true if it reaches EOF or if an error occurs. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5ExprNodeNext_STRING( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */ + int bFromValid, + i64 iFrom +){ + Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0]; + int rc = SQLITE_OK; + + pNode->bNomatch = 0; + if( pTerm->pSynonym ){ + int bEof = 1; + Fts5ExprTerm *p; + + /* Find the firstest rowid any synonym points to. */ + i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0); + + /* Advance each iterator that currently points to iRowid. Or, if iFrom + ** is valid - each iterator that points to a rowid before iFrom. */ + for(p=pTerm; p; p=p->pSynonym){ + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + i64 ii = p->pIter->iRowid; + if( ii==iRowid + || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) + ){ + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom); + }else{ + rc = sqlite3Fts5IterNext(p->pIter); + } + if( rc!=SQLITE_OK ) break; + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + bEof = 0; + } + }else{ + bEof = 0; + } + } + } + + /* Set the EOF flag if either all synonym iterators are at EOF or an + ** error has occurred. */ + pNode->bEof = (rc || bEof); + }else{ + Fts5IndexIter *pIter = pTerm->pIter; + + assert( Fts5NodeIsString(pNode) ); + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(pIter, iFrom); + }else{ + rc = sqlite3Fts5IterNext(pIter); + } + + pNode->bEof = (rc || sqlite3Fts5IterEof(pIter)); + } + + if( pNode->bEof==0 ){ + assert( rc==SQLITE_OK ); + rc = fts5ExprNodeTest_STRING(pExpr, pNode); + } + + return rc; +} + + +static int fts5ExprNodeTest_TERM( + Fts5Expr *pExpr, /* Expression that pNear is a part of */ + Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ +){ + /* As this "NEAR" object is actually a single phrase that consists + ** of a single term only, grab pointers into the poslist managed by the + ** fts5_index.c iterator object. This is much faster than synthesizing + ** a new poslist the way we have to for more complicated phrase or NEAR + ** expressions. */ + Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0]; + Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; + + assert( pNode->eType==FTS5_TERM ); + assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 ); + assert( pPhrase->aTerm[0].pSynonym==0 ); + + pPhrase->poslist.n = pIter->nData; + if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){ + pPhrase->poslist.p = (u8*)pIter->pData; + } + pNode->iRowid = pIter->iRowid; + pNode->bNomatch = (pPhrase->poslist.n==0); + return SQLITE_OK; +} + +/* +** xNext() method for a node of type FTS5_TERM. +*/ +static int fts5ExprNodeNext_TERM( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc; + Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter; + + assert( pNode->bEof==0 ); + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(pIter, iFrom); + }else{ + rc = sqlite3Fts5IterNext(pIter); + } + if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){ + rc = fts5ExprNodeTest_TERM(pExpr, pNode); + }else{ + pNode->bEof = 1; + pNode->bNomatch = 0; + } + return rc; +} + +static void fts5ExprNodeTest_OR( + Fts5Expr *pExpr, /* Expression of which pNode is a part */ + Fts5ExprNode *pNode /* Expression node to test */ +){ + Fts5ExprNode *pNext = pNode->apChild[0]; + int i; + + for(i=1; inChild; i++){ + Fts5ExprNode *pChild = pNode->apChild[i]; + int cmp = fts5NodeCompare(pExpr, pNext, pChild); + if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){ + pNext = pChild; + } + } + pNode->iRowid = pNext->iRowid; + pNode->bEof = pNext->bEof; + pNode->bNomatch = pNext->bNomatch; +} + +static int fts5ExprNodeNext_OR( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int i; + i64 iLast = pNode->iRowid; + + for(i=0; inChild; i++){ + Fts5ExprNode *p1 = pNode->apChild[i]; + assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); + if( p1->bEof==0 ){ + if( (p1->iRowid==iLast) + || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) + ){ + int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); + if( rc!=SQLITE_OK ) return rc; + } + } + } + + fts5ExprNodeTest_OR(pExpr, pNode); + return SQLITE_OK; +} + +/* +** Argument pNode is an FTS5_AND node. +*/ +static int fts5ExprNodeTest_AND( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pAnd /* FTS5_AND node to advance */ +){ + int iChild; + i64 iLast = pAnd->iRowid; + int rc = SQLITE_OK; + int bMatch; + + assert( pAnd->bEof==0 ); + do { + pAnd->bNomatch = 0; + bMatch = 1; + for(iChild=0; iChildnChild; iChild++){ + Fts5ExprNode *pChild = pAnd->apChild[iChild]; + int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid); + if( cmp>0 ){ + /* Advance pChild until it points to iLast or laster */ + rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); + if( rc!=SQLITE_OK ) return rc; + } + + /* If the child node is now at EOF, so is the parent AND node. Otherwise, + ** the child node is guaranteed to have advanced at least as far as + ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the + ** new lastest rowid seen so far. */ + assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 ); + if( pChild->bEof ){ + fts5ExprSetEof(pAnd); + bMatch = 1; + break; + }else if( iLast!=pChild->iRowid ){ + bMatch = 0; + iLast = pChild->iRowid; + } + + if( pChild->bNomatch ){ + pAnd->bNomatch = 1; + } + } + }while( bMatch==0 ); + + if( pAnd->bNomatch && pAnd!=pExpr->pRoot ){ + fts5ExprNodeZeroPoslist(pAnd); + } + pAnd->iRowid = iLast; + return SQLITE_OK; +} + +static int fts5ExprNodeNext_AND( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest_AND(pExpr, pNode); + } + return rc; +} + +static int fts5ExprNodeTest_NOT( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode /* FTS5_NOT node to advance */ +){ + int rc = SQLITE_OK; + Fts5ExprNode *p1 = pNode->apChild[0]; + Fts5ExprNode *p2 = pNode->apChild[1]; + assert( pNode->nChild==2 ); + + while( rc==SQLITE_OK && p1->bEof==0 ){ + int cmp = fts5NodeCompare(pExpr, p1, p2); + if( cmp>0 ){ + rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid); + cmp = fts5NodeCompare(pExpr, p1, p2); + } + assert( rc!=SQLITE_OK || cmp<=0 ); + if( cmp || p2->bNomatch ) break; + rc = fts5ExprNodeNext(pExpr, p1, 0, 0); + } + pNode->bEof = p1->bEof; + pNode->bNomatch = p1->bNomatch; + pNode->iRowid = p1->iRowid; + if( p1->bEof ){ + fts5ExprNodeZeroPoslist(p2); + } + return rc; +} + +static int fts5ExprNodeNext_NOT( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest_NOT(pExpr, pNode); + } + return rc; +} + +/* +** If pNode currently points to a match, this function returns SQLITE_OK +** without modifying it. Otherwise, pNode is advanced until it does point +** to a match or EOF is reached. +*/ +static int fts5ExprNodeTest( + Fts5Expr *pExpr, /* Expression of which pNode is a part */ + Fts5ExprNode *pNode /* Expression node to test */ +){ + int rc = SQLITE_OK; + if( pNode->bEof==0 ){ + switch( pNode->eType ){ + + case FTS5_STRING: { + rc = fts5ExprNodeTest_STRING(pExpr, pNode); + break; + } + + case FTS5_TERM: { + rc = fts5ExprNodeTest_TERM(pExpr, pNode); + break; + } + + case FTS5_AND: { + rc = fts5ExprNodeTest_AND(pExpr, pNode); + break; + } + + case FTS5_OR: { + fts5ExprNodeTest_OR(pExpr, pNode); + break; + } + + default: assert( pNode->eType==FTS5_NOT ); { + rc = fts5ExprNodeTest_NOT(pExpr, pNode); + break; + } + } + } + return rc; +} + + +/* +** Set node pNode, which is part of expression pExpr, to point to the first +** match. If there are no matches, set the Node.bEof flag to indicate EOF. +** +** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. +** It is not an error if there are no matches. +*/ +static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ + int rc = SQLITE_OK; + pNode->bEof = 0; + pNode->bNomatch = 0; + + if( Fts5NodeIsString(pNode) ){ + /* Initialize all term iterators in the NEAR object. */ + rc = fts5ExprNearInitAll(pExpr, pNode); + }else if( pNode->xNext==0 ){ + pNode->bEof = 1; + }else{ + int i; + int nEof = 0; + for(i=0; inChild && rc==SQLITE_OK; i++){ + Fts5ExprNode *pChild = pNode->apChild[i]; + rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]); + assert( pChild->bEof==0 || pChild->bEof==1 ); + nEof += pChild->bEof; + } + pNode->iRowid = pNode->apChild[0]->iRowid; + + switch( pNode->eType ){ + case FTS5_AND: + if( nEof>0 ) fts5ExprSetEof(pNode); + break; + + case FTS5_OR: + if( pNode->nChild==nEof ) fts5ExprSetEof(pNode); + break; + + default: + assert( pNode->eType==FTS5_NOT ); + pNode->bEof = pNode->apChild[0]->bEof; + break; + } + } + + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest(pExpr, pNode); + } + return rc; +} + + +/* +** Begin iterating through the set of documents in index pIdx matched by +** the MATCH expression passed as the first argument. If the "bDesc" +** parameter is passed a non-zero value, iteration is in descending rowid +** order. Or, if it is zero, in ascending order. +** +** If iterating in ascending rowid order (bDesc==0), the first document +** visited is that with the smallest rowid that is larger than or equal +** to parameter iFirst. Or, if iterating in ascending order (bDesc==1), +** then the first document visited must have a rowid smaller than or +** equal to iFirst. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. It +** is not considered an error if the query does not match any documents. +*/ +static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){ + Fts5ExprNode *pRoot = p->pRoot; + int rc; /* Return code */ + + p->pIndex = pIdx; + p->bDesc = bDesc; + rc = fts5ExprNodeFirst(p, pRoot); + + /* If not at EOF but the current rowid occurs earlier than iFirst in + ** the iteration order, move to document iFirst or later. */ + if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ + rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); + } + + /* If the iterator is not at a real match, skip forward until it is. */ + while( pRoot->bNomatch ){ + assert( pRoot->bEof==0 && rc==SQLITE_OK ); + rc = fts5ExprNodeNext(p, pRoot, 0, 0); + } + return rc; +} + +/* +** Move to the next document +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. It +** is not considered an error if the query does not match any documents. +*/ +static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){ + int rc; + Fts5ExprNode *pRoot = p->pRoot; + assert( pRoot->bEof==0 && pRoot->bNomatch==0 ); + do { + rc = fts5ExprNodeNext(p, pRoot, 0, 0); + assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) ); + }while( pRoot->bNomatch ); + if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){ + pRoot->bEof = 1; + } + return rc; +} + +static int sqlite3Fts5ExprEof(Fts5Expr *p){ + return p->pRoot->bEof; +} + +static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){ + return p->pRoot->iRowid; +} + +static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){ + int rc = SQLITE_OK; + *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n); + return rc; +} + +/* +** Free the phrase object passed as the only argument. +*/ +static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ + if( pPhrase ){ + int i; + for(i=0; inTerm; i++){ + Fts5ExprTerm *pSyn; + Fts5ExprTerm *pNext; + Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; + sqlite3_free(pTerm->zTerm); + sqlite3Fts5IterClose(pTerm->pIter); + for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ + pNext = pSyn->pSynonym; + sqlite3Fts5IterClose(pSyn->pIter); + fts5BufferFree((Fts5Buffer*)&pSyn[1]); + sqlite3_free(pSyn); + } + } + if( pPhrase->poslist.nSpace>0 ) fts5BufferFree(&pPhrase->poslist); + sqlite3_free(pPhrase); + } +} + +/* +** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated +** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is +** appended to it and the results returned. +** +** If an OOM error occurs, both the pNear and pPhrase objects are freed and +** NULL returned. +*/ +static Fts5ExprNearset *sqlite3Fts5ParseNearset( + Fts5Parse *pParse, /* Parse context */ + Fts5ExprNearset *pNear, /* Existing nearset, or NULL */ + Fts5ExprPhrase *pPhrase /* Recently parsed phrase */ +){ + const int SZALLOC = 8; + Fts5ExprNearset *pRet = 0; + + if( pParse->rc==SQLITE_OK ){ + if( pPhrase==0 ){ + return pNear; + } + if( pNear==0 ){ + int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + pRet = sqlite3_malloc(nByte); + if( pRet==0 ){ + pParse->rc = SQLITE_NOMEM; + }else{ + memset(pRet, 0, nByte); + } + }else if( (pNear->nPhrase % SZALLOC)==0 ){ + int nNew = pNear->nPhrase + SZALLOC; + int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + + pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte); + if( pRet==0 ){ + pParse->rc = SQLITE_NOMEM; + } + }else{ + pRet = pNear; + } + } + + if( pRet==0 ){ + assert( pParse->rc!=SQLITE_OK ); + sqlite3Fts5ParseNearsetFree(pNear); + sqlite3Fts5ParsePhraseFree(pPhrase); + }else{ + if( pRet->nPhrase>0 ){ + Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1]; + assert( pLast==pParse->apPhrase[pParse->nPhrase-2] ); + if( pPhrase->nTerm==0 ){ + fts5ExprPhraseFree(pPhrase); + pRet->nPhrase--; + pParse->nPhrase--; + pPhrase = pLast; + }else if( pLast->nTerm==0 ){ + fts5ExprPhraseFree(pLast); + pParse->apPhrase[pParse->nPhrase-2] = pPhrase; + pParse->nPhrase--; + pRet->nPhrase--; + } + } + pRet->apPhrase[pRet->nPhrase++] = pPhrase; + } + return pRet; +} + +typedef struct TokenCtx TokenCtx; +struct TokenCtx { + Fts5ExprPhrase *pPhrase; + int rc; +}; + +/* +** Callback for tokenizing terms used by ParseTerm(). +*/ +static int fts5ParseTokenize( + void *pContext, /* Pointer to Fts5InsertCtx object */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + int rc = SQLITE_OK; + const int SZALLOC = 8; + TokenCtx *pCtx = (TokenCtx*)pContext; + Fts5ExprPhrase *pPhrase = pCtx->pPhrase; + + UNUSED_PARAM2(iUnused1, iUnused2); + + /* If an error has already occurred, this is a no-op */ + if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; + + if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ + Fts5ExprTerm *pSyn; + int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; + pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); + if( pSyn==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pSyn, 0, nByte); + pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); + memcpy(pSyn->zTerm, pToken, nToken); + pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; + pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; + } + }else{ + Fts5ExprTerm *pTerm; + if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){ + Fts5ExprPhrase *pNew; + int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); + + pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase, + sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew + ); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase)); + pCtx->pPhrase = pPhrase = pNew; + pNew->nTerm = nNew - SZALLOC; + } + } + + if( rc==SQLITE_OK ){ + pTerm = &pPhrase->aTerm[pPhrase->nTerm++]; + memset(pTerm, 0, sizeof(Fts5ExprTerm)); + pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); + } + } + + pCtx->rc = rc; + return rc; +} + + +/* +** Free the phrase object passed as the only argument. +*/ +static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase *pPhrase){ + fts5ExprPhraseFree(pPhrase); +} + +/* +** Free the phrase object passed as the second argument. +*/ +static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset *pNear){ + if( pNear ){ + int i; + for(i=0; inPhrase; i++){ + fts5ExprPhraseFree(pNear->apPhrase[i]); + } + sqlite3_free(pNear->pColset); + sqlite3_free(pNear); + } +} + +static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ + assert( pParse->pExpr==0 ); + pParse->pExpr = p; +} + +/* +** This function is called by the parser to process a string token. The +** string may or may not be quoted. In any case it is tokenized and a +** phrase object consisting of all tokens returned. +*/ +static Fts5ExprPhrase *sqlite3Fts5ParseTerm( + Fts5Parse *pParse, /* Parse context */ + Fts5ExprPhrase *pAppend, /* Phrase to append to */ + Fts5Token *pToken, /* String to tokenize */ + int bPrefix /* True if there is a trailing "*" */ +){ + Fts5Config *pConfig = pParse->pConfig; + TokenCtx sCtx; /* Context object passed to callback */ + int rc; /* Tokenize return code */ + char *z = 0; + + memset(&sCtx, 0, sizeof(TokenCtx)); + sCtx.pPhrase = pAppend; + + rc = fts5ParseStringFromToken(pToken, &z); + if( rc==SQLITE_OK ){ + int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0); + int n; + sqlite3Fts5Dequote(z); + n = (int)strlen(z); + rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize); + } + sqlite3_free(z); + if( rc || (rc = sCtx.rc) ){ + pParse->rc = rc; + fts5ExprPhraseFree(sCtx.pPhrase); + sCtx.pPhrase = 0; + }else{ + + if( pAppend==0 ){ + if( (pParse->nPhrase % 8)==0 ){ + int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); + Fts5ExprPhrase **apNew; + apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); + if( apNew==0 ){ + pParse->rc = SQLITE_NOMEM; + fts5ExprPhraseFree(sCtx.pPhrase); + return 0; + } + pParse->apPhrase = apNew; + } + pParse->nPhrase++; + } + + if( sCtx.pPhrase==0 ){ + /* This happens when parsing a token or quoted phrase that contains + ** no token characters at all. (e.g ... MATCH '""'). */ + sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); + }else if( sCtx.pPhrase->nTerm ){ + sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; + } + pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; + } + + return sCtx.pPhrase; +} + +/* +** Create a new FTS5 expression by cloning phrase iPhrase of the +** expression passed as the second argument. +*/ +static int sqlite3Fts5ExprClonePhrase( + Fts5Expr *pExpr, + int iPhrase, + Fts5Expr **ppNew +){ + int rc = SQLITE_OK; /* Return code */ + Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ + Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ + TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ + + pOrig = pExpr->apExprPhrase[iPhrase]; + pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); + if( rc==SQLITE_OK ){ + pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, + sizeof(Fts5ExprPhrase*)); + } + if( rc==SQLITE_OK ){ + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, + sizeof(Fts5ExprNode)); + } + if( rc==SQLITE_OK ){ + pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, + sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); + } + if( rc==SQLITE_OK ){ + Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; + if( pColsetOrig ){ + int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); + if( pColset ){ + memcpy(pColset, pColsetOrig, nByte); + } + pNew->pRoot->pNear->pColset = pColset; + } + } + + if( pOrig->nTerm ){ + int i; /* Used to iterate through phrase terms */ + for(i=0; rc==SQLITE_OK && inTerm; i++){ + int tflags = 0; + Fts5ExprTerm *p; + for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ + const char *zTerm = p->zTerm; + rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), + 0, 0); + tflags = FTS5_TOKEN_COLOCATED; + } + if( rc==SQLITE_OK ){ + sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; + } + } + }else{ + /* This happens when parsing a token or quoted phrase that contains + ** no token characters at all. (e.g ... MATCH '""'). */ + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); + } + + if( rc==SQLITE_OK ){ + /* All the allocations succeeded. Put the expression object together. */ + pNew->pIndex = pExpr->pIndex; + pNew->pConfig = pExpr->pConfig; + pNew->nPhrase = 1; + pNew->apExprPhrase[0] = sCtx.pPhrase; + pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; + pNew->pRoot->pNear->nPhrase = 1; + sCtx.pPhrase->pNode = pNew->pRoot; + + if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){ + pNew->pRoot->eType = FTS5_TERM; + pNew->pRoot->xNext = fts5ExprNodeNext_TERM; + }else{ + pNew->pRoot->eType = FTS5_STRING; + pNew->pRoot->xNext = fts5ExprNodeNext_STRING; + } + }else{ + sqlite3Fts5ExprFree(pNew); + fts5ExprPhraseFree(sCtx.pPhrase); + pNew = 0; + } + + *ppNew = pNew; + return rc; +} + + +/* +** Token pTok has appeared in a MATCH expression where the NEAR operator +** is expected. If token pTok does not contain "NEAR", store an error +** in the pParse object. +*/ +static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){ + if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){ + sqlite3Fts5ParseError( + pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p + ); + } +} + +static void sqlite3Fts5ParseSetDistance( + Fts5Parse *pParse, + Fts5ExprNearset *pNear, + Fts5Token *p +){ + if( pNear ){ + int nNear = 0; + int i; + if( p->n ){ + for(i=0; in; i++){ + char c = (char)p->p[i]; + if( c<'0' || c>'9' ){ + sqlite3Fts5ParseError( + pParse, "expected integer, got \"%.*s\"", p->n, p->p + ); + return; + } + nNear = nNear * 10 + (p->p[i] - '0'); + } + }else{ + nNear = FTS5_DEFAULT_NEARDIST; + } + pNear->nNear = nNear; + } +} + +/* +** The second argument passed to this function may be NULL, or it may be +** an existing Fts5Colset object. This function returns a pointer to +** a new colset object containing the contents of (p) with new value column +** number iCol appended. +** +** If an OOM error occurs, store an error code in pParse and return NULL. +** The old colset object (if any) is not freed in this case. +*/ +static Fts5Colset *fts5ParseColset( + Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ + Fts5Colset *p, /* Existing colset object */ + int iCol /* New column to add to colset object */ +){ + int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */ + Fts5Colset *pNew; /* New colset object to return */ + + assert( pParse->rc==SQLITE_OK ); + assert( iCol>=0 && iColpConfig->nCol ); + + pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + if( pNew==0 ){ + pParse->rc = SQLITE_NOMEM; + }else{ + int *aiCol = pNew->aiCol; + int i, j; + for(i=0; iiCol ) break; + } + for(j=nCol; j>i; j--){ + aiCol[j] = aiCol[j-1]; + } + aiCol[i] = iCol; + pNew->nCol = nCol+1; + +#ifndef NDEBUG + /* Check that the array is in order and contains no duplicate entries. */ + for(i=1; inCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); +#endif + } + + return pNew; +} + +/* +** Allocate and return an Fts5Colset object specifying the inverse of +** the colset passed as the second argument. Free the colset passed +** as the second argument before returning. +*/ +static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){ + Fts5Colset *pRet; + int nCol = pParse->pConfig->nCol; + + pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, + sizeof(Fts5Colset) + sizeof(int)*nCol + ); + if( pRet ){ + int i; + int iOld = 0; + for(i=0; i=p->nCol || p->aiCol[iOld]!=i ){ + pRet->aiCol[pRet->nCol++] = i; + }else{ + iOld++; + } + } + } + + sqlite3_free(p); + return pRet; +} + +static Fts5Colset *sqlite3Fts5ParseColset( + Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ + Fts5Colset *pColset, /* Existing colset object */ + Fts5Token *p +){ + Fts5Colset *pRet = 0; + int iCol; + char *z; /* Dequoted copy of token p */ + + z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n); + if( pParse->rc==SQLITE_OK ){ + Fts5Config *pConfig = pParse->pConfig; + sqlite3Fts5Dequote(z); + for(iCol=0; iColnCol; iCol++){ + if( 0==sqlite3_stricmp(pConfig->azCol[iCol], z) ) break; + } + if( iCol==pConfig->nCol ){ + sqlite3Fts5ParseError(pParse, "no such column: %s", z); + }else{ + pRet = fts5ParseColset(pParse, pColset, iCol); + } + sqlite3_free(z); + } + + if( pRet==0 ){ + assert( pParse->rc!=SQLITE_OK ); + sqlite3_free(pColset); + } + + return pRet; +} + +static void sqlite3Fts5ParseSetColset( + Fts5Parse *pParse, + Fts5ExprNearset *pNear, + Fts5Colset *pColset +){ + if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ + pParse->rc = SQLITE_ERROR; + pParse->zErr = sqlite3_mprintf( + "fts5: column queries are not supported (detail=none)" + ); + sqlite3_free(pColset); + return; + } + + if( pNear ){ + pNear->pColset = pColset; + }else{ + sqlite3_free(pColset); + } +} + +static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ + switch( pNode->eType ){ + case FTS5_STRING: { + Fts5ExprNearset *pNear = pNode->pNear; + if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 + && pNear->apPhrase[0]->aTerm[0].pSynonym==0 + ){ + pNode->eType = FTS5_TERM; + pNode->xNext = fts5ExprNodeNext_TERM; + }else{ + pNode->xNext = fts5ExprNodeNext_STRING; + } + break; + }; + + case FTS5_OR: { + pNode->xNext = fts5ExprNodeNext_OR; + break; + }; + + case FTS5_AND: { + pNode->xNext = fts5ExprNodeNext_AND; + break; + }; + + default: assert( pNode->eType==FTS5_NOT ); { + pNode->xNext = fts5ExprNodeNext_NOT; + break; + }; + } +} + +static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ + if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){ + int nByte = sizeof(Fts5ExprNode*) * pSub->nChild; + memcpy(&p->apChild[p->nChild], pSub->apChild, nByte); + p->nChild += pSub->nChild; + sqlite3_free(pSub); + }else{ + p->apChild[p->nChild++] = pSub; + } +} + +/* +** Allocate and return a new expression object. If anything goes wrong (i.e. +** OOM error), leave an error code in pParse and return NULL. +*/ +static Fts5ExprNode *sqlite3Fts5ParseNode( + Fts5Parse *pParse, /* Parse context */ + int eType, /* FTS5_STRING, AND, OR or NOT */ + Fts5ExprNode *pLeft, /* Left hand child expression */ + Fts5ExprNode *pRight, /* Right hand child expression */ + Fts5ExprNearset *pNear /* For STRING expressions, the near cluster */ +){ + Fts5ExprNode *pRet = 0; + + if( pParse->rc==SQLITE_OK ){ + int nChild = 0; /* Number of children of returned node */ + int nByte; /* Bytes of space to allocate for this node */ + + assert( (eType!=FTS5_STRING && !pNear) + || (eType==FTS5_STRING && !pLeft && !pRight) + ); + if( eType==FTS5_STRING && pNear==0 ) return 0; + if( eType!=FTS5_STRING && pLeft==0 ) return pRight; + if( eType!=FTS5_STRING && pRight==0 ) return pLeft; + + if( eType==FTS5_NOT ){ + nChild = 2; + }else if( eType==FTS5_AND || eType==FTS5_OR ){ + nChild = 2; + if( pLeft->eType==eType ) nChild += pLeft->nChild-1; + if( pRight->eType==eType ) nChild += pRight->nChild-1; + } + + nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); + + if( pRet ){ + pRet->eType = eType; + pRet->pNear = pNear; + fts5ExprAssignXNext(pRet); + if( eType==FTS5_STRING ){ + int iPhrase; + for(iPhrase=0; iPhrasenPhrase; iPhrase++){ + pNear->apPhrase[iPhrase]->pNode = pRet; + if( pNear->apPhrase[iPhrase]->nTerm==0 ){ + pRet->xNext = 0; + pRet->eType = FTS5_EOF; + } + } + + if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL + && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1) + ){ + assert( pParse->rc==SQLITE_OK ); + pParse->rc = SQLITE_ERROR; + assert( pParse->zErr==0 ); + pParse->zErr = sqlite3_mprintf( + "fts5: %s queries are not supported (detail!=full)", + pNear->nPhrase==1 ? "phrase": "NEAR" + ); + sqlite3_free(pRet); + pRet = 0; + } + + }else{ + fts5ExprAddChildren(pRet, pLeft); + fts5ExprAddChildren(pRet, pRight); + } + } + } + + if( pRet==0 ){ + assert( pParse->rc!=SQLITE_OK ); + sqlite3Fts5ParseNodeFree(pLeft); + sqlite3Fts5ParseNodeFree(pRight); + sqlite3Fts5ParseNearsetFree(pNear); + } + return pRet; +} + +static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( + Fts5Parse *pParse, /* Parse context */ + Fts5ExprNode *pLeft, /* Left hand child expression */ + Fts5ExprNode *pRight /* Right hand child expression */ +){ + Fts5ExprNode *pRet = 0; + Fts5ExprNode *pPrev; + + if( pParse->rc ){ + sqlite3Fts5ParseNodeFree(pLeft); + sqlite3Fts5ParseNodeFree(pRight); + }else{ + + assert( pLeft->eType==FTS5_STRING + || pLeft->eType==FTS5_TERM + || pLeft->eType==FTS5_EOF + || pLeft->eType==FTS5_AND + ); + assert( pRight->eType==FTS5_STRING + || pRight->eType==FTS5_TERM + || pRight->eType==FTS5_EOF + ); + + if( pLeft->eType==FTS5_AND ){ + pPrev = pLeft->apChild[pLeft->nChild-1]; + }else{ + pPrev = pLeft; + } + assert( pPrev->eType==FTS5_STRING + || pPrev->eType==FTS5_TERM + || pPrev->eType==FTS5_EOF + ); + + if( pRight->eType==FTS5_EOF ){ + assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); + sqlite3Fts5ParseNodeFree(pRight); + pRet = pLeft; + pParse->nPhrase--; + } + else if( pPrev->eType==FTS5_EOF ){ + Fts5ExprPhrase **ap; + + if( pPrev==pLeft ){ + pRet = pRight; + }else{ + pLeft->apChild[pLeft->nChild-1] = pRight; + pRet = pLeft; + } + + ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase]; + assert( ap[0]==pPrev->pNear->apPhrase[0] ); + memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase); + pParse->nPhrase--; + + sqlite3Fts5ParseNodeFree(pPrev); + } + else{ + pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); + } + } + + return pRet; +} + +static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ + int nByte = 0; + Fts5ExprTerm *p; + char *zQuoted; + + /* Determine the maximum amount of space required. */ + for(p=pTerm; p; p=p->pSynonym){ + nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; + } + zQuoted = sqlite3_malloc(nByte); + + if( zQuoted ){ + int i = 0; + for(p=pTerm; p; p=p->pSynonym){ + char *zIn = p->zTerm; + zQuoted[i++] = '"'; + while( *zIn ){ + if( *zIn=='"' ) zQuoted[i++] = '"'; + zQuoted[i++] = *zIn++; + } + zQuoted[i++] = '"'; + if( p->pSynonym ) zQuoted[i++] = '|'; + } + if( pTerm->bPrefix ){ + zQuoted[i++] = ' '; + zQuoted[i++] = '*'; + } + zQuoted[i++] = '\0'; + } + return zQuoted; +} + +static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){ + char *zNew; + va_list ap; + va_start(ap, zFmt); + zNew = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( zApp && zNew ){ + char *zNew2 = sqlite3_mprintf("%s%s", zApp, zNew); + sqlite3_free(zNew); + zNew = zNew2; + } + sqlite3_free(zApp); + return zNew; +} + +/* +** Compose a tcl-readable representation of expression pExpr. Return a +** pointer to a buffer containing that representation. It is the +** responsibility of the caller to at some point free the buffer using +** sqlite3_free(). +*/ +static char *fts5ExprPrintTcl( + Fts5Config *pConfig, + const char *zNearsetCmd, + Fts5ExprNode *pExpr +){ + char *zRet = 0; + if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pExpr->pNear; + int i; + int iTerm; + + zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd); + if( zRet==0 ) return 0; + if( pNear->pColset ){ + int *aiCol = pNear->pColset->aiCol; + int nCol = pNear->pColset->nCol; + if( nCol==1 ){ + zRet = fts5PrintfAppend(zRet, "-col %d ", aiCol[0]); + }else{ + zRet = fts5PrintfAppend(zRet, "-col {%d", aiCol[0]); + for(i=1; ipColset->nCol; i++){ + zRet = fts5PrintfAppend(zRet, " %d", aiCol[i]); + } + zRet = fts5PrintfAppend(zRet, "} "); + } + if( zRet==0 ) return 0; + } + + if( pNear->nPhrase>1 ){ + zRet = fts5PrintfAppend(zRet, "-near %d ", pNear->nNear); + if( zRet==0 ) return 0; + } + + zRet = fts5PrintfAppend(zRet, "--"); + if( zRet==0 ) return 0; + + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + + zRet = fts5PrintfAppend(zRet, " {"); + for(iTerm=0; zRet && iTermnTerm; iTerm++){ + char *zTerm = pPhrase->aTerm[iTerm].zTerm; + zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); + if( pPhrase->aTerm[iTerm].bPrefix ){ + zRet = fts5PrintfAppend(zRet, "*"); + } + } + + if( zRet ) zRet = fts5PrintfAppend(zRet, "}"); + if( zRet==0 ) return 0; + } + + }else{ + char const *zOp = 0; + int i; + switch( pExpr->eType ){ + case FTS5_AND: zOp = "AND"; break; + case FTS5_NOT: zOp = "NOT"; break; + default: + assert( pExpr->eType==FTS5_OR ); + zOp = "OR"; + break; + } + + zRet = sqlite3_mprintf("%s", zOp); + for(i=0; zRet && inChild; i++){ + char *z = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->apChild[i]); + if( !z ){ + sqlite3_free(zRet); + zRet = 0; + }else{ + zRet = fts5PrintfAppend(zRet, " [%z]", z); + } + } + } + + return zRet; +} + +static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ + char *zRet = 0; + if( pExpr->eType==0 ){ + return sqlite3_mprintf("\"\""); + }else + if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pExpr->pNear; + int i; + int iTerm; + + if( pNear->pColset ){ + int iCol = pNear->pColset->aiCol[0]; + zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); + if( zRet==0 ) return 0; + } + + if( pNear->nPhrase>1 ){ + zRet = fts5PrintfAppend(zRet, "NEAR("); + if( zRet==0 ) return 0; + } + + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + if( i!=0 ){ + zRet = fts5PrintfAppend(zRet, " "); + if( zRet==0 ) return 0; + } + for(iTerm=0; iTermnTerm; iTerm++){ + char *zTerm = fts5ExprTermPrint(&pPhrase->aTerm[iTerm]); + if( zTerm ){ + zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" + ", zTerm); + sqlite3_free(zTerm); + } + if( zTerm==0 || zRet==0 ){ + sqlite3_free(zRet); + return 0; + } + } + } + + if( pNear->nPhrase>1 ){ + zRet = fts5PrintfAppend(zRet, ", %d)", pNear->nNear); + if( zRet==0 ) return 0; + } + + }else{ + char const *zOp = 0; + int i; + + switch( pExpr->eType ){ + case FTS5_AND: zOp = " AND "; break; + case FTS5_NOT: zOp = " NOT "; break; + default: + assert( pExpr->eType==FTS5_OR ); + zOp = " OR "; + break; + } + + for(i=0; inChild; i++){ + char *z = fts5ExprPrint(pConfig, pExpr->apChild[i]); + if( z==0 ){ + sqlite3_free(zRet); + zRet = 0; + }else{ + int e = pExpr->apChild[i]->eType; + int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF); + zRet = fts5PrintfAppend(zRet, "%s%s%z%s", + (i==0 ? "" : zOp), + (b?"(":""), z, (b?")":"") + ); + } + if( zRet==0 ) break; + } + } + + return zRet; +} + +/* +** The implementation of user-defined scalar functions fts5_expr() (bTcl==0) +** and fts5_expr_tcl() (bTcl!=0). +*/ +static void fts5ExprFunction( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal, /* Function arguments */ + int bTcl +){ + Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + const char *zExpr = 0; + char *zErr = 0; + Fts5Expr *pExpr = 0; + int rc; + int i; + + const char **azConfig; /* Array of arguments for Fts5Config */ + const char *zNearsetCmd = "nearset"; + int nConfig; /* Size of azConfig[] */ + Fts5Config *pConfig = 0; + int iArg = 1; + + if( nArg<1 ){ + zErr = sqlite3_mprintf("wrong number of arguments to function %s", + bTcl ? "fts5_expr_tcl" : "fts5_expr" + ); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + return; + } + + if( bTcl && nArg>1 ){ + zNearsetCmd = (const char*)sqlite3_value_text(apVal[1]); + iArg = 2; + } + + nConfig = 3 + (nArg-iArg); + azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig); + if( azConfig==0 ){ + sqlite3_result_error_nomem(pCtx); + return; + } + azConfig[0] = 0; + azConfig[1] = "main"; + azConfig[2] = "tbl"; + for(i=3; iArgpRoot->xNext==0 ){ + zText = sqlite3_mprintf(""); + }else if( bTcl ){ + zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot); + }else{ + zText = fts5ExprPrint(pConfig, pExpr->pRoot); + } + if( zText==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_result_text(pCtx, zText, -1, SQLITE_TRANSIENT); + sqlite3_free(zText); + } + } + + if( rc!=SQLITE_OK ){ + if( zErr ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + }else{ + sqlite3_result_error_code(pCtx, rc); + } + } + sqlite3_free((void *)azConfig); + sqlite3Fts5ConfigFree(pConfig); + sqlite3Fts5ExprFree(pExpr); +} + +static void fts5ExprFunctionHr( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + fts5ExprFunction(pCtx, nArg, apVal, 0); +} +static void fts5ExprFunctionTcl( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + fts5ExprFunction(pCtx, nArg, apVal, 1); +} + +/* +** The implementation of an SQLite user-defined-function that accepts a +** single integer as an argument. If the integer is an alpha-numeric +** unicode code point, 1 is returned. Otherwise 0. +*/ +static void fts5ExprIsAlnum( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + int iCode; + if( nArg!=1 ){ + sqlite3_result_error(pCtx, + "wrong number of arguments to function fts5_isalnum", -1 + ); + return; + } + iCode = sqlite3_value_int(apVal[0]); + sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode)); +} + +static void fts5ExprFold( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apVal /* Function arguments */ +){ + if( nArg!=1 && nArg!=2 ){ + sqlite3_result_error(pCtx, + "wrong number of arguments to function fts5_fold", -1 + ); + }else{ + int iCode; + int bRemoveDiacritics = 0; + iCode = sqlite3_value_int(apVal[0]); + if( nArg==2 ) bRemoveDiacritics = sqlite3_value_int(apVal[1]); + sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics)); + } +} + +/* +** This is called during initialization to register the fts5_expr() scalar +** UDF with the SQLite handle passed as the only argument. +*/ +static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ + struct Fts5ExprFunc { + const char *z; + void (*x)(sqlite3_context*,int,sqlite3_value**); + } aFunc[] = { + { "fts5_expr", fts5ExprFunctionHr }, + { "fts5_expr_tcl", fts5ExprFunctionTcl }, + { "fts5_isalnum", fts5ExprIsAlnum }, + { "fts5_fold", fts5ExprFold }, + }; + int i; + int rc = SQLITE_OK; + void *pCtx = (void*)pGlobal; + + for(i=0; rc==SQLITE_OK && iz, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); + } + + /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ +#ifndef NDEBUG + (void)sqlite3Fts5ParserTrace; +#endif + + return rc; +} + +/* +** Return the number of phrases in expression pExpr. +*/ +static int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){ + return (pExpr ? pExpr->nPhrase : 0); +} + +/* +** Return the number of terms in the iPhrase'th phrase in pExpr. +*/ +static int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){ + if( iPhrase<0 || iPhrase>=pExpr->nPhrase ) return 0; + return pExpr->apExprPhrase[iPhrase]->nTerm; +} + +/* +** This function is used to access the current position list for phrase +** iPhrase. +*/ +static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){ + int nRet; + Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; + Fts5ExprNode *pNode = pPhrase->pNode; + if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){ + *pa = pPhrase->poslist.p; + nRet = pPhrase->poslist.n; + }else{ + *pa = 0; + nRet = 0; + } + return nRet; +} + +struct Fts5PoslistPopulator { + Fts5PoslistWriter writer; + int bOk; /* True if ok to populate */ + int bMiss; +}; + +static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ + Fts5PoslistPopulator *pRet; + pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + if( pRet ){ + int i; + memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + for(i=0; inPhrase; i++){ + Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; + assert( pExpr->apExprPhrase[i]->nTerm==1 ); + if( bLive && + (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) + ){ + pRet[i].bMiss = 1; + }else{ + pBuf->n = 0; + } + } + } + return pRet; +} + +struct Fts5ExprCtx { + Fts5Expr *pExpr; + Fts5PoslistPopulator *aPopulator; + i64 iOff; +}; +typedef struct Fts5ExprCtx Fts5ExprCtx; + +/* +** TODO: Make this more efficient! +*/ +static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + +static int fts5ExprPopulatePoslistsCb( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Byte offset of token within input text */ + int iUnused2 /* Byte offset of end of token within input text */ +){ + Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx; + Fts5Expr *pExpr = p->pExpr; + int i; + + UNUSED_PARAM2(iUnused1, iUnused2); + + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; + for(i=0; inPhrase; i++){ + Fts5ExprTerm *pTerm; + if( p->aPopulator[i].bOk==0 ) continue; + for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + int nTerm = (int)strlen(pTerm->zTerm); + if( (nTerm==nToken || (nTermbPrefix)) + && memcmp(pTerm->zTerm, pToken, nTerm)==0 + ){ + int rc = sqlite3Fts5PoslistWriterAppend( + &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff + ); + if( rc ) return rc; + break; + } + } + } + return SQLITE_OK; +} + +static int sqlite3Fts5ExprPopulatePoslists( + Fts5Config *pConfig, + Fts5Expr *pExpr, + Fts5PoslistPopulator *aPopulator, + int iCol, + const char *z, int n +){ + int i; + Fts5ExprCtx sCtx; + sCtx.pExpr = pExpr; + sCtx.aPopulator = aPopulator; + sCtx.iOff = (((i64)iCol) << 32) - 1; + + for(i=0; inPhrase; i++){ + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; + Fts5Colset *pColset = pNode->pNear->pColset; + if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) + || aPopulator[i].bMiss + ){ + aPopulator[i].bOk = 0; + }else{ + aPopulator[i].bOk = 1; + } + } + + return sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb + ); +} + +static void fts5ExprClearPoslists(Fts5ExprNode *pNode){ + if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){ + pNode->pNear->apPhrase[0]->poslist.n = 0; + }else{ + int i; + for(i=0; inChild; i++){ + fts5ExprClearPoslists(pNode->apChild[i]); + } + } +} + +static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ + pNode->iRowid = iRowid; + pNode->bEof = 0; + switch( pNode->eType ){ + case FTS5_TERM: + case FTS5_STRING: + return (pNode->pNear->apPhrase[0]->poslist.n>0); + + case FTS5_AND: { + int i; + for(i=0; inChild; i++){ + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){ + fts5ExprClearPoslists(pNode); + return 0; + } + } + break; + } + + case FTS5_OR: { + int i; + int bRet = 0; + for(i=0; inChild; i++){ + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){ + bRet = 1; + } + } + return bRet; + } + + default: { + assert( pNode->eType==FTS5_NOT ); + if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid) + || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid) + ){ + fts5ExprClearPoslists(pNode); + return 0; + } + break; + } + } + return 1; +} + +static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ + fts5ExprCheckPoslists(pExpr->pRoot, iRowid); +} + +/* +** This function is only called for detail=columns tables. +*/ +static int sqlite3Fts5ExprPhraseCollist( + Fts5Expr *pExpr, + int iPhrase, + const u8 **ppCollist, + int *pnCollist +){ + Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; + Fts5ExprNode *pNode = pPhrase->pNode; + int rc = SQLITE_OK; + + assert( iPhrase>=0 && iPhrasenPhrase ); + assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + + if( pNode->bEof==0 + && pNode->iRowid==pExpr->pRoot->iRowid + && pPhrase->poslist.n>0 + ){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[0]; + if( pTerm->pSynonym ){ + Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1]; + rc = fts5ExprSynonymList( + pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist + ); + }else{ + *ppCollist = pPhrase->aTerm[0].pIter->pData; + *pnCollist = pPhrase->aTerm[0].pIter->nData; + } + }else{ + *ppCollist = 0; + *pnCollist = 0; + } + + return rc; +} + + +#line 1 "fts5_hash.c" +/* +** 2014 August 11 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ + + + +/* #include "fts5Int.h" */ + +typedef struct Fts5HashEntry Fts5HashEntry; + +/* +** This file contains the implementation of an in-memory hash table used +** to accumuluate "term -> doclist" content before it is flused to a level-0 +** segment. +*/ + + +struct Fts5Hash { + int eDetail; /* Copy of Fts5Config.eDetail */ + int *pnByte; /* Pointer to bytes counter */ + int nEntry; /* Number of entries currently in hash */ + int nSlot; /* Size of aSlot[] array */ + Fts5HashEntry *pScan; /* Current ordered scan item */ + Fts5HashEntry **aSlot; /* Array of hash slots */ +}; + +/* +** Each entry in the hash table is represented by an object of the +** following type. Each object, its key (zKey[]) and its current data +** are stored in a single memory allocation. The position list data +** immediately follows the key data in memory. +** +** The data that follows the key is in a similar, but not identical format +** to the doclist data stored in the database. It is: +** +** * Rowid, as a varint +** * Position list, without 0x00 terminator. +** * Size of previous position list and rowid, as a 4 byte +** big-endian integer. +** +** iRowidOff: +** Offset of last rowid written to data area. Relative to first byte of +** structure. +** +** nData: +** Bytes of data written since iRowidOff. +*/ +struct Fts5HashEntry { + Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ + Fts5HashEntry *pScanNext; /* Next entry in sorted order */ + + int nAlloc; /* Total size of allocation */ + int iSzPoslist; /* Offset of space for 4-byte poslist size */ + int nData; /* Total bytes of data (incl. structure) */ + int nKey; /* Length of zKey[] in bytes */ + u8 bDel; /* Set delete-flag @ iSzPoslist */ + u8 bContent; /* Set content-flag (detail=none mode) */ + i16 iCol; /* Column of last value written */ + int iPos; /* Position of last value written */ + i64 iRowid; /* Rowid of last value written */ + char zKey[8]; /* Nul-terminated entry key */ +}; + +/* +** Size of Fts5HashEntry without the zKey[] array. +*/ +#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8) + + + +/* +** Allocate a new hash table. +*/ +static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ + int rc = SQLITE_OK; + Fts5Hash *pNew; + + *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + int nByte; + memset(pNew, 0, sizeof(Fts5Hash)); + pNew->pnByte = pnByte; + pNew->eDetail = pConfig->eDetail; + + pNew->nSlot = 1024; + nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; + pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); + if( pNew->aSlot==0 ){ + sqlite3_free(pNew); + *ppNew = 0; + rc = SQLITE_NOMEM; + }else{ + memset(pNew->aSlot, 0, nByte); + } + } + return rc; +} + +/* +** Free a hash table object. +*/ +static void sqlite3Fts5HashFree(Fts5Hash *pHash){ + if( pHash ){ + sqlite3Fts5HashClear(pHash); + sqlite3_free(pHash->aSlot); + sqlite3_free(pHash); + } +} + +/* +** Empty (but do not delete) a hash table. +*/ +static void sqlite3Fts5HashClear(Fts5Hash *pHash){ + int i; + for(i=0; inSlot; i++){ + Fts5HashEntry *pNext; + Fts5HashEntry *pSlot; + for(pSlot=pHash->aSlot[i]; pSlot; pSlot=pNext){ + pNext = pSlot->pHashNext; + sqlite3_free(pSlot); + } + } + memset(pHash->aSlot, 0, pHash->nSlot * sizeof(Fts5HashEntry*)); + pHash->nEntry = 0; +} + +static unsigned int fts5HashKey(int nSlot, const u8 *p, int n){ + int i; + unsigned int h = 13; + for(i=n-1; i>=0; i--){ + h = (h << 3) ^ h ^ p[i]; + } + return (h % nSlot); +} + +static unsigned int fts5HashKey2(int nSlot, u8 b, const u8 *p, int n){ + int i; + unsigned int h = 13; + for(i=n-1; i>=0; i--){ + h = (h << 3) ^ h ^ p[i]; + } + h = (h << 3) ^ h ^ b; + return (h % nSlot); +} + +/* +** Resize the hash table by doubling the number of slots. +*/ +static int fts5HashResize(Fts5Hash *pHash){ + int nNew = pHash->nSlot*2; + int i; + Fts5HashEntry **apNew; + Fts5HashEntry **apOld = pHash->aSlot; + + apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*)); + if( !apNew ) return SQLITE_NOMEM; + memset(apNew, 0, nNew*sizeof(Fts5HashEntry*)); + + for(i=0; inSlot; i++){ + while( apOld[i] ){ + int iHash; + Fts5HashEntry *p = apOld[i]; + apOld[i] = p->pHashNext; + iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey)); + p->pHashNext = apNew[iHash]; + apNew[iHash] = p; + } + } + + sqlite3_free(apOld); + pHash->nSlot = nNew; + pHash->aSlot = apNew; + return SQLITE_OK; +} + +static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ + if( p->iSzPoslist ){ + u8 *pPtr = (u8*)p; + if( pHash->eDetail==FTS5_DETAIL_NONE ){ + assert( p->nData==p->iSzPoslist ); + if( p->bDel ){ + pPtr[p->nData++] = 0x00; + if( p->bContent ){ + pPtr[p->nData++] = 0x00; + } + } + }else{ + int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nPos = nSz*2 + p->bDel; /* Value of nPos field */ + + assert( p->bDel==0 || p->bDel==1 ); + if( nPos<=127 ){ + pPtr[p->iSzPoslist] = (u8)nPos; + }else{ + int nByte = sqlite3Fts5GetVarintLen((u32)nPos); + memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); + sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); + p->nData += (nByte-1); + } + } + + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; + } +} + +/* +** Add an entry to the in-memory hash table. The key is the concatenation +** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). +** +** (bByte || pToken) -> (iRowid,iCol,iPos) +** +** Or, if iCol is negative, then the value is a delete marker. +*/ +static int sqlite3Fts5HashWrite( + Fts5Hash *pHash, + i64 iRowid, /* Rowid for this entry */ + int iCol, /* Column token appears in (-ve -> delete) */ + int iPos, /* Position of token within column */ + char bByte, /* First byte of token */ + const char *pToken, int nToken /* Token to add or remove to or from index */ +){ + unsigned int iHash; + Fts5HashEntry *p; + u8 *pPtr; + int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ + int bNew; /* If non-delete entry should be written */ + + bNew = (pHash->eDetail==FTS5_DETAIL_FULL); + + /* Attempt to locate an existing hash entry */ + iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); + for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ + if( p->zKey[0]==bByte + && p->nKey==nToken + && memcmp(&p->zKey[1], pToken, nToken)==0 + ){ + break; + } + } + + /* If an existing hash entry cannot be found, create a new one. */ + if( p==0 ){ + /* Figure out how much space to allocate */ + int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; + if( nByte<128 ) nByte = 128; + + /* Grow the Fts5Hash.aSlot[] array if necessary. */ + if( (pHash->nEntry*2)>=pHash->nSlot ){ + int rc = fts5HashResize(pHash); + if( rc!=SQLITE_OK ) return rc; + iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); + } + + /* Allocate new Fts5HashEntry and add it to the hash table. */ + p = (Fts5HashEntry*)sqlite3_malloc(nByte); + if( !p ) return SQLITE_NOMEM; + memset(p, 0, FTS5_HASHENTRYSIZE); + p->nAlloc = nByte; + p->zKey[0] = bByte; + memcpy(&p->zKey[1], pToken, nToken); + assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); + p->nKey = nToken; + p->zKey[nToken+1] = '\0'; + p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; + p->pHashNext = pHash->aSlot[iHash]; + pHash->aSlot[iHash] = p; + pHash->nEntry++; + + /* Add the first rowid field to the hash-entry */ + p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); + p->iRowid = iRowid; + + p->iSzPoslist = p->nData; + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ + p->nData += 1; + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); + } + + nIncr += p->nData; + }else{ + + /* Appending to an existing hash-entry. Check that there is enough + ** space to append the largest possible new entry. Worst case scenario + ** is: + ** + ** + 9 bytes for a new rowid, + ** + 4 byte reserved for the "poslist size" varint. + ** + 1 byte for a "new column" byte, + ** + 3 bytes for a new column number (16-bit max) as a varint, + ** + 5 bytes for the new position offset (32-bit max). + */ + if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ + int nNew = p->nAlloc * 2; + Fts5HashEntry *pNew; + Fts5HashEntry **pp; + pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->nAlloc = nNew; + for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); + *pp = pNew; + p = pNew; + } + nIncr -= p->nData; + } + assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); + + pPtr = (u8*)p; + + /* If this is a new rowid, append the 4-byte size field for the previous + ** entry, and the new rowid for this entry. */ + if( iRowid!=p->iRowid ){ + fts5HashAddPoslistSize(pHash, p); + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); + p->iRowid = iRowid; + bNew = 1; + p->iSzPoslist = p->nData; + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ + p->nData += 1; + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); + p->iPos = 0; + } + } + + if( iCol>=0 ){ + if( pHash->eDetail==FTS5_DETAIL_NONE ){ + p->bContent = 1; + }else{ + /* Append a new column value, if necessary */ + assert( iCol>=p->iCol ); + if( iCol!=p->iCol ){ + if( pHash->eDetail==FTS5_DETAIL_FULL ){ + pPtr[p->nData++] = 0x01; + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); + p->iCol = (i16)iCol; + p->iPos = 0; + }else{ + bNew = 1; + p->iCol = (i16)(iPos = iCol); + } + } + + /* Append the new position offset, if necessary */ + if( bNew ){ + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); + p->iPos = iPos; + } + } + }else{ + /* This is a delete. Set the delete flag. */ + p->bDel = 1; + } + + nIncr += p->nData; + *pHash->pnByte += nIncr; + return SQLITE_OK; +} + + +/* +** Arguments pLeft and pRight point to linked-lists of hash-entry objects, +** each sorted in key order. This function merges the two lists into a +** single list and returns a pointer to its first element. +*/ +static Fts5HashEntry *fts5HashEntryMerge( + Fts5HashEntry *pLeft, + Fts5HashEntry *pRight +){ + Fts5HashEntry *p1 = pLeft; + Fts5HashEntry *p2 = pRight; + Fts5HashEntry *pRet = 0; + Fts5HashEntry **ppOut = &pRet; + + while( p1 || p2 ){ + if( p1==0 ){ + *ppOut = p2; + p2 = 0; + }else if( p2==0 ){ + *ppOut = p1; + p1 = 0; + }else{ + int i = 0; + while( p1->zKey[i]==p2->zKey[i] ) i++; + + if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){ + /* p2 is smaller */ + *ppOut = p2; + ppOut = &p2->pScanNext; + p2 = p2->pScanNext; + }else{ + /* p1 is smaller */ + *ppOut = p1; + ppOut = &p1->pScanNext; + p1 = p1->pScanNext; + } + *ppOut = 0; + } + } + + return pRet; +} + +/* +** Extract all tokens from hash table iHash and link them into a list +** in sorted order. The hash table is cleared before returning. It is +** the responsibility of the caller to free the elements of the returned +** list. +*/ +static int fts5HashEntrySort( + Fts5Hash *pHash, + const char *pTerm, int nTerm, /* Query prefix, if any */ + Fts5HashEntry **ppSorted +){ + const int nMergeSlot = 32; + Fts5HashEntry **ap; + Fts5HashEntry *pList; + int iSlot; + int i; + + *ppSorted = 0; + ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot); + if( !ap ) return SQLITE_NOMEM; + memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot); + + for(iSlot=0; iSlotnSlot; iSlot++){ + Fts5HashEntry *pIter; + for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ + if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){ + Fts5HashEntry *pEntry = pIter; + pEntry->pScanNext = 0; + for(i=0; ap[i]; i++){ + pEntry = fts5HashEntryMerge(pEntry, ap[i]); + ap[i] = 0; + } + ap[i] = pEntry; + } + } + } + + pList = 0; + for(i=0; inEntry = 0; + sqlite3_free(ap); + *ppSorted = pList; + return SQLITE_OK; +} + +/* +** Query the hash table for a doclist associated with term pTerm/nTerm. +*/ +static int sqlite3Fts5HashQuery( + Fts5Hash *pHash, /* Hash table to query */ + const char *pTerm, int nTerm, /* Query term */ + const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + int *pnDoclist /* OUT: Size of doclist in bytes */ +){ + unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); + Fts5HashEntry *p; + + for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ + if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; + } + + if( p ){ + fts5HashAddPoslistSize(pHash, p); + *ppDoclist = (const u8*)&p->zKey[nTerm+1]; + *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + }else{ + *ppDoclist = 0; + *pnDoclist = 0; + } + + return SQLITE_OK; +} + +static int sqlite3Fts5HashScanInit( + Fts5Hash *p, /* Hash table to query */ + const char *pTerm, int nTerm /* Query prefix */ +){ + return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan); +} + +static void sqlite3Fts5HashScanNext(Fts5Hash *p){ + assert( !sqlite3Fts5HashScanEof(p) ); + p->pScan = p->pScan->pScanNext; +} + +static int sqlite3Fts5HashScanEof(Fts5Hash *p){ + return (p->pScan==0); +} + +static void sqlite3Fts5HashScanEntry( + Fts5Hash *pHash, + const char **pzTerm, /* OUT: term (nul-terminated) */ + const u8 **ppDoclist, /* OUT: pointer to doclist */ + int *pnDoclist /* OUT: size of doclist in bytes */ +){ + Fts5HashEntry *p; + if( (p = pHash->pScan) ){ + int nTerm = (int)strlen(p->zKey); + fts5HashAddPoslistSize(pHash, p); + *pzTerm = p->zKey; + *ppDoclist = (const u8*)&p->zKey[nTerm+1]; + *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + }else{ + *pzTerm = 0; + *ppDoclist = 0; + *pnDoclist = 0; + } +} + + +#line 1 "fts5_index.c" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Low level access to the FTS index stored in the database file. The +** routines in this file file implement all read and write access to the +** %_data table. Other parts of the system access this functionality via +** the interface defined in fts5Int.h. +*/ + + +/* #include "fts5Int.h" */ + +/* +** Overview: +** +** The %_data table contains all the FTS indexes for an FTS5 virtual table. +** As well as the main term index, there may be up to 31 prefix indexes. +** The format is similar to FTS3/4, except that: +** +** * all segment b-tree leaf data is stored in fixed size page records +** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is +** taken to ensure it is possible to iterate in either direction through +** the entries in a doclist, or to seek to a specific entry within a +** doclist, without loading it into memory. +** +** * large doclists that span many pages have associated "doclist index" +** records that contain a copy of the first rowid on each page spanned by +** the doclist. This is used to speed up seek operations, and merges of +** large doclists with very small doclists. +** +** * extra fields in the "structure record" record the state of ongoing +** incremental merge operations. +** +*/ + + +#define FTS5_OPT_WORK_UNIT 1000 /* Number of leaf pages per optimize step */ +#define FTS5_WORK_UNIT 64 /* Number of leaf pages in unit of work */ + +#define FTS5_MIN_DLIDX_SIZE 4 /* Add dlidx if this many empty pages */ + +#define FTS5_MAIN_PREFIX '0' + +#if FTS5_MAX_PREFIX_INDEXES > 31 +# error "FTS5_MAX_PREFIX_INDEXES is too large" +#endif + +/* +** Details: +** +** The %_data table managed by this module, +** +** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB); +** +** , contains the following 5 types of records. See the comments surrounding +** the FTS5_*_ROWID macros below for a description of how %_data rowids are +** assigned to each fo them. +** +** 1. Structure Records: +** +** The set of segments that make up an index - the index structure - are +** recorded in a single record within the %_data table. The record consists +** of a single 32-bit configuration cookie value followed by a list of +** SQLite varints. If the FTS table features more than one index (because +** there are one or more prefix indexes), it is guaranteed that all share +** the same cookie value. +** +** Immediately following the configuration cookie, the record begins with +** three varints: +** +** + number of levels, +** + total number of segments on all levels, +** + value of write counter. +** +** Then, for each level from 0 to nMax: +** +** + number of input segments in ongoing merge. +** + total number of segments in level. +** + for each segment from oldest to newest: +** + segment id (always > 0) +** + first leaf page number (often 1, always greater than 0) +** + final leaf page number +** +** 2. The Averages Record: +** +** A single record within the %_data table. The data is a list of varints. +** The first value is the number of rows in the index. Then, for each column +** from left to right, the total number of tokens in the column for all +** rows of the table. +** +** 3. Segment leaves: +** +** TERM/DOCLIST FORMAT: +** +** Most of each segment leaf is taken up by term/doclist data. The +** general format of term/doclist, starting with the first term +** on the leaf page, is: +** +** varint : size of first term +** blob: first term data +** doclist: first doclist +** zero-or-more { +** varint: number of bytes in common with previous term +** varint: number of bytes of new term data (nNew) +** blob: nNew bytes of new term data +** doclist: next doclist +** } +** +** doclist format: +** +** varint: first rowid +** poslist: first poslist +** zero-or-more { +** varint: rowid delta (always > 0) +** poslist: next poslist +** } +** +** poslist format: +** +** varint: size of poslist in bytes multiplied by 2, not including +** this field. Plus 1 if this entry carries the "delete" flag. +** collist: collist for column 0 +** zero-or-more { +** 0x01 byte +** varint: column number (I) +** collist: collist for column I +** } +** +** collist format: +** +** varint: first offset + 2 +** zero-or-more { +** varint: offset delta + 2 +** } +** +** PAGE FORMAT +** +** Each leaf page begins with a 4-byte header containing 2 16-bit +** unsigned integer fields in big-endian format. They are: +** +** * The byte offset of the first rowid on the page, if it exists +** and occurs before the first term (otherwise 0). +** +** * The byte offset of the start of the page footer. If the page +** footer is 0 bytes in size, then this field is the same as the +** size of the leaf page in bytes. +** +** The page footer consists of a single varint for each term located +** on the page. Each varint is the byte offset of the current term +** within the page, delta-compressed against the previous value. In +** other words, the first varint in the footer is the byte offset of +** the first term, the second is the byte offset of the second less that +** of the first, and so on. +** +** The term/doclist format described above is accurate if the entire +** term/doclist data fits on a single leaf page. If this is not the case, +** the format is changed in two ways: +** +** + if the first rowid on a page occurs before the first term, it +** is stored as a literal value: +** +** varint: first rowid +** +** + the first term on each page is stored in the same way as the +** very first term of the segment: +** +** varint : size of first term +** blob: first term data +** +** 5. Segment doclist indexes: +** +** Doclist indexes are themselves b-trees, however they usually consist of +** a single leaf record only. The format of each doclist index leaf page +** is: +** +** * Flags byte. Bits are: +** 0x01: Clear if leaf is also the root page, otherwise set. +** +** * Page number of fts index leaf page. As a varint. +** +** * First rowid on page indicated by previous field. As a varint. +** +** * A list of varints, one for each subsequent termless page. A +** positive delta if the termless page contains at least one rowid, +** or an 0x00 byte otherwise. +** +** Internal doclist index nodes are: +** +** * Flags byte. Bits are: +** 0x01: Clear for root page, otherwise set. +** +** * Page number of first child page. As a varint. +** +** * Copy of first rowid on page indicated by previous field. As a varint. +** +** * A list of delta-encoded varints - the first rowid on each subsequent +** child page. +** +*/ + +/* +** Rowids for the averages and structure records in the %_data table. +*/ +#define FTS5_AVERAGES_ROWID 1 /* Rowid used for the averages record */ +#define FTS5_STRUCTURE_ROWID 10 /* The structure record */ + +/* +** Macros determining the rowids used by segment leaves and dlidx leaves +** and nodes. All nodes and leaves are stored in the %_data table with large +** positive rowids. +** +** Each segment has a unique non-zero 16-bit id. +** +** The rowid for each segment leaf is found by passing the segment id and +** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered +** sequentially starting from 1. +*/ +#define FTS5_DATA_ID_B 16 /* Max seg id number 65535 */ +#define FTS5_DATA_DLI_B 1 /* Doclist-index flag (1 bit) */ +#define FTS5_DATA_HEIGHT_B 5 /* Max dlidx tree height of 32 */ +#define FTS5_DATA_PAGE_B 31 /* Max page number of 2147483648 */ + +#define fts5_dri(segid, dlidx, height, pgno) ( \ + ((i64)(segid) << (FTS5_DATA_PAGE_B+FTS5_DATA_HEIGHT_B+FTS5_DATA_DLI_B)) + \ + ((i64)(dlidx) << (FTS5_DATA_PAGE_B + FTS5_DATA_HEIGHT_B)) + \ + ((i64)(height) << (FTS5_DATA_PAGE_B)) + \ + ((i64)(pgno)) \ +) + +#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno) +#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno) + +/* +** Maximum segments permitted in a single index +*/ +#define FTS5_MAX_SEGMENT 2000 + +#ifdef SQLITE_DEBUG +static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; } +#endif + + +/* +** Each time a blob is read from the %_data table, it is padded with this +** many zero bytes. This makes it easier to decode the various record formats +** without overreading if the records are corrupt. +*/ +#define FTS5_DATA_ZERO_PADDING 8 +#define FTS5_DATA_PADDING 20 + +typedef struct Fts5Data Fts5Data; +typedef struct Fts5DlidxIter Fts5DlidxIter; +typedef struct Fts5DlidxLvl Fts5DlidxLvl; +typedef struct Fts5DlidxWriter Fts5DlidxWriter; +typedef struct Fts5Iter Fts5Iter; +typedef struct Fts5PageWriter Fts5PageWriter; +typedef struct Fts5SegIter Fts5SegIter; +typedef struct Fts5DoclistIter Fts5DoclistIter; +typedef struct Fts5SegWriter Fts5SegWriter; +typedef struct Fts5Structure Fts5Structure; +typedef struct Fts5StructureLevel Fts5StructureLevel; +typedef struct Fts5StructureSegment Fts5StructureSegment; + +struct Fts5Data { + u8 *p; /* Pointer to buffer containing record */ + int nn; /* Size of record in bytes */ + int szLeaf; /* Size of leaf without page-index */ +}; + +/* +** One object per %_data table. +*/ +struct Fts5Index { + Fts5Config *pConfig; /* Virtual table configuration */ + char *zDataTbl; /* Name of %_data table */ + int nWorkUnit; /* Leaf pages in a "unit" of work */ + + /* + ** Variables related to the accumulation of tokens and doclists within the + ** in-memory hash tables before they are flushed to disk. + */ + Fts5Hash *pHash; /* Hash table for in-memory data */ + int nPendingData; /* Current bytes of pending data */ + i64 iWriteRowid; /* Rowid for current doc being written */ + int bDelete; /* Current write is a delete */ + + /* Error state. */ + int rc; /* Current error code */ + + /* State used by the fts5DataXXX() functions. */ + sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ + sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ + sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ + sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ + sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */ + sqlite3_stmt *pIdxSelect; + int nRead; /* Total number of blocks read */ + + sqlite3_stmt *pDataVersion; + i64 iStructVersion; /* data_version when pStruct read */ + Fts5Structure *pStruct; /* Current db structure (or NULL) */ +}; + +struct Fts5DoclistIter { + u8 *aEof; /* Pointer to 1 byte past end of doclist */ + + /* Output variables. aPoslist==0 at EOF */ + i64 iRowid; + u8 *aPoslist; + int nPoslist; + int nSize; +}; + +/* +** The contents of the "structure" record for each index are represented +** using an Fts5Structure record in memory. Which uses instances of the +** other Fts5StructureXXX types as components. +*/ +struct Fts5StructureSegment { + int iSegid; /* Segment id */ + int pgnoFirst; /* First leaf page number in segment */ + int pgnoLast; /* Last leaf page number in segment */ +}; +struct Fts5StructureLevel { + int nMerge; /* Number of segments in incr-merge */ + int nSeg; /* Total number of segments on level */ + Fts5StructureSegment *aSeg; /* Array of segments. aSeg[0] is oldest. */ +}; +struct Fts5Structure { + int nRef; /* Object reference count */ + u64 nWriteCounter; /* Total leaves written to level 0 */ + int nSegment; /* Total segments in this structure */ + int nLevel; /* Number of levels in this index */ + Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */ +}; + +/* +** An object of type Fts5SegWriter is used to write to segments. +*/ +struct Fts5PageWriter { + int pgno; /* Page number for this page */ + int iPrevPgidx; /* Previous value written into pgidx */ + Fts5Buffer buf; /* Buffer containing leaf data */ + Fts5Buffer pgidx; /* Buffer containing page-index */ + Fts5Buffer term; /* Buffer containing previous term on page */ +}; +struct Fts5DlidxWriter { + int pgno; /* Page number for this page */ + int bPrevValid; /* True if iPrev is valid */ + i64 iPrev; /* Previous rowid value written to page */ + Fts5Buffer buf; /* Buffer containing page data */ +}; +struct Fts5SegWriter { + int iSegid; /* Segid to write to */ + Fts5PageWriter writer; /* PageWriter object */ + i64 iPrevRowid; /* Previous rowid written to current leaf */ + u8 bFirstRowidInDoclist; /* True if next rowid is first in doclist */ + u8 bFirstRowidInPage; /* True if next rowid is first in page */ + /* TODO1: Can use (writer.pgidx.n==0) instead of bFirstTermInPage */ + u8 bFirstTermInPage; /* True if next term will be first in leaf */ + int nLeafWritten; /* Number of leaf pages written */ + int nEmpty; /* Number of contiguous term-less nodes */ + + int nDlidx; /* Allocated size of aDlidx[] array */ + Fts5DlidxWriter *aDlidx; /* Array of Fts5DlidxWriter objects */ + + /* Values to insert into the %_idx table */ + Fts5Buffer btterm; /* Next term to insert into %_idx table */ + int iBtPage; /* Page number corresponding to btterm */ +}; + +typedef struct Fts5CResult Fts5CResult; +struct Fts5CResult { + u16 iFirst; /* aSeg[] index of firstest iterator */ + u8 bTermEq; /* True if the terms are equal */ +}; + +/* +** Object for iterating through a single segment, visiting each term/rowid +** pair in the segment. +** +** pSeg: +** The segment to iterate through. +** +** iLeafPgno: +** Current leaf page number within segment. +** +** iLeafOffset: +** Byte offset within the current leaf that is the first byte of the +** position list data (one byte passed the position-list size field). +** rowid field of the current entry. Usually this is the size field of the +** position list data. The exception is if the rowid for the current entry +** is the last thing on the leaf page. +** +** pLeaf: +** Buffer containing current leaf page data. Set to NULL at EOF. +** +** iTermLeafPgno, iTermLeafOffset: +** Leaf page number containing the last term read from the segment. And +** the offset immediately following the term data. +** +** flags: +** Mask of FTS5_SEGITER_XXX values. Interpreted as follows: +** +** FTS5_SEGITER_ONETERM: +** If set, set the iterator to point to EOF after the current doclist +** has been exhausted. Do not proceed to the next term in the segment. +** +** FTS5_SEGITER_REVERSE: +** This flag is only ever set if FTS5_SEGITER_ONETERM is also set. If +** it is set, iterate through rowid in descending order instead of the +** default ascending order. +** +** iRowidOffset/nRowidOffset/aRowidOffset: +** These are used if the FTS5_SEGITER_REVERSE flag is set. +** +** For each rowid on the page corresponding to the current term, the +** corresponding aRowidOffset[] entry is set to the byte offset of the +** start of the "position-list-size" field within the page. +** +** iTermIdx: +** Index of current term on iTermLeafPgno. +*/ +struct Fts5SegIter { + Fts5StructureSegment *pSeg; /* Segment to iterate through */ + int flags; /* Mask of configuration flags */ + int iLeafPgno; /* Current leaf page number */ + Fts5Data *pLeaf; /* Current leaf data */ + Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ + int iLeafOffset; /* Byte offset within current leaf */ + + /* Next method */ + void (*xNext)(Fts5Index*, Fts5SegIter*, int*); + + /* The page and offset from which the current term was read. The offset + ** is the offset of the first rowid in the current doclist. */ + int iTermLeafPgno; + int iTermLeafOffset; + + int iPgidxOff; /* Next offset in pgidx */ + int iEndofDoclist; + + /* The following are only used if the FTS5_SEGITER_REVERSE flag is set. */ + int iRowidOffset; /* Current entry in aRowidOffset[] */ + int nRowidOffset; /* Allocated size of aRowidOffset[] array */ + int *aRowidOffset; /* Array of offset to rowid fields */ + + Fts5DlidxIter *pDlidx; /* If there is a doclist-index */ + + /* Variables populated based on current entry. */ + Fts5Buffer term; /* Current term */ + i64 iRowid; /* Current rowid */ + int nPos; /* Number of bytes in current position list */ + u8 bDel; /* True if the delete flag is set */ +}; + +/* +** Argument is a pointer to an Fts5Data structure that contains a +** leaf page. +*/ +#define ASSERT_SZLEAF_OK(x) assert( \ + (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \ +) + +#define FTS5_SEGITER_ONETERM 0x01 +#define FTS5_SEGITER_REVERSE 0x02 + +/* +** Argument is a pointer to an Fts5Data structure that contains a leaf +** page. This macro evaluates to true if the leaf contains no terms, or +** false if it contains at least one term. +*/ +#define fts5LeafIsTermless(x) ((x)->szLeaf >= (x)->nn) + +#define fts5LeafTermOff(x, i) (fts5GetU16(&(x)->p[(x)->szLeaf + (i)*2])) + +#define fts5LeafFirstRowidOff(x) (fts5GetU16((x)->p)) + +/* +** Object for iterating through the merged results of one or more segments, +** visiting each term/rowid pair in the merged data. +** +** nSeg is always a power of two greater than or equal to the number of +** segments that this object is merging data from. Both the aSeg[] and +** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded +** with zeroed objects - these are handled as if they were iterators opened +** on empty segments. +** +** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an +** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the +** comparison in this context is the index of the iterator that currently +** points to the smaller term/rowid combination. Iterators at EOF are +** considered to be greater than all other iterators. +** +** aFirst[1] contains the index in aSeg[] of the iterator that points to +** the smallest key overall. aFirst[0] is unused. +** +** poslist: +** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. +** There is no way to tell if this is populated or not. +*/ +struct Fts5Iter { + Fts5IndexIter base; /* Base class containing output vars */ + + Fts5Index *pIndex; /* Index that owns this iterator */ + Fts5Structure *pStruct; /* Database structure for this iterator */ + Fts5Buffer poslist; /* Buffer containing current poslist */ + Fts5Colset *pColset; /* Restrict matches to these columns */ + + /* Invoked to set output variables. */ + void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*); + + int nSeg; /* Size of aSeg[] array */ + int bRev; /* True to iterate in reverse order */ + u8 bSkipEmpty; /* True to skip deleted entries */ + + i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ + Fts5CResult *aFirst; /* Current merge state (see above) */ + Fts5SegIter aSeg[1]; /* Array of segment iterators */ +}; + + +/* +** An instance of the following type is used to iterate through the contents +** of a doclist-index record. +** +** pData: +** Record containing the doclist-index data. +** +** bEof: +** Set to true once iterator has reached EOF. +** +** iOff: +** Set to the current offset within record pData. +*/ +struct Fts5DlidxLvl { + Fts5Data *pData; /* Data for current page of this level */ + int iOff; /* Current offset into pData */ + int bEof; /* At EOF already */ + int iFirstOff; /* Used by reverse iterators */ + + /* Output variables */ + int iLeafPgno; /* Page number of current leaf page */ + i64 iRowid; /* First rowid on leaf iLeafPgno */ +}; +struct Fts5DlidxIter { + int nLvl; + int iSegid; + Fts5DlidxLvl aLvl[1]; +}; + +static void fts5PutU16(u8 *aOut, u16 iVal){ + aOut[0] = (iVal>>8); + aOut[1] = (iVal&0xFF); +} + +static u16 fts5GetU16(const u8 *aIn){ + return ((u16)aIn[0] << 8) + aIn[1]; +} + +/* +** Allocate and return a buffer at least nByte bytes in size. +** +** If an OOM error is encountered, return NULL and set the error code in +** the Fts5Index handle passed as the first argument. +*/ +static void *fts5IdxMalloc(Fts5Index *p, int nByte){ + return sqlite3Fts5MallocZero(&p->rc, nByte); +} + +/* +** Compare the contents of the pLeft buffer with the pRight/nRight blob. +** +** Return -ve if pLeft is smaller than pRight, 0 if they are equal or +** +ve if pRight is smaller than pLeft. In other words: +** +** res = *pLeft - *pRight +*/ +#ifdef SQLITE_DEBUG +static int fts5BufferCompareBlob( + Fts5Buffer *pLeft, /* Left hand side of comparison */ + const u8 *pRight, int nRight /* Right hand side of comparison */ +){ + int nCmp = MIN(pLeft->n, nRight); + int res = memcmp(pLeft->p, pRight, nCmp); + return (res==0 ? (pLeft->n - nRight) : res); +} +#endif + +/* +** Compare the contents of the two buffers using memcmp(). If one buffer +** is a prefix of the other, it is considered the lesser. +** +** Return -ve if pLeft is smaller than pRight, 0 if they are equal or +** +ve if pRight is smaller than pLeft. In other words: +** +** res = *pLeft - *pRight +*/ +static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ + int nCmp = MIN(pLeft->n, pRight->n); + int res = memcmp(pLeft->p, pRight->p, nCmp); + return (res==0 ? (pLeft->n - pRight->n) : res); +} + +static int fts5LeafFirstTermOff(Fts5Data *pLeaf){ + int ret; + fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret); + return ret; +} + +/* +** Close the read-only blob handle, if it is open. +*/ +static void fts5CloseReader(Fts5Index *p){ + if( p->pReader ){ + sqlite3_blob *pReader = p->pReader; + p->pReader = 0; + sqlite3_blob_close(pReader); + } +} + + +/* +** Retrieve a record from the %_data table. +** +** If an error occurs, NULL is returned and an error left in the +** Fts5Index object. +*/ +static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ + Fts5Data *pRet = 0; + if( p->rc==SQLITE_OK ){ + int rc = SQLITE_OK; + + if( p->pReader ){ + /* This call may return SQLITE_ABORT if there has been a savepoint + ** rollback since it was last used. In this case a new blob handle + ** is required. */ + sqlite3_blob *pBlob = p->pReader; + p->pReader = 0; + rc = sqlite3_blob_reopen(pBlob, iRowid); + assert( p->pReader==0 ); + p->pReader = pBlob; + if( rc!=SQLITE_OK ){ + fts5CloseReader(p); + } + if( rc==SQLITE_ABORT ) rc = SQLITE_OK; + } + + /* If the blob handle is not open at this point, open it and seek + ** to the requested entry. */ + if( p->pReader==0 && rc==SQLITE_OK ){ + Fts5Config *pConfig = p->pConfig; + rc = sqlite3_blob_open(pConfig->db, + pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader + ); + } + + /* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls + ** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead. + ** All the reasons those functions might return SQLITE_ERROR - missing + ** table, missing row, non-blob/text in block column - indicate + ** backing store corruption. */ + if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; + + if( rc==SQLITE_OK ){ + u8 *aOut = 0; /* Read blob data into this buffer */ + int nByte = sqlite3_blob_bytes(p->pReader); + int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; + pRet = (Fts5Data*)sqlite3_malloc(nAlloc); + if( pRet ){ + pRet->nn = nByte; + aOut = pRet->p = (u8*)&pRet[1]; + }else{ + rc = SQLITE_NOMEM; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_blob_read(p->pReader, aOut, nByte, 0); + } + if( rc!=SQLITE_OK ){ + sqlite3_free(pRet); + pRet = 0; + }else{ + /* TODO1: Fix this */ + pRet->szLeaf = fts5GetU16(&pRet->p[2]); + } + } + p->rc = rc; + p->nRead++; + } + + assert( (pRet==0)==(p->rc!=SQLITE_OK) ); + return pRet; +} + +/* +** Release a reference to data record returned by an earlier call to +** fts5DataRead(). +*/ +static void fts5DataRelease(Fts5Data *pData){ + sqlite3_free(pData); +} + +static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ + Fts5Data *pRet = fts5DataRead(p, iRowid); + if( pRet ){ + if( pRet->szLeaf>pRet->nn ){ + p->rc = FTS5_CORRUPT; + fts5DataRelease(pRet); + pRet = 0; + } + } + return pRet; +} + +static int fts5IndexPrepareStmt( + Fts5Index *p, + sqlite3_stmt **ppStmt, + char *zSql +){ + if( p->rc==SQLITE_OK ){ + if( zSql ){ + p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0); + }else{ + p->rc = SQLITE_NOMEM; + } + } + sqlite3_free(zSql); + return p->rc; +} + + +/* +** INSERT OR REPLACE a record into the %_data table. +*/ +static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){ + if( p->rc!=SQLITE_OK ) return; + + if( p->pWriter==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf( + "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)", + pConfig->zDb, pConfig->zName + )); + if( p->rc ) return; + } + + sqlite3_bind_int64(p->pWriter, 1, iRowid); + sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC); + sqlite3_step(p->pWriter); + p->rc = sqlite3_reset(p->pWriter); +} + +/* +** Execute the following SQL: +** +** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast +*/ +static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ + if( p->rc!=SQLITE_OK ) return; + + if( p->pDeleter==0 ){ + int rc; + Fts5Config *pConfig = p->pConfig; + char *zSql = sqlite3_mprintf( + "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", + pConfig->zDb, pConfig->zName + ); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0); + sqlite3_free(zSql); + } + if( rc!=SQLITE_OK ){ + p->rc = rc; + return; + } + } + + sqlite3_bind_int64(p->pDeleter, 1, iFirst); + sqlite3_bind_int64(p->pDeleter, 2, iLast); + sqlite3_step(p->pDeleter); + p->rc = sqlite3_reset(p->pDeleter); +} + +/* +** Remove all records associated with segment iSegid. +*/ +static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){ + i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0); + i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1; + fts5DataDelete(p, iFirst, iLast); + if( p->pIdxDeleter==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlite3_mprintf( + "DELETE FROM '%q'.'%q_idx' WHERE segid=?", + pConfig->zDb, pConfig->zName + )); + } + if( p->rc==SQLITE_OK ){ + sqlite3_bind_int(p->pIdxDeleter, 1, iSegid); + sqlite3_step(p->pIdxDeleter); + p->rc = sqlite3_reset(p->pIdxDeleter); + } +} + +/* +** Release a reference to an Fts5Structure object returned by an earlier +** call to fts5StructureRead() or fts5StructureDecode(). +*/ +static void fts5StructureRelease(Fts5Structure *pStruct){ + if( pStruct && 0>=(--pStruct->nRef) ){ + int i; + assert( pStruct->nRef==0 ); + for(i=0; inLevel; i++){ + sqlite3_free(pStruct->aLevel[i].aSeg); + } + sqlite3_free(pStruct); + } +} + +static void fts5StructureRef(Fts5Structure *pStruct){ + pStruct->nRef++; +} + +/* +** Deserialize and return the structure record currently stored in serialized +** form within buffer pData/nData. +** +** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array +** are over-allocated by one slot. This allows the structure contents +** to be more easily edited. +** +** If an error occurs, *ppOut is set to NULL and an SQLite error code +** returned. Otherwise, *ppOut is set to point to the new object and +** SQLITE_OK returned. +*/ +static int fts5StructureDecode( + const u8 *pData, /* Buffer containing serialized structure */ + int nData, /* Size of buffer pData in bytes */ + int *piCookie, /* Configuration cookie value */ + Fts5Structure **ppOut /* OUT: Deserialized object */ +){ + int rc = SQLITE_OK; + int i = 0; + int iLvl; + int nLevel = 0; + int nSegment = 0; + int nByte; /* Bytes of space to allocate at pRet */ + Fts5Structure *pRet = 0; /* Structure object to return */ + + /* Grab the cookie value */ + if( piCookie ) *piCookie = sqlite3Fts5Get32(pData); + i = 4; + + /* Read the total number of levels and segments from the start of the + ** structure record. */ + i += fts5GetVarint32(&pData[i], nLevel); + i += fts5GetVarint32(&pData[i], nSegment); + nByte = ( + sizeof(Fts5Structure) + /* Main structure */ + sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ + ); + pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte); + + if( pRet ){ + pRet->nRef = 1; + pRet->nLevel = nLevel; + pRet->nSegment = nSegment; + i += sqlite3Fts5GetVarint(&pData[i], &pRet->nWriteCounter); + + for(iLvl=0; rc==SQLITE_OK && iLvlaLevel[iLvl]; + int nTotal = 0; + int iSeg; + + if( i>=nData ){ + rc = FTS5_CORRUPT; + }else{ + i += fts5GetVarint32(&pData[i], pLvl->nMerge); + i += fts5GetVarint32(&pData[i], nTotal); + assert( nTotal>=pLvl->nMerge ); + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, + nTotal * sizeof(Fts5StructureSegment) + ); + } + + if( rc==SQLITE_OK ){ + pLvl->nSeg = nTotal; + for(iSeg=0; iSeg=nData ){ + rc = FTS5_CORRUPT; + break; + } + i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid); + i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst); + i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast); + } + } + } + if( rc!=SQLITE_OK ){ + fts5StructureRelease(pRet); + pRet = 0; + } + } + + *ppOut = pRet; + return rc; +} + +/* +** +*/ +static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ + if( *pRc==SQLITE_OK ){ + Fts5Structure *pStruct = *ppStruct; + int nLevel = pStruct->nLevel; + int nByte = ( + sizeof(Fts5Structure) + /* Main structure */ + sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ + ); + + pStruct = sqlite3_realloc(pStruct, nByte); + if( pStruct ){ + memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel)); + pStruct->nLevel++; + *ppStruct = pStruct; + }else{ + *pRc = SQLITE_NOMEM; + } + } +} + +/* +** Extend level iLvl so that there is room for at least nExtra more +** segments. +*/ +static void fts5StructureExtendLevel( + int *pRc, + Fts5Structure *pStruct, + int iLvl, + int nExtra, + int bInsert +){ + if( *pRc==SQLITE_OK ){ + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + Fts5StructureSegment *aNew; + int nByte; + + nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment); + aNew = sqlite3_realloc(pLvl->aSeg, nByte); + if( aNew ){ + if( bInsert==0 ){ + memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra); + }else{ + int nMove = pLvl->nSeg * sizeof(Fts5StructureSegment); + memmove(&aNew[nExtra], aNew, nMove); + memset(aNew, 0, sizeof(Fts5StructureSegment) * nExtra); + } + pLvl->aSeg = aNew; + }else{ + *pRc = SQLITE_NOMEM; + } + } +} + +static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){ + Fts5Structure *pRet = 0; + Fts5Config *pConfig = p->pConfig; + int iCookie; /* Configuration cookie */ + Fts5Data *pData; + + pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); + if( p->rc==SQLITE_OK ){ + /* TODO: Do we need this if the leaf-index is appended? Probably... */ + memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); + p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); + if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){ + p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); + } + fts5DataRelease(pData); + if( p->rc!=SQLITE_OK ){ + fts5StructureRelease(pRet); + pRet = 0; + } + } + + return pRet; +} + +static i64 fts5IndexDataVersion(Fts5Index *p){ + i64 iVersion = 0; + + if( p->rc==SQLITE_OK ){ + if( p->pDataVersion==0 ){ + p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, + sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb) + ); + if( p->rc ) return 0; + } + + if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){ + iVersion = sqlite3_column_int64(p->pDataVersion, 0); + } + p->rc = sqlite3_reset(p->pDataVersion); + } + + return iVersion; +} + +/* +** Read, deserialize and return the structure record. +** +** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array +** are over-allocated as described for function fts5StructureDecode() +** above. +** +** If an error occurs, NULL is returned and an error code left in the +** Fts5Index handle. If an error has already occurred when this function +** is called, it is a no-op. +*/ +static Fts5Structure *fts5StructureRead(Fts5Index *p){ + + if( p->pStruct==0 ){ + p->iStructVersion = fts5IndexDataVersion(p); + if( p->rc==SQLITE_OK ){ + p->pStruct = fts5StructureReadUncached(p); + } + } + +#if 0 + else{ + Fts5Structure *pTest = fts5StructureReadUncached(p); + if( pTest ){ + int i, j; + assert_nc( p->pStruct->nSegment==pTest->nSegment ); + assert_nc( p->pStruct->nLevel==pTest->nLevel ); + for(i=0; inLevel; i++){ + assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge ); + assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg ); + for(j=0; jaLevel[i].nSeg; j++){ + Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j]; + Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j]; + assert_nc( p1->iSegid==p2->iSegid ); + assert_nc( p1->pgnoFirst==p2->pgnoFirst ); + assert_nc( p1->pgnoLast==p2->pgnoLast ); + } + } + fts5StructureRelease(pTest); + } + } +#endif + + if( p->rc!=SQLITE_OK ) return 0; + assert( p->iStructVersion!=0 ); + assert( p->pStruct!=0 ); + fts5StructureRef(p->pStruct); + return p->pStruct; +} + +static void fts5StructureInvalidate(Fts5Index *p){ + if( p->pStruct ){ + fts5StructureRelease(p->pStruct); + p->pStruct = 0; + } +} + +/* +** Return the total number of segments in index structure pStruct. This +** function is only ever used as part of assert() conditions. +*/ +#ifdef SQLITE_DEBUG +static int fts5StructureCountSegments(Fts5Structure *pStruct){ + int nSegment = 0; /* Total number of segments */ + if( pStruct ){ + int iLvl; /* Used to iterate through levels */ + for(iLvl=0; iLvlnLevel; iLvl++){ + nSegment += pStruct->aLevel[iLvl].nSeg; + } + } + + return nSegment; +} +#endif + +#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) { \ + assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) ); \ + memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob); \ + (pBuf)->n += nBlob; \ +} + +#define fts5BufferSafeAppendVarint(pBuf, iVal) { \ + (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal)); \ + assert( (pBuf)->nSpace>=(pBuf)->n ); \ +} + + +/* +** Serialize and store the "structure" record. +** +** If an error occurs, leave an error code in the Fts5Index object. If an +** error has already occurred, this function is a no-op. +*/ +static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){ + if( p->rc==SQLITE_OK ){ + Fts5Buffer buf; /* Buffer to serialize record into */ + int iLvl; /* Used to iterate through levels */ + int iCookie; /* Cookie value to store */ + + assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); + memset(&buf, 0, sizeof(Fts5Buffer)); + + /* Append the current configuration cookie */ + iCookie = p->pConfig->iCookie; + if( iCookie<0 ) iCookie = 0; + + if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){ + sqlite3Fts5Put32(buf.p, iCookie); + buf.n = 4; + fts5BufferSafeAppendVarint(&buf, pStruct->nLevel); + fts5BufferSafeAppendVarint(&buf, pStruct->nSegment); + fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter); + } + + for(iLvl=0; iLvlnLevel; iLvl++){ + int iSeg; /* Used to iterate through segments */ + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + fts5BufferAppendVarint(&p->rc, &buf, pLvl->nMerge); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->nSeg); + assert( pLvl->nMerge<=pLvl->nSeg ); + + for(iSeg=0; iSegnSeg; iSeg++){ + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast); + } + } + + fts5DataWrite(p, FTS5_STRUCTURE_ROWID, buf.p, buf.n); + fts5BufferFree(&buf); + } +} + +#if 0 +static void fts5DebugStructure(int*,Fts5Buffer*,Fts5Structure*); +static void fts5PrintStructure(const char *zCaption, Fts5Structure *pStruct){ + int rc = SQLITE_OK; + Fts5Buffer buf; + memset(&buf, 0, sizeof(buf)); + fts5DebugStructure(&rc, &buf, pStruct); + fprintf(stdout, "%s: %s\n", zCaption, buf.p); + fflush(stdout); + fts5BufferFree(&buf); +} +#else +# define fts5PrintStructure(x,y) +#endif + +static int fts5SegmentSize(Fts5StructureSegment *pSeg){ + return 1 + pSeg->pgnoLast - pSeg->pgnoFirst; +} + +/* +** Return a copy of index structure pStruct. Except, promote as many +** segments as possible to level iPromote. If an OOM occurs, NULL is +** returned. +*/ +static void fts5StructurePromoteTo( + Fts5Index *p, + int iPromote, + int szPromote, + Fts5Structure *pStruct +){ + int il, is; + Fts5StructureLevel *pOut = &pStruct->aLevel[iPromote]; + + if( pOut->nMerge==0 ){ + for(il=iPromote+1; ilnLevel; il++){ + Fts5StructureLevel *pLvl = &pStruct->aLevel[il]; + if( pLvl->nMerge ) return; + for(is=pLvl->nSeg-1; is>=0; is--){ + int sz = fts5SegmentSize(&pLvl->aSeg[is]); + if( sz>szPromote ) return; + fts5StructureExtendLevel(&p->rc, pStruct, iPromote, 1, 1); + if( p->rc ) return; + memcpy(pOut->aSeg, &pLvl->aSeg[is], sizeof(Fts5StructureSegment)); + pOut->nSeg++; + pLvl->nSeg--; + } + } + } +} + +/* +** A new segment has just been written to level iLvl of index structure +** pStruct. This function determines if any segments should be promoted +** as a result. Segments are promoted in two scenarios: +** +** a) If the segment just written is smaller than one or more segments +** within the previous populated level, it is promoted to the previous +** populated level. +** +** b) If the segment just written is larger than the newest segment on +** the next populated level, then that segment, and any other adjacent +** segments that are also smaller than the one just written, are +** promoted. +** +** If one or more segments are promoted, the structure object is updated +** to reflect this. +*/ +static void fts5StructurePromote( + Fts5Index *p, /* FTS5 backend object */ + int iLvl, /* Index level just updated */ + Fts5Structure *pStruct /* Index structure */ +){ + if( p->rc==SQLITE_OK ){ + int iTst; + int iPromote = -1; + int szPromote = 0; /* Promote anything this size or smaller */ + Fts5StructureSegment *pSeg; /* Segment just written */ + int szSeg; /* Size of segment just written */ + int nSeg = pStruct->aLevel[iLvl].nSeg; + + if( nSeg==0 ) return; + pSeg = &pStruct->aLevel[iLvl].aSeg[pStruct->aLevel[iLvl].nSeg-1]; + szSeg = (1 + pSeg->pgnoLast - pSeg->pgnoFirst); + + /* Check for condition (a) */ + for(iTst=iLvl-1; iTst>=0 && pStruct->aLevel[iTst].nSeg==0; iTst--); + if( iTst>=0 ){ + int i; + int szMax = 0; + Fts5StructureLevel *pTst = &pStruct->aLevel[iTst]; + assert( pTst->nMerge==0 ); + for(i=0; inSeg; i++){ + int sz = pTst->aSeg[i].pgnoLast - pTst->aSeg[i].pgnoFirst + 1; + if( sz>szMax ) szMax = sz; + } + if( szMax>=szSeg ){ + /* Condition (a) is true. Promote the newest segment on level + ** iLvl to level iTst. */ + iPromote = iTst; + szPromote = szMax; + } + } + + /* If condition (a) is not met, assume (b) is true. StructurePromoteTo() + ** is a no-op if it is not. */ + if( iPromote<0 ){ + iPromote = iLvl; + szPromote = szSeg; + } + fts5StructurePromoteTo(p, iPromote, szPromote, pStruct); + } +} + + +/* +** Advance the iterator passed as the only argument. If the end of the +** doclist-index page is reached, return non-zero. +*/ +static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){ + Fts5Data *pData = pLvl->pData; + + if( pLvl->iOff==0 ){ + assert( pLvl->bEof==0 ); + pLvl->iOff = 1; + pLvl->iOff += fts5GetVarint32(&pData->p[1], pLvl->iLeafPgno); + pLvl->iOff += fts5GetVarint(&pData->p[pLvl->iOff], (u64*)&pLvl->iRowid); + pLvl->iFirstOff = pLvl->iOff; + }else{ + int iOff; + for(iOff=pLvl->iOff; iOffnn; iOff++){ + if( pData->p[iOff] ) break; + } + + if( iOffnn ){ + i64 iVal; + pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1; + iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal); + pLvl->iRowid += iVal; + pLvl->iOff = iOff; + }else{ + pLvl->bEof = 1; + } + } + + return pLvl->bEof; +} + +/* +** Advance the iterator passed as the only argument. +*/ +static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){ + Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl]; + + assert( iLvlnLvl ); + if( fts5DlidxLvlNext(pLvl) ){ + if( (iLvl+1) < pIter->nLvl ){ + fts5DlidxIterNextR(p, pIter, iLvl+1); + if( pLvl[1].bEof==0 ){ + fts5DataRelease(pLvl->pData); + memset(pLvl, 0, sizeof(Fts5DlidxLvl)); + pLvl->pData = fts5DataRead(p, + FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno) + ); + if( pLvl->pData ) fts5DlidxLvlNext(pLvl); + } + } + } + + return pIter->aLvl[0].bEof; +} +static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){ + return fts5DlidxIterNextR(p, pIter, 0); +} + +/* +** The iterator passed as the first argument has the following fields set +** as follows. This function sets up the rest of the iterator so that it +** points to the first rowid in the doclist-index. +** +** pData: +** pointer to doclist-index record, +** +** When this function is called pIter->iLeafPgno is the page number the +** doclist is associated with (the one featuring the term). +*/ +static int fts5DlidxIterFirst(Fts5DlidxIter *pIter){ + int i; + for(i=0; inLvl; i++){ + fts5DlidxLvlNext(&pIter->aLvl[i]); + } + return pIter->aLvl[0].bEof; +} + + +static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){ + return p->rc!=SQLITE_OK || pIter->aLvl[0].bEof; +} + +static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){ + int i; + + /* Advance each level to the last entry on the last page */ + for(i=pIter->nLvl-1; p->rc==SQLITE_OK && i>=0; i--){ + Fts5DlidxLvl *pLvl = &pIter->aLvl[i]; + while( fts5DlidxLvlNext(pLvl)==0 ); + pLvl->bEof = 0; + + if( i>0 ){ + Fts5DlidxLvl *pChild = &pLvl[-1]; + fts5DataRelease(pChild->pData); + memset(pChild, 0, sizeof(Fts5DlidxLvl)); + pChild->pData = fts5DataRead(p, + FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno) + ); + } + } +} + +/* +** Move the iterator passed as the only argument to the previous entry. +*/ +static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){ + int iOff = pLvl->iOff; + + assert( pLvl->bEof==0 ); + if( iOff<=pLvl->iFirstOff ){ + pLvl->bEof = 1; + }else{ + u8 *a = pLvl->pData->p; + i64 iVal; + int iLimit; + int ii; + int nZero = 0; + + /* Currently iOff points to the first byte of a varint. This block + ** decrements iOff until it points to the first byte of the previous + ** varint. Taking care not to read any memory locations that occur + ** before the buffer in memory. */ + iLimit = (iOff>9 ? iOff-9 : 0); + for(iOff--; iOff>iLimit; iOff--){ + if( (a[iOff-1] & 0x80)==0 ) break; + } + + fts5GetVarint(&a[iOff], (u64*)&iVal); + pLvl->iRowid -= iVal; + pLvl->iLeafPgno--; + + /* Skip backwards past any 0x00 varints. */ + for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){ + nZero++; + } + if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){ + /* The byte immediately before the last 0x00 byte has the 0x80 bit + ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80 + ** bytes before a[ii]. */ + int bZero = 0; /* True if last 0x00 counts */ + if( (ii-8)>=pLvl->iFirstOff ){ + int j; + for(j=1; j<=8 && (a[ii-j] & 0x80); j++); + bZero = (j>8); + } + if( bZero==0 ) nZero--; + } + pLvl->iLeafPgno -= nZero; + pLvl->iOff = iOff - nZero; + } + + return pLvl->bEof; +} + +static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){ + Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl]; + + assert( iLvlnLvl ); + if( fts5DlidxLvlPrev(pLvl) ){ + if( (iLvl+1) < pIter->nLvl ){ + fts5DlidxIterPrevR(p, pIter, iLvl+1); + if( pLvl[1].bEof==0 ){ + fts5DataRelease(pLvl->pData); + memset(pLvl, 0, sizeof(Fts5DlidxLvl)); + pLvl->pData = fts5DataRead(p, + FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno) + ); + if( pLvl->pData ){ + while( fts5DlidxLvlNext(pLvl)==0 ); + pLvl->bEof = 0; + } + } + } + } + + return pIter->aLvl[0].bEof; +} +static int fts5DlidxIterPrev(Fts5Index *p, Fts5DlidxIter *pIter){ + return fts5DlidxIterPrevR(p, pIter, 0); +} + +/* +** Free a doclist-index iterator object allocated by fts5DlidxIterInit(). +*/ +static void fts5DlidxIterFree(Fts5DlidxIter *pIter){ + if( pIter ){ + int i; + for(i=0; inLvl; i++){ + fts5DataRelease(pIter->aLvl[i].pData); + } + sqlite3_free(pIter); + } +} + +static Fts5DlidxIter *fts5DlidxIterInit( + Fts5Index *p, /* Fts5 Backend to iterate within */ + int bRev, /* True for ORDER BY ASC */ + int iSegid, /* Segment id */ + int iLeafPg /* Leaf page number to load dlidx for */ +){ + Fts5DlidxIter *pIter = 0; + int i; + int bDone = 0; + + for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ + int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + Fts5DlidxIter *pNew; + + pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte); + if( pNew==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + i64 iRowid = FTS5_DLIDX_ROWID(iSegid, i, iLeafPg); + Fts5DlidxLvl *pLvl = &pNew->aLvl[i]; + pIter = pNew; + memset(pLvl, 0, sizeof(Fts5DlidxLvl)); + pLvl->pData = fts5DataRead(p, iRowid); + if( pLvl->pData && (pLvl->pData->p[0] & 0x0001)==0 ){ + bDone = 1; + } + pIter->nLvl = i+1; + } + } + + if( p->rc==SQLITE_OK ){ + pIter->iSegid = iSegid; + if( bRev==0 ){ + fts5DlidxIterFirst(pIter); + }else{ + fts5DlidxIterLast(p, pIter); + } + } + + if( p->rc!=SQLITE_OK ){ + fts5DlidxIterFree(pIter); + pIter = 0; + } + + return pIter; +} + +static i64 fts5DlidxIterRowid(Fts5DlidxIter *pIter){ + return pIter->aLvl[0].iRowid; +} +static int fts5DlidxIterPgno(Fts5DlidxIter *pIter){ + return pIter->aLvl[0].iLeafPgno; +} + +/* +** Load the next leaf page into the segment iterator. +*/ +static void fts5SegIterNextPage( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter /* Iterator to advance to next page */ +){ + Fts5Data *pLeaf; + Fts5StructureSegment *pSeg = pIter->pSeg; + fts5DataRelease(pIter->pLeaf); + pIter->iLeafPgno++; + if( pIter->pNextLeaf ){ + pIter->pLeaf = pIter->pNextLeaf; + pIter->pNextLeaf = 0; + }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){ + pIter->pLeaf = fts5LeafRead(p, + FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno) + ); + }else{ + pIter->pLeaf = 0; + } + pLeaf = pIter->pLeaf; + + if( pLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf; + if( fts5LeafIsTermless(pLeaf) ){ + pIter->iEndofDoclist = pLeaf->nn+1; + }else{ + pIter->iPgidxOff += fts5GetVarint32(&pLeaf->p[pIter->iPgidxOff], + pIter->iEndofDoclist + ); + } + } +} + +/* +** Argument p points to a buffer containing a varint to be interpreted as a +** position list size field. Read the varint and return the number of bytes +** read. Before returning, set *pnSz to the number of bytes in the position +** list, and *pbDel to true if the delete flag is set, or false otherwise. +*/ +static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){ + int nSz; + int n = 0; + fts5FastGetVarint32(p, n, nSz); + assert_nc( nSz>=0 ); + *pnSz = nSz/2; + *pbDel = nSz & 0x0001; + return n; +} + +/* +** Fts5SegIter.iLeafOffset currently points to the first byte of a +** position-list size field. Read the value of the field and store it +** in the following variables: +** +** Fts5SegIter.nPos +** Fts5SegIter.bDel +** +** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the +** position list content (if any). +*/ +static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ + if( p->rc==SQLITE_OK ){ + int iOff = pIter->iLeafOffset; /* Offset to read at */ + ASSERT_SZLEAF_OK(pIter->pLeaf); + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf); + pIter->bDel = 0; + pIter->nPos = 1; + if( iOffpLeaf->p[iOff]==0 ){ + pIter->bDel = 1; + iOff++; + if( iOffpLeaf->p[iOff]==0 ){ + pIter->nPos = 1; + iOff++; + }else{ + pIter->nPos = 0; + } + } + }else{ + int nSz; + fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz); + pIter->bDel = (nSz & 0x0001); + pIter->nPos = nSz>>1; + assert_nc( pIter->nPos>=0 ); + } + pIter->iLeafOffset = iOff; + } +} + +static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ + u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ + int iOff = pIter->iLeafOffset; + + ASSERT_SZLEAF_OK(pIter->pLeaf); + if( iOff>=pIter->pLeaf->szLeaf ){ + fts5SegIterNextPage(p, pIter); + if( pIter->pLeaf==0 ){ + if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; + return; + } + iOff = 4; + a = pIter->pLeaf->p; + } + iOff += sqlite3Fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; +} + +/* +** Fts5SegIter.iLeafOffset currently points to the first byte of the +** "nSuffix" field of a term. Function parameter nKeep contains the value +** of the "nPrefix" field (if there was one - it is passed 0 if this is +** the first term in the segment). +** +** This function populates: +** +** Fts5SegIter.term +** Fts5SegIter.rowid +** +** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of +** the first position list. The position list belonging to document +** (Fts5SegIter.iRowid). +*/ +static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ + u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ + int iOff = pIter->iLeafOffset; /* Offset to read at */ + int nNew; /* Bytes of new data */ + + iOff += fts5GetVarint32(&a[iOff], nNew); + if( iOff+nNew>pIter->pLeaf->nn ){ + p->rc = FTS5_CORRUPT; + return; + } + pIter->term.n = nKeep; + fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); + iOff += nNew; + pIter->iTermLeafOffset = iOff; + pIter->iTermLeafPgno = pIter->iLeafPgno; + pIter->iLeafOffset = iOff; + + if( pIter->iPgidxOff>=pIter->pLeaf->nn ){ + pIter->iEndofDoclist = pIter->pLeaf->nn+1; + }else{ + int nExtra; + pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], nExtra); + pIter->iEndofDoclist += nExtra; + } + + fts5SegIterLoadRowid(p, pIter); +} + +static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*); +static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*); +static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*); + +static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ + if( pIter->flags & FTS5_SEGITER_REVERSE ){ + pIter->xNext = fts5SegIterNext_Reverse; + }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + pIter->xNext = fts5SegIterNext_None; + }else{ + pIter->xNext = fts5SegIterNext; + } +} + +/* +** Initialize the iterator object pIter to iterate through the entries in +** segment pSeg. The iterator is left pointing to the first entry when +** this function returns. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** an error has already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterInit( + Fts5Index *p, /* FTS index object */ + Fts5StructureSegment *pSeg, /* Description of segment */ + Fts5SegIter *pIter /* Object to populate */ +){ + if( pSeg->pgnoFirst==0 ){ + /* This happens if the segment is being used as an input to an incremental + ** merge and all data has already been "trimmed". See function + ** fts5TrimSegments() for details. In this case leave the iterator empty. + ** The caller will see the (pIter->pLeaf==0) and assume the iterator is + ** at EOF already. */ + assert( pIter->pLeaf==0 ); + return; + } + + if( p->rc==SQLITE_OK ){ + memset(pIter, 0, sizeof(*pIter)); + fts5SegIterSetNext(p, pIter); + pIter->pSeg = pSeg; + pIter->iLeafPgno = pSeg->pgnoFirst-1; + fts5SegIterNextPage(p, pIter); + } + + if( p->rc==SQLITE_OK ){ + pIter->iLeafOffset = 4; + assert_nc( pIter->pLeaf->nn>4 ); + assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); + pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; + fts5SegIterLoadTerm(p, pIter, 0); + fts5SegIterLoadNPos(p, pIter); + } +} + +/* +** This function is only ever called on iterators created by calls to +** Fts5IndexQuery() with the FTS5INDEX_QUERY_DESC flag set. +** +** The iterator is in an unusual state when this function is called: the +** Fts5SegIter.iLeafOffset variable is set to the offset of the start of +** the position-list size field for the first relevant rowid on the page. +** Fts5SegIter.rowid is set, but nPos and bDel are not. +** +** This function advances the iterator so that it points to the last +** relevant rowid on the page and, if necessary, initializes the +** aRowidOffset[] and iRowidOffset variables. At this point the iterator +** is in its regular state - Fts5SegIter.iLeafOffset points to the first +** byte of the position list content associated with said rowid. +*/ +static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ + int eDetail = p->pConfig->eDetail; + int n = pIter->pLeaf->szLeaf; + int i = pIter->iLeafOffset; + u8 *a = pIter->pLeaf->p; + int iRowidOffset = 0; + + if( n>pIter->iEndofDoclist ){ + n = pIter->iEndofDoclist; + } + + ASSERT_SZLEAF_OK(pIter->pLeaf); + while( 1 ){ + i64 iDelta = 0; + + if( eDetail==FTS5_DETAIL_NONE ){ + /* todo */ + if( i=n ) break; + i += fts5GetVarint(&a[i], (u64*)&iDelta); + pIter->iRowid += iDelta; + + /* If necessary, grow the pIter->aRowidOffset[] array. */ + if( iRowidOffset>=pIter->nRowidOffset ){ + int nNew = pIter->nRowidOffset + 8; + int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int)); + if( aNew==0 ){ + p->rc = SQLITE_NOMEM; + break; + } + pIter->aRowidOffset = aNew; + pIter->nRowidOffset = nNew; + } + + pIter->aRowidOffset[iRowidOffset++] = pIter->iLeafOffset; + pIter->iLeafOffset = i; + } + pIter->iRowidOffset = iRowidOffset; + fts5SegIterLoadNPos(p, pIter); +} + +/* +** +*/ +static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ + assert( pIter->flags & FTS5_SEGITER_REVERSE ); + assert( pIter->flags & FTS5_SEGITER_ONETERM ); + + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){ + Fts5Data *pNew; + pIter->iLeafPgno--; + pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID( + pIter->pSeg->iSegid, pIter->iLeafPgno + )); + if( pNew ){ + /* iTermLeafOffset may be equal to szLeaf if the term is the last + ** thing on the page - i.e. the first rowid is on the following page. + ** In this case leave pIter->pLeaf==0, this iterator is at EOF. */ + if( pIter->iLeafPgno==pIter->iTermLeafPgno ){ + assert( pIter->pLeaf==0 ); + if( pIter->iTermLeafOffsetszLeaf ){ + pIter->pLeaf = pNew; + pIter->iLeafOffset = pIter->iTermLeafOffset; + } + }else{ + int iRowidOff; + iRowidOff = fts5LeafFirstRowidOff(pNew); + if( iRowidOff ){ + pIter->pLeaf = pNew; + pIter->iLeafOffset = iRowidOff; + } + } + + if( pIter->pLeaf ){ + u8 *a = &pIter->pLeaf->p[pIter->iLeafOffset]; + pIter->iLeafOffset += fts5GetVarint(a, (u64*)&pIter->iRowid); + break; + }else{ + fts5DataRelease(pNew); + } + } + } + + if( pIter->pLeaf ){ + pIter->iEndofDoclist = pIter->pLeaf->nn+1; + fts5SegIterReverseInitPage(p, pIter); + } +} + +/* +** Return true if the iterator passed as the second argument currently +** points to a delete marker. A delete marker is an entry with a 0 byte +** position-list. +*/ +static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){ + Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; + return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0); +} + +/* +** Advance iterator pIter to the next entry. +** +** This version of fts5SegIterNext() is only used by reverse iterators. +*/ +static void fts5SegIterNext_Reverse( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbUnused /* Unused */ +){ + assert( pIter->flags & FTS5_SEGITER_REVERSE ); + assert( pIter->pNextLeaf==0 ); + UNUSED_PARAM(pbUnused); + + if( pIter->iRowidOffset>0 ){ + u8 *a = pIter->pLeaf->p; + int iOff; + i64 iDelta; + + pIter->iRowidOffset--; + pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; + fts5SegIterLoadNPos(p, pIter); + iOff = pIter->iLeafOffset; + if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ + iOff += pIter->nPos; + } + fts5GetVarint(&a[iOff], (u64*)&iDelta); + pIter->iRowid -= iDelta; + }else{ + fts5SegIterReverseNewPage(p, pIter); + } +} + +/* +** Advance iterator pIter to the next entry. +** +** This version of fts5SegIterNext() is only used if detail=none and the +** iterator is not a reverse direction iterator. +*/ +static void fts5SegIterNext_None( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbNewTerm /* OUT: Set for new term */ +){ + int iOff; + + assert( p->rc==SQLITE_OK ); + assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 ); + assert( p->pConfig->eDetail==FTS5_DETAIL_NONE ); + + ASSERT_SZLEAF_OK(pIter->pLeaf); + iOff = pIter->iLeafOffset; + + /* Next entry is on the next page */ + if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ + fts5SegIterNextPage(p, pIter); + if( p->rc || pIter->pLeaf==0 ) return; + pIter->iRowid = 0; + iOff = 4; + } + + if( iOffiEndofDoclist ){ + /* Next entry is on the current page */ + i64 iDelta; + iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta); + pIter->iLeafOffset = iOff; + pIter->iRowid += iDelta; + }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){ + if( pIter->pSeg ){ + int nKeep = 0; + if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){ + iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep); + } + pIter->iLeafOffset = iOff; + fts5SegIterLoadTerm(p, pIter, nKeep); + }else{ + const u8 *pList = 0; + const char *zTerm = 0; + int nList; + sqlite3Fts5HashScanNext(p->pHash); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); + if( pList==0 ) goto next_none_eof; + pIter->pLeaf->p = (u8*)pList; + pIter->pLeaf->nn = nList; + pIter->pLeaf->szLeaf = nList; + pIter->iEndofDoclist = nList; + sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); + } + + if( pbNewTerm ) *pbNewTerm = 1; + }else{ + goto next_none_eof; + } + + fts5SegIterLoadNPos(p, pIter); + + return; + next_none_eof: + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; +} + + +/* +** Advance iterator pIter to the next entry. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. It +** is not considered an error if the iterator reaches EOF. If an error has +** already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterNext( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbNewTerm /* OUT: Set for new term */ +){ + Fts5Data *pLeaf = pIter->pLeaf; + int iOff; + int bNewTerm = 0; + int nKeep = 0; + u8 *a; + int n; + + assert( pbNewTerm==0 || *pbNewTerm==0 ); + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); + + /* Search for the end of the position list within the current page. */ + a = pLeaf->p; + n = pLeaf->szLeaf; + + ASSERT_SZLEAF_OK(pLeaf); + iOff = pIter->iLeafOffset + pIter->nPos; + + if( iOffiEndofDoclist ); + if( iOff>=pIter->iEndofDoclist ){ + bNewTerm = 1; + if( iOff!=fts5LeafFirstTermOff(pLeaf) ){ + iOff += fts5GetVarint32(&a[iOff], nKeep); + } + }else{ + u64 iDelta; + iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta); + pIter->iRowid += iDelta; + assert_nc( iDelta>0 ); + } + pIter->iLeafOffset = iOff; + + }else if( pIter->pSeg==0 ){ + const u8 *pList = 0; + const char *zTerm = 0; + int nList = 0; + assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); + if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ + sqlite3Fts5HashScanNext(p->pHash); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); + } + if( pList==0 ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + }else{ + pIter->pLeaf->p = (u8*)pList; + pIter->pLeaf->nn = nList; + pIter->pLeaf->szLeaf = nList; + pIter->iEndofDoclist = nList+1; + sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), + (u8*)zTerm); + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); + *pbNewTerm = 1; + } + }else{ + iOff = 0; + /* Next entry is not on the current page */ + while( iOff==0 ){ + fts5SegIterNextPage(p, pIter); + pLeaf = pIter->pLeaf; + if( pLeaf==0 ) break; + ASSERT_SZLEAF_OK(pLeaf); + if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOffszLeaf ){ + iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + + if( pLeaf->nn>pLeaf->szLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( + &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist + ); + } + } + else if( pLeaf->nn>pLeaf->szLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( + &pLeaf->p[pLeaf->szLeaf], iOff + ); + pIter->iLeafOffset = iOff; + pIter->iEndofDoclist = iOff; + bNewTerm = 1; + } + assert_nc( iOffszLeaf ); + if( iOff>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } + } + } + + /* Check if the iterator is now at EOF. If so, return early. */ + if( pIter->pLeaf ){ + if( bNewTerm ){ + if( pIter->flags & FTS5_SEGITER_ONETERM ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + }else{ + fts5SegIterLoadTerm(p, pIter, nKeep); + fts5SegIterLoadNPos(p, pIter); + if( pbNewTerm ) *pbNewTerm = 1; + } + }else{ + /* The following could be done by calling fts5SegIterLoadNPos(). But + ** this block is particularly performance critical, so equivalent + ** code is inlined. + ** + ** Later: Switched back to fts5SegIterLoadNPos() because it supports + ** detail=none mode. Not ideal. + */ + int nSz; + assert( p->rc==SQLITE_OK ); + fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); + pIter->bDel = (nSz & 0x0001); + pIter->nPos = nSz>>1; + assert_nc( pIter->nPos>=0 ); + } + } +} + +#define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; } + +#define fts5IndexSkipVarint(a, iOff) { \ + int iEnd = iOff+9; \ + while( (a[iOff++] & 0x80) && iOffpDlidx; + Fts5Data *pLast = 0; + int pgnoLast = 0; + + if( pDlidx ){ + int iSegid = pIter->pSeg->iSegid; + pgnoLast = fts5DlidxIterPgno(pDlidx); + pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); + }else{ + Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ + + /* Currently, Fts5SegIter.iLeafOffset points to the first byte of + ** position-list content for the current rowid. Back it up so that it + ** points to the start of the position-list size field. */ + int iPoslist; + if( pIter->iTermLeafPgno==pIter->iLeafPgno ){ + iPoslist = pIter->iTermLeafOffset; + }else{ + iPoslist = 4; + } + fts5IndexSkipVarint(pLeaf->p, iPoslist); + pIter->iLeafOffset = iPoslist; + + /* If this condition is true then the largest rowid for the current + ** term may not be stored on the current page. So search forward to + ** see where said rowid really is. */ + if( pIter->iEndofDoclist>=pLeaf->szLeaf ){ + int pgno; + Fts5StructureSegment *pSeg = pIter->pSeg; + + /* The last rowid in the doclist may not be on the current page. Search + ** forward to find the page containing the last rowid. */ + for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){ + i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); + Fts5Data *pNew = fts5DataRead(p, iAbs); + if( pNew ){ + int iRowid, bTermless; + iRowid = fts5LeafFirstRowidOff(pNew); + bTermless = fts5LeafIsTermless(pNew); + if( iRowid ){ + SWAPVAL(Fts5Data*, pNew, pLast); + pgnoLast = pgno; + } + fts5DataRelease(pNew); + if( bTermless==0 ) break; + } + } + } + } + + /* If pLast is NULL at this point, then the last rowid for this doclist + ** lies on the page currently indicated by the iterator. In this case + ** pIter->iLeafOffset is already set to point to the position-list size + ** field associated with the first relevant rowid on the page. + ** + ** Or, if pLast is non-NULL, then it is the page that contains the last + ** rowid. In this case configure the iterator so that it points to the + ** first rowid on this page. + */ + if( pLast ){ + int iOff; + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = pLast; + pIter->iLeafPgno = pgnoLast; + iOff = fts5LeafFirstRowidOff(pLast); + iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + + if( fts5LeafIsTermless(pLast) ){ + pIter->iEndofDoclist = pLast->nn+1; + }else{ + pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); + } + + } + + fts5SegIterReverseInitPage(p, pIter); +} + +/* +** Iterator pIter currently points to the first rowid of a doclist. +** There is a doclist-index associated with the final term on the current +** page. If the current term is the last term on the page, load the +** doclist-index from disk and initialize an iterator at (pIter->pDlidx). +*/ +static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){ + int iSeg = pIter->pSeg->iSegid; + int bRev = (pIter->flags & FTS5_SEGITER_REVERSE); + Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ + + assert( pIter->flags & FTS5_SEGITER_ONETERM ); + assert( pIter->pDlidx==0 ); + + /* Check if the current doclist ends on this page. If it does, return + ** early without loading the doclist-index (as it belongs to a different + ** term. */ + if( pIter->iTermLeafPgno==pIter->iLeafPgno + && pIter->iEndofDoclistszLeaf + ){ + return; + } + + pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno); +} + +/* +** The iterator object passed as the second argument currently contains +** no valid values except for the Fts5SegIter.pLeaf member variable. This +** function searches the leaf page for a term matching (pTerm/nTerm). +** +** If the specified term is found on the page, then the iterator is left +** pointing to it. If argument bGe is zero and the term is not found, +** the iterator is left pointing at EOF. +** +** If bGe is non-zero and the specified term is not found, then the +** iterator is left pointing to the smallest term in the segment that +** is larger than the specified term, even if this term is not on the +** current page. +*/ +static void fts5LeafSeek( + Fts5Index *p, /* Leave any error code here */ + int bGe, /* True for a >= search */ + Fts5SegIter *pIter, /* Iterator to seek */ + const u8 *pTerm, int nTerm /* Term to search for */ +){ + int iOff; + const u8 *a = pIter->pLeaf->p; + int szLeaf = pIter->pLeaf->szLeaf; + int n = pIter->pLeaf->nn; + + int nMatch = 0; + int nKeep = 0; + int nNew = 0; + int iTermOff; + int iPgidx; /* Current offset in pgidx */ + int bEndOfPage = 0; + + assert( p->rc==SQLITE_OK ); + + iPgidx = szLeaf; + iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); + iOff = iTermOff; + if( iOff>n ){ + p->rc = FTS5_CORRUPT; + return; + } + + while( 1 ){ + + /* Figure out how many new bytes are in this term */ + fts5FastGetVarint32(a, iOff, nNew); + if( nKeep=nMatch ); + if( nKeep==nMatch ){ + int nCmp; + int i; + nCmp = MIN(nNew, nTerm-nMatch); + for(i=0; ipTerm[nMatch] ){ + goto search_failed; + } + } + + if( iPgidx>=n ){ + bEndOfPage = 1; + break; + } + + iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); + iTermOff += nKeep; + iOff = iTermOff; + + if( iOff>=n ){ + p->rc = FTS5_CORRUPT; + return; + } + + /* Read the nKeep field of the next term. */ + fts5FastGetVarint32(a, iOff, nKeep); + } + + search_failed: + if( bGe==0 ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + return; + }else if( bEndOfPage ){ + do { + fts5SegIterNextPage(p, pIter); + if( pIter->pLeaf==0 ) return; + a = pIter->pLeaf->p; + if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ + iPgidx = pIter->pLeaf->szLeaf; + iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); + if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + nKeep = 0; + iTermOff = iOff; + n = pIter->pLeaf->nn; + iOff += fts5GetVarint32(&a[iOff], nNew); + break; + } + } + }while( 1 ); + } + + search_success: + + pIter->iLeafOffset = iOff + nNew; + pIter->iTermLeafOffset = pIter->iLeafOffset; + pIter->iTermLeafPgno = pIter->iLeafPgno; + + fts5BufferSet(&p->rc, &pIter->term, nKeep, pTerm); + fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); + + if( iPgidx>=n ){ + pIter->iEndofDoclist = pIter->pLeaf->nn+1; + }else{ + int nExtra; + iPgidx += fts5GetVarint32(&a[iPgidx], nExtra); + pIter->iEndofDoclist = iTermOff + nExtra; + } + pIter->iPgidxOff = iPgidx; + + fts5SegIterLoadRowid(p, pIter); + fts5SegIterLoadNPos(p, pIter); +} + +static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){ + if( p->pIdxSelect==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf( + "SELECT pgno FROM '%q'.'%q_idx' WHERE " + "segid=? AND term<=? ORDER BY term DESC LIMIT 1", + pConfig->zDb, pConfig->zName + )); + } + return p->pIdxSelect; +} + +/* +** Initialize the object pIter to point to term pTerm/nTerm within segment +** pSeg. If there is no such term in the index, the iterator is set to EOF. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** an error has already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterSeekInit( + Fts5Index *p, /* FTS5 backend */ + const u8 *pTerm, int nTerm, /* Term to seek to */ + int flags, /* Mask of FTS5INDEX_XXX flags */ + Fts5StructureSegment *pSeg, /* Description of segment */ + Fts5SegIter *pIter /* Object to populate */ +){ + int iPg = 1; + int bGe = (flags & FTS5INDEX_QUERY_SCAN); + int bDlidx = 0; /* True if there is a doclist-index */ + sqlite3_stmt *pIdxSelect = 0; + + assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 ); + assert( pTerm && nTerm ); + memset(pIter, 0, sizeof(*pIter)); + pIter->pSeg = pSeg; + + /* This block sets stack variable iPg to the leaf page number that may + ** contain term (pTerm/nTerm), if it is present in the segment. */ + pIdxSelect = fts5IdxSelectStmt(p); + if( p->rc ) return; + sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid); + sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){ + i64 val = sqlite3_column_int(pIdxSelect, 0); + iPg = (int)(val>>1); + bDlidx = (val & 0x0001); + } + p->rc = sqlite3_reset(pIdxSelect); + + if( iPgpgnoFirst ){ + iPg = pSeg->pgnoFirst; + bDlidx = 0; + } + + pIter->iLeafPgno = iPg - 1; + fts5SegIterNextPage(p, pIter); + + if( pIter->pLeaf ){ + fts5LeafSeek(p, bGe, pIter, pTerm, nTerm); + } + + if( p->rc==SQLITE_OK && bGe==0 ){ + pIter->flags |= FTS5_SEGITER_ONETERM; + if( pIter->pLeaf ){ + if( flags & FTS5INDEX_QUERY_DESC ){ + pIter->flags |= FTS5_SEGITER_REVERSE; + } + if( bDlidx ){ + fts5SegIterLoadDlidx(p, pIter); + } + if( flags & FTS5INDEX_QUERY_DESC ){ + fts5SegIterReverse(p, pIter); + } + } + } + + fts5SegIterSetNext(p, pIter); + + /* Either: + ** + ** 1) an error has occurred, or + ** 2) the iterator points to EOF, or + ** 3) the iterator points to an entry with term (pTerm/nTerm), or + ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points + ** to an entry with a term greater than or equal to (pTerm/nTerm). + */ + assert( p->rc!=SQLITE_OK /* 1 */ + || pIter->pLeaf==0 /* 2 */ + || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ + || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ + ); +} + +/* +** Initialize the object pIter to point to term pTerm/nTerm within the +** in-memory hash table. If there is no such term in the hash-table, the +** iterator is set to EOF. +** +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** an error has already occurred when this function is called, it is a no-op. +*/ +static void fts5SegIterHashInit( + Fts5Index *p, /* FTS5 backend */ + const u8 *pTerm, int nTerm, /* Term to seek to */ + int flags, /* Mask of FTS5INDEX_XXX flags */ + Fts5SegIter *pIter /* Object to populate */ +){ + const u8 *pList = 0; + int nList = 0; + const u8 *z = 0; + int n = 0; + + assert( p->pHash ); + assert( p->rc==SQLITE_OK ); + + if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ + p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); + sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); + n = (z ? (int)strlen((const char*)z) : 0); + }else{ + pIter->flags |= FTS5_SEGITER_ONETERM; + sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList); + z = pTerm; + n = nTerm; + } + + if( pList ){ + Fts5Data *pLeaf; + sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); + pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); + if( pLeaf==0 ) return; + pLeaf->p = (u8*)pList; + pLeaf->nn = pLeaf->szLeaf = nList; + pIter->pLeaf = pLeaf; + pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); + pIter->iEndofDoclist = pLeaf->nn; + + if( flags & FTS5INDEX_QUERY_DESC ){ + pIter->flags |= FTS5_SEGITER_REVERSE; + fts5SegIterReverseInitPage(p, pIter); + }else{ + fts5SegIterLoadNPos(p, pIter); + } + } + + fts5SegIterSetNext(p, pIter); +} + +/* +** Zero the iterator passed as the only argument. +*/ +static void fts5SegIterClear(Fts5SegIter *pIter){ + fts5BufferFree(&pIter->term); + fts5DataRelease(pIter->pLeaf); + fts5DataRelease(pIter->pNextLeaf); + fts5DlidxIterFree(pIter->pDlidx); + sqlite3_free(pIter->aRowidOffset); + memset(pIter, 0, sizeof(Fts5SegIter)); +} + +#ifdef SQLITE_DEBUG + +/* +** This function is used as part of the big assert() procedure implemented by +** fts5AssertMultiIterSetup(). It ensures that the result currently stored +** in *pRes is the correct result of comparing the current positions of the +** two iterators. +*/ +static void fts5AssertComparisonResult( + Fts5Iter *pIter, + Fts5SegIter *p1, + Fts5SegIter *p2, + Fts5CResult *pRes +){ + int i1 = p1 - pIter->aSeg; + int i2 = p2 - pIter->aSeg; + + if( p1->pLeaf || p2->pLeaf ){ + if( p1->pLeaf==0 ){ + assert( pRes->iFirst==i2 ); + }else if( p2->pLeaf==0 ){ + assert( pRes->iFirst==i1 ); + }else{ + int nMin = MIN(p1->term.n, p2->term.n); + int res = memcmp(p1->term.p, p2->term.p, nMin); + if( res==0 ) res = p1->term.n - p2->term.n; + + if( res==0 ){ + assert( pRes->bTermEq==1 ); + assert( p1->iRowid!=p2->iRowid ); + res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : 1; + }else{ + assert( pRes->bTermEq==0 ); + } + + if( res<0 ){ + assert( pRes->iFirst==i1 ); + }else{ + assert( pRes->iFirst==i2 ); + } + } + } +} + +/* +** This function is a no-op unless SQLITE_DEBUG is defined when this module +** is compiled. In that case, this function is essentially an assert() +** statement used to verify that the contents of the pIter->aFirst[] array +** are correct. +*/ +static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){ + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + int i; + + assert( (pFirst->pLeaf==0)==pIter->base.bEof ); + + /* Check that pIter->iSwitchRowid is set correctly. */ + for(i=0; inSeg; i++){ + Fts5SegIter *p1 = &pIter->aSeg[i]; + assert( p1==pFirst + || p1->pLeaf==0 + || fts5BufferCompare(&pFirst->term, &p1->term) + || p1->iRowid==pIter->iSwitchRowid + || (p1->iRowidiSwitchRowid)==pIter->bRev + ); + } + + for(i=0; inSeg; i+=2){ + Fts5SegIter *p1 = &pIter->aSeg[i]; + Fts5SegIter *p2 = &pIter->aSeg[i+1]; + Fts5CResult *pRes = &pIter->aFirst[(pIter->nSeg + i) / 2]; + fts5AssertComparisonResult(pIter, p1, p2, pRes); + } + + for(i=1; i<(pIter->nSeg / 2); i+=2){ + Fts5SegIter *p1 = &pIter->aSeg[ pIter->aFirst[i*2].iFirst ]; + Fts5SegIter *p2 = &pIter->aSeg[ pIter->aFirst[i*2+1].iFirst ]; + Fts5CResult *pRes = &pIter->aFirst[i]; + fts5AssertComparisonResult(pIter, p1, p2, pRes); + } + } +} +#else +# define fts5AssertMultiIterSetup(x,y) +#endif + +/* +** Do the comparison necessary to populate pIter->aFirst[iOut]. +** +** If the returned value is non-zero, then it is the index of an entry +** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing +** to a key that is a duplicate of another, higher priority, +** segment-iterator in the pSeg->aSeg[] array. +*/ +static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ + int i1; /* Index of left-hand Fts5SegIter */ + int i2; /* Index of right-hand Fts5SegIter */ + int iRes; + Fts5SegIter *p1; /* Left-hand Fts5SegIter */ + Fts5SegIter *p2; /* Right-hand Fts5SegIter */ + Fts5CResult *pRes = &pIter->aFirst[iOut]; + + assert( iOutnSeg && iOut>0 ); + assert( pIter->bRev==0 || pIter->bRev==1 ); + + if( iOut>=(pIter->nSeg/2) ){ + i1 = (iOut - pIter->nSeg/2) * 2; + i2 = i1 + 1; + }else{ + i1 = pIter->aFirst[iOut*2].iFirst; + i2 = pIter->aFirst[iOut*2+1].iFirst; + } + p1 = &pIter->aSeg[i1]; + p2 = &pIter->aSeg[i2]; + + pRes->bTermEq = 0; + if( p1->pLeaf==0 ){ /* If p1 is at EOF */ + iRes = i2; + }else if( p2->pLeaf==0 ){ /* If p2 is at EOF */ + iRes = i1; + }else{ + int res = fts5BufferCompare(&p1->term, &p2->term); + if( res==0 ){ + assert( i2>i1 ); + assert( i2!=0 ); + pRes->bTermEq = 1; + if( p1->iRowid==p2->iRowid ){ + p1->bDel = p2->bDel; + return i2; + } + res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1; + } + assert( res!=0 ); + if( res<0 ){ + iRes = i1; + }else{ + iRes = i2; + } + } + + pRes->iFirst = (u16)iRes; + return 0; +} + +/* +** Move the seg-iter so that it points to the first rowid on page iLeafPgno. +** It is an error if leaf iLeafPgno does not exist or contains no rowids. +*/ +static void fts5SegIterGotoPage( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int iLeafPgno +){ + assert( iLeafPgno>pIter->iLeafPgno ); + + if( iLeafPgno>pIter->pSeg->pgnoLast ){ + p->rc = FTS5_CORRUPT; + }else{ + fts5DataRelease(pIter->pNextLeaf); + pIter->pNextLeaf = 0; + pIter->iLeafPgno = iLeafPgno-1; + fts5SegIterNextPage(p, pIter); + assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); + + if( p->rc==SQLITE_OK ){ + int iOff; + u8 *a = pIter->pLeaf->p; + int n = pIter->pLeaf->szLeaf; + + iOff = fts5LeafFirstRowidOff(pIter->pLeaf); + if( iOff<4 || iOff>=n ){ + p->rc = FTS5_CORRUPT; + }else{ + iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + fts5SegIterLoadNPos(p, pIter); + } + } + } +} + +/* +** Advance the iterator passed as the second argument until it is at or +** past rowid iFrom. Regardless of the value of iFrom, the iterator is +** always advanced at least once. +*/ +static void fts5SegIterNextFrom( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + i64 iMatch /* Advance iterator at least this far */ +){ + int bRev = (pIter->flags & FTS5_SEGITER_REVERSE); + Fts5DlidxIter *pDlidx = pIter->pDlidx; + int iLeafPgno = pIter->iLeafPgno; + int bMove = 1; + + assert( pIter->flags & FTS5_SEGITER_ONETERM ); + assert( pIter->pDlidx ); + assert( pIter->pLeaf ); + + if( bRev==0 ){ + while( !fts5DlidxIterEof(p, pDlidx) && iMatch>fts5DlidxIterRowid(pDlidx) ){ + iLeafPgno = fts5DlidxIterPgno(pDlidx); + fts5DlidxIterNext(p, pDlidx); + } + assert_nc( iLeafPgno>=pIter->iLeafPgno || p->rc ); + if( iLeafPgno>pIter->iLeafPgno ){ + fts5SegIterGotoPage(p, pIter, iLeafPgno); + bMove = 0; + } + }else{ + assert( pIter->pNextLeaf==0 ); + assert( iMatchiRowid ); + while( !fts5DlidxIterEof(p, pDlidx) && iMatchiLeafPgno ); + + if( iLeafPgnoiLeafPgno ){ + pIter->iLeafPgno = iLeafPgno+1; + fts5SegIterReverseNewPage(p, pIter); + bMove = 0; + } + } + + do{ + if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0); + if( pIter->pLeaf==0 ) break; + if( bRev==0 && pIter->iRowid>=iMatch ) break; + if( bRev!=0 && pIter->iRowid<=iMatch ) break; + bMove = 1; + }while( p->rc==SQLITE_OK ); +} + + +/* +** Free the iterator object passed as the second argument. +*/ +static void fts5MultiIterFree(Fts5Iter *pIter){ + if( pIter ){ + int i; + for(i=0; inSeg; i++){ + fts5SegIterClear(&pIter->aSeg[i]); + } + fts5StructureRelease(pIter->pStruct); + fts5BufferFree(&pIter->poslist); + sqlite3_free(pIter); + } +} + +static void fts5MultiIterAdvanced( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ + int iChanged, /* Index of sub-iterator just advanced */ + int iMinset /* Minimum entry in aFirst[] to set */ +){ + int i; + for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){ + Fts5SegIter *pSeg = &pIter->aSeg[iEq]; + assert( p->rc==SQLITE_OK ); + pSeg->xNext(p, pSeg, 0); + i = pIter->nSeg + iEq; + } + } +} + +/* +** Sub-iterator iChanged of iterator pIter has just been advanced. It still +** points to the same term though - just a different rowid. This function +** attempts to update the contents of the pIter->aFirst[] accordingly. +** If it does so successfully, 0 is returned. Otherwise 1. +** +** If non-zero is returned, the caller should call fts5MultiIterAdvanced() +** on the iterator instead. That function does the same as this one, except +** that it deals with more complicated cases as well. +*/ +static int fts5MultiIterAdvanceRowid( + Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ + int iChanged, /* Index of sub-iterator just advanced */ + Fts5SegIter **ppFirst +){ + Fts5SegIter *pNew = &pIter->aSeg[iChanged]; + + if( pNew->iRowid==pIter->iSwitchRowid + || (pNew->iRowidiSwitchRowid)==pIter->bRev + ){ + int i; + Fts5SegIter *pOther = &pIter->aSeg[iChanged ^ 0x0001]; + pIter->iSwitchRowid = pIter->bRev ? SMALLEST_INT64 : LARGEST_INT64; + for(i=(pIter->nSeg+iChanged)/2; 1; i=i/2){ + Fts5CResult *pRes = &pIter->aFirst[i]; + + assert( pNew->pLeaf ); + assert( pRes->bTermEq==0 || pOther->pLeaf ); + + if( pRes->bTermEq ){ + if( pNew->iRowid==pOther->iRowid ){ + return 1; + }else if( (pOther->iRowid>pNew->iRowid)==pIter->bRev ){ + pIter->iSwitchRowid = pOther->iRowid; + pNew = pOther; + }else if( (pOther->iRowid>pIter->iSwitchRowid)==pIter->bRev ){ + pIter->iSwitchRowid = pOther->iRowid; + } + } + pRes->iFirst = (u16)(pNew - pIter->aSeg); + if( i==1 ) break; + + pOther = &pIter->aSeg[ pIter->aFirst[i ^ 0x0001].iFirst ]; + } + } + + *ppFirst = pNew; + return 0; +} + +/* +** Set the pIter->bEof variable based on the state of the sub-iterators. +*/ +static void fts5MultiIterSetEof(Fts5Iter *pIter){ + Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + pIter->base.bEof = pSeg->pLeaf==0; + pIter->iSwitchRowid = pSeg->iRowid; +} + +/* +** Move the iterator to the next entry. +** +** If an error occurs, an error code is left in Fts5Index.rc. It is not +** considered an error if the iterator reaches EOF, or if it is already at +** EOF when this function is called. +*/ +static void fts5MultiIterNext( + Fts5Index *p, + Fts5Iter *pIter, + int bFrom, /* True if argument iFrom is valid */ + i64 iFrom /* Advance at least as far as this */ +){ + int bUseFrom = bFrom; + assert( pIter->base.bEof==0 ); + while( p->rc==SQLITE_OK ){ + int iFirst = pIter->aFirst[1].iFirst; + int bNewTerm = 0; + Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; + assert( p->rc==SQLITE_OK ); + if( bUseFrom && pSeg->pDlidx ){ + fts5SegIterNextFrom(p, pSeg, iFrom); + }else{ + pSeg->xNext(p, pSeg, &bNewTerm); + } + + if( pSeg->pLeaf==0 || bNewTerm + || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) + ){ + fts5MultiIterAdvanced(p, pIter, iFirst, 1); + fts5MultiIterSetEof(pIter); + pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; + if( pSeg->pLeaf==0 ) return; + } + + fts5AssertMultiIterSetup(p, pIter); + assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf ); + if( pIter->bSkipEmpty==0 || pSeg->nPos ){ + pIter->xSetOutputs(pIter, pSeg); + return; + } + bUseFrom = 0; + } +} + +static void fts5MultiIterNext2( + Fts5Index *p, + Fts5Iter *pIter, + int *pbNewTerm /* OUT: True if *might* be new term */ +){ + assert( pIter->bSkipEmpty ); + if( p->rc==SQLITE_OK ){ + do { + int iFirst = pIter->aFirst[1].iFirst; + Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; + int bNewTerm = 0; + + assert( p->rc==SQLITE_OK ); + pSeg->xNext(p, pSeg, &bNewTerm); + if( pSeg->pLeaf==0 || bNewTerm + || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) + ){ + fts5MultiIterAdvanced(p, pIter, iFirst, 1); + fts5MultiIterSetEof(pIter); + *pbNewTerm = 1; + }else{ + *pbNewTerm = 0; + } + fts5AssertMultiIterSetup(p, pIter); + + }while( fts5MultiIterIsEmpty(p, pIter) ); + } +} + +static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){ + UNUSED_PARAM2(pUnused1, pUnused2); +} + +static Fts5Iter *fts5MultiIterAlloc( + Fts5Index *p, /* FTS5 backend to iterate within */ + int nSeg +){ + Fts5Iter *pNew; + int nSlot; /* Power of two >= nSeg */ + + for(nSlot=2; nSlotaSeg[] */ + sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ + ); + if( pNew ){ + pNew->nSeg = nSlot; + pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot]; + pNew->pIndex = p; + pNew->xSetOutputs = fts5IterSetOutputs_Noop; + } + return pNew; +} + +static void fts5PoslistCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk); + } +} + +typedef struct PoslistCallbackCtx PoslistCallbackCtx; +struct PoslistCallbackCtx { + Fts5Buffer *pBuf; /* Append to this buffer */ + Fts5Colset *pColset; /* Restrict matches to this column */ + int eState; /* See above */ +}; + +typedef struct PoslistOffsetsCtx PoslistOffsetsCtx; +struct PoslistOffsetsCtx { + Fts5Buffer *pBuf; /* Append to this buffer */ + Fts5Colset *pColset; /* Restrict matches to this column */ + int iRead; + int iWrite; +}; + +/* +** TODO: Make this more efficient! +*/ +static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + +static void fts5PoslistOffsetsCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext; + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + int i = 0; + while( iiRead - 2; + pCtx->iRead = iVal; + if( fts5IndexColsetTest(pCtx->pColset, iVal) ){ + fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite); + pCtx->iWrite = iVal; + } + } + } +} + +static void fts5PoslistFilterCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext; + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + /* Search through to find the first varint with value 1. This is the + ** start of the next columns hits. */ + int i = 0; + int iStart = 0; + + if( pCtx->eState==2 ){ + int iCol; + fts5FastGetVarint32(pChunk, i, iCol); + if( fts5IndexColsetTest(pCtx->pColset, iCol) ){ + pCtx->eState = 1; + fts5BufferSafeAppendVarint(pCtx->pBuf, 1); + }else{ + pCtx->eState = 0; + } + } + + do { + while( ieState ){ + fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); + } + if( i=nChunk ){ + pCtx->eState = 2; + }else{ + fts5FastGetVarint32(pChunk, i, iCol); + pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol); + if( pCtx->eState ){ + fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); + iStart = i; + } + } + } + }while( inPos; /* Number of bytes still to come */ + Fts5Data *pData = 0; + u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); + int pgno = pSeg->iLeafPgno; + int pgnoSave = 0; + + /* This function does notmwork with detail=none databases. */ + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); + + if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ + pgnoSave = pgno+1; + } + + while( 1 ){ + xChunk(p, pCtx, pChunk, nChunk); + nRem -= nChunk; + fts5DataRelease(pData); + if( nRem<=0 ){ + break; + }else{ + pgno++; + pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); + if( pData==0 ) break; + pChunk = &pData->p[4]; + nChunk = MIN(nRem, pData->szLeaf - 4); + if( pgno==pgnoSave ){ + assert( pSeg->pNextLeaf==0 ); + pSeg->pNextLeaf = pData; + pData = 0; + } + } + } +} + +/* +** Iterator pIter currently points to a valid entry (not EOF). This +** function appends the position list data for the current entry to +** buffer pBuf. It does not make a copy of the position-list size +** field. +*/ +static void fts5SegiterPoslist( + Fts5Index *p, + Fts5SegIter *pSeg, + Fts5Colset *pColset, + Fts5Buffer *pBuf +){ + if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){ + if( pColset==0 ){ + fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); + }else{ + if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){ + PoslistCallbackCtx sCtx; + sCtx.pBuf = pBuf; + sCtx.pColset = pColset; + sCtx.eState = fts5IndexColsetTest(pColset, 0); + assert( sCtx.eState==0 || sCtx.eState==1 ); + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); + }else{ + PoslistOffsetsCtx sCtx; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.pBuf = pBuf; + sCtx.pColset = pColset; + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); + } + } + } +} + +/* +** IN/OUT parameter (*pa) points to a position list n bytes in size. If +** the position list contains entries for column iCol, then (*pa) is set +** to point to the sub-position-list for that column and the number of +** bytes in it returned. Or, if the argument position list does not +** contain any entries for column iCol, return 0. +*/ +static int fts5IndexExtractCol( + const u8 **pa, /* IN/OUT: Pointer to poslist */ + int n, /* IN: Size of poslist in bytes */ + int iCol /* Column to extract from poslist */ +){ + int iCurrent = 0; /* Anything before the first 0x01 is col 0 */ + const u8 *p = *pa; + const u8 *pEnd = &p[n]; /* One byte past end of position list */ + + while( iCol>iCurrent ){ + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint. Note that it is not possible for a negative + ** or extremely large varint to occur within an uncorrupted position + ** list. So the last byte of each varint may be assumed to have a clear + ** 0x80 bit. */ + while( *p!=0x01 ){ + while( *p++ & 0x80 ); + if( p>=pEnd ) return 0; + } + *pa = p++; + iCurrent = *p++; + if( iCurrent & 0x80 ){ + p--; + p += fts5GetVarint32(p, iCurrent); + } + } + if( iCol!=iCurrent ) return 0; + + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint */ + while( pnCol; i++){ + const u8 *pSub = pPos; + int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]); + if( nSub ){ + fts5BufferAppendBlob(&rc, pBuf, nSub, pSub); + } + } + return rc; +} + +/* +** xSetOutputs callback used by detail=none tables. +*/ +static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){ + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE ); + pIter->base.iRowid = pSeg->iRowid; + pIter->base.nData = pSeg->nPos; +} + +/* +** xSetOutputs callback used by detail=full and detail=col tables when no +** column filters are specified. +*/ +static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){ + pIter->base.iRowid = pSeg->iRowid; + pIter->base.nData = pSeg->nPos; + + assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE ); + assert( pIter->pColset==0 ); + + if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ + /* All data is stored on the current page. Populate the output + ** variables to point into the body of the page object. */ + pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + }else{ + /* The data is distributed over two or more pages. Copy it into the + ** Fts5Iter.poslist buffer and then set the output pointer to point + ** to this buffer. */ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + } +} + +/* +** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match +** against no columns at all). +*/ +static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){ + UNUSED_PARAM(pSeg); + pIter->base.nData = 0; +} + +/* +** xSetOutputs callback used by detail=col when there is a column filter +** and there are 100 or more columns. Also called as a fallback from +** fts5IterSetOutputs_Col100 if the column-list spans more than one page. +*/ +static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, pIter->pColset, &pIter->poslist); + pIter->base.iRowid = pSeg->iRowid; + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; +} + +/* +** xSetOutputs callback used when: +** +** * detail=col, +** * there is a column filter, and +** * the table contains 100 or fewer columns. +** +** The last point is to ensure all column numbers are stored as +** single-byte varints. +*/ +static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){ + + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + assert( pIter->pColset ); + + if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){ + fts5IterSetOutputs_Col(pIter, pSeg); + }else{ + u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset]; + u8 *pEnd = (u8*)&a[pSeg->nPos]; + int iPrev = 0; + int *aiCol = pIter->pColset->aiCol; + int *aiColEnd = &aiCol[pIter->pColset->nCol]; + + u8 *aOut = pIter->poslist.p; + int iPrevOut = 0; + + pIter->base.iRowid = pSeg->iRowid; + + while( abase.pData = pIter->poslist.p; + pIter->base.nData = aOut - pIter->poslist.p; + } +} + +/* +** xSetOutputs callback used by detail=full when there is a column filter. +*/ +static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){ + Fts5Colset *pColset = pIter->pColset; + pIter->base.iRowid = pSeg->iRowid; + + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL ); + assert( pColset ); + + if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ + /* All data is stored on the current page. Populate the output + ** variables to point into the body of the page object. */ + const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + if( pColset->nCol==1 ){ + pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]); + pIter->base.pData = a; + }else{ + fts5BufferZero(&pIter->poslist); + fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + } + }else{ + /* The data is distributed over two or more pages. Copy it into the + ** Fts5Iter.poslist buffer and then set the output pointer to point + ** to this buffer. */ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + } +} + +static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ + if( *pRc==SQLITE_OK ){ + Fts5Config *pConfig = pIter->pIndex->pConfig; + if( pConfig->eDetail==FTS5_DETAIL_NONE ){ + pIter->xSetOutputs = fts5IterSetOutputs_None; + } + + else if( pIter->pColset==0 ){ + pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; + } + + else if( pIter->pColset->nCol==0 ){ + pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset; + } + + else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ + pIter->xSetOutputs = fts5IterSetOutputs_Full; + } + + else{ + assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + if( pConfig->nCol<=100 ){ + pIter->xSetOutputs = fts5IterSetOutputs_Col100; + sqlite3Fts5BufferSize(pRc, &pIter->poslist, pConfig->nCol); + }else{ + pIter->xSetOutputs = fts5IterSetOutputs_Col; + } + } + } +} + + +/* +** Allocate a new Fts5Iter object. +** +** The new object will be used to iterate through data in structure pStruct. +** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel +** is zero or greater, data from the first nSegment segments on level iLevel +** is merged. +** +** The iterator initially points to the first term/rowid entry in the +** iterated data. +*/ +static void fts5MultiIterNew( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5Structure *pStruct, /* Structure of specific index */ + int flags, /* FTS5INDEX_QUERY_XXX flags */ + Fts5Colset *pColset, /* Colset to filter on (or NULL) */ + const u8 *pTerm, int nTerm, /* Term to seek to (or NULL/0) */ + int iLevel, /* Level to iterate (-1 for all) */ + int nSegment, /* Number of segments to merge (iLevel>=0) */ + Fts5Iter **ppOut /* New object */ +){ + int nSeg = 0; /* Number of segment-iters in use */ + int iIter = 0; /* */ + int iSeg; /* Used to iterate through segments */ + Fts5StructureLevel *pLvl; + Fts5Iter *pNew; + + assert( (pTerm==0 && nTerm==0) || iLevel<0 ); + + /* Allocate space for the new multi-seg-iterator. */ + if( p->rc==SQLITE_OK ){ + if( iLevel<0 ){ + assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); + nSeg = pStruct->nSegment; + nSeg += (p->pHash ? 1 : 0); + }else{ + nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); + } + } + *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); + if( pNew==0 ) return; + pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); + pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY)); + pNew->pStruct = pStruct; + pNew->pColset = pColset; + fts5StructureRef(pStruct); + if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){ + fts5IterSetOutputCb(&p->rc, pNew); + } + + /* Initialize each of the component segment iterators. */ + if( p->rc==SQLITE_OK ){ + if( iLevel<0 ){ + Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; + if( p->pHash ){ + /* Add a segment iterator for the current contents of the hash table. */ + Fts5SegIter *pIter = &pNew->aSeg[iIter++]; + fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter); + } + for(pLvl=&pStruct->aLevel[0]; pLvlnSeg-1; iSeg>=0; iSeg--){ + Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; + Fts5SegIter *pIter = &pNew->aSeg[iIter++]; + if( pTerm==0 ){ + fts5SegIterInit(p, pSeg, pIter); + }else{ + fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter); + } + } + } + }else{ + pLvl = &pStruct->aLevel[iLevel]; + for(iSeg=nSeg-1; iSeg>=0; iSeg--){ + fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]); + } + } + assert( iIter==nSeg ); + } + + /* If the above was successful, each component iterators now points + ** to the first entry in its segment. In this case initialize the + ** aFirst[] array. Or, if an error has occurred, free the iterator + ** object and set the output variable to NULL. */ + if( p->rc==SQLITE_OK ){ + for(iIter=pNew->nSeg-1; iIter>0; iIter--){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ + Fts5SegIter *pSeg = &pNew->aSeg[iEq]; + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); + fts5MultiIterAdvanced(p, pNew, iEq, iIter); + } + } + fts5MultiIterSetEof(pNew); + fts5AssertMultiIterSetup(p, pNew); + + if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){ + fts5MultiIterNext(p, pNew, 0, 0); + }else if( pNew->base.bEof==0 ){ + Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst]; + pNew->xSetOutputs(pNew, pSeg); + } + + }else{ + fts5MultiIterFree(pNew); + *ppOut = 0; + } +} + +/* +** Create an Fts5Iter that iterates through the doclist provided +** as the second argument. +*/ +static void fts5MultiIterNew2( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5Data *pData, /* Doclist to iterate through */ + int bDesc, /* True for descending rowid order */ + Fts5Iter **ppOut /* New object */ +){ + Fts5Iter *pNew; + pNew = fts5MultiIterAlloc(p, 2); + if( pNew ){ + Fts5SegIter *pIter = &pNew->aSeg[1]; + + pIter->flags = FTS5_SEGITER_ONETERM; + if( pData->szLeaf>0 ){ + pIter->pLeaf = pData; + pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid); + pIter->iEndofDoclist = pData->nn; + pNew->aFirst[1].iFirst = 1; + if( bDesc ){ + pNew->bRev = 1; + pIter->flags |= FTS5_SEGITER_REVERSE; + fts5SegIterReverseInitPage(p, pIter); + }else{ + fts5SegIterLoadNPos(p, pIter); + } + pData = 0; + }else{ + pNew->base.bEof = 1; + } + fts5SegIterSetNext(p, pIter); + + *ppOut = pNew; + } + + fts5DataRelease(pData); +} + +/* +** Return true if the iterator is at EOF or if an error has occurred. +** False otherwise. +*/ +static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ + assert( p->rc + || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof + ); + return (p->rc || pIter->base.bEof); +} + +/* +** Return the rowid of the entry that the iterator currently points +** to. If the iterator points to EOF when this function is called the +** results are undefined. +*/ +static i64 fts5MultiIterRowid(Fts5Iter *pIter){ + assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf ); + return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid; +} + +/* +** Move the iterator to the next entry at or following iMatch. +*/ +static void fts5MultiIterNextFrom( + Fts5Index *p, + Fts5Iter *pIter, + i64 iMatch +){ + while( 1 ){ + i64 iRowid; + fts5MultiIterNext(p, pIter, 1, iMatch); + if( fts5MultiIterEof(p, pIter) ) break; + iRowid = fts5MultiIterRowid(pIter); + if( pIter->bRev==0 && iRowid>=iMatch ) break; + if( pIter->bRev!=0 && iRowid<=iMatch ) break; + } +} + +/* +** Return a pointer to a buffer containing the term associated with the +** entry that the iterator currently points to. +*/ +static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){ + Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + *pn = p->term.n; + return p->term.p; +} + +/* +** Allocate a new segment-id for the structure pStruct. The new segment +** id must be between 1 and 65335 inclusive, and must not be used by +** any currently existing segment. If a free segment id cannot be found, +** SQLITE_FULL is returned. +** +** If an error has already occurred, this function is a no-op. 0 is +** returned in this case. +*/ +static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ + int iSegid = 0; + + if( p->rc==SQLITE_OK ){ + if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){ + p->rc = SQLITE_FULL; + }else{ + /* FTS5_MAX_SEGMENT is currently defined as 2000. So the following + ** array is 63 elements, or 252 bytes, in size. */ + u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32]; + int iLvl, iSeg; + int i; + u32 mask; + memset(aUsed, 0, sizeof(aUsed)); + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid; + if( iId<=FTS5_MAX_SEGMENT ){ + aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32); + } + } + } + + for(i=0; aUsed[i]==0xFFFFFFFF; i++); + mask = aUsed[i]; + for(iSegid=0; mask & (1 << iSegid); iSegid++); + iSegid += 1 + i*32; + +#ifdef SQLITE_DEBUG + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ); + } + } + assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); + + { + sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); + if( p->rc==SQLITE_OK ){ + u8 aBlob[2] = {0xff, 0xff}; + sqlite3_bind_int(pIdxSelect, 1, iSegid); + sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC); + assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); + p->rc = sqlite3_reset(pIdxSelect); + } + } +#endif + } + } + + return iSegid; +} + +/* +** Discard all data currently cached in the hash-tables. +*/ +static void fts5IndexDiscardData(Fts5Index *p){ + assert( p->pHash || p->nPendingData==0 ); + if( p->pHash ){ + sqlite3Fts5HashClear(p->pHash); + p->nPendingData = 0; + } +} + +/* +** Return the size of the prefix, in bytes, that buffer +** (pNew/) shares with buffer (pOld/nOld). +** +** Buffer (pNew/) is guaranteed to be greater +** than buffer (pOld/nOld). +*/ +static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){ + int i; + for(i=0; inDlidx>0 && pWriter->aDlidx[0].buf.n>0) ); + for(i=0; inDlidx; i++){ + Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i]; + if( pDlidx->buf.n==0 ) break; + if( bFlush ){ + assert( pDlidx->pgno!=0 ); + fts5DataWrite(p, + FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno), + pDlidx->buf.p, pDlidx->buf.n + ); + } + sqlite3Fts5BufferZero(&pDlidx->buf); + pDlidx->bPrevValid = 0; + } +} + +/* +** Grow the pWriter->aDlidx[] array to at least nLvl elements in size. +** Any new array elements are zeroed before returning. +*/ +static int fts5WriteDlidxGrow( + Fts5Index *p, + Fts5SegWriter *pWriter, + int nLvl +){ + if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){ + Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc( + pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl + ); + if( aDlidx==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); + memset(&aDlidx[pWriter->nDlidx], 0, nByte); + pWriter->aDlidx = aDlidx; + pWriter->nDlidx = nLvl; + } + } + return p->rc; +} + +/* +** If the current doclist-index accumulating in pWriter->aDlidx[] is large +** enough, flush it to disk and return 1. Otherwise discard it and return +** zero. +*/ +static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){ + int bFlag = 0; + + /* If there were FTS5_MIN_DLIDX_SIZE or more empty leaf pages written + ** to the database, also write the doclist-index to disk. */ + if( pWriter->aDlidx[0].buf.n>0 && pWriter->nEmpty>=FTS5_MIN_DLIDX_SIZE ){ + bFlag = 1; + } + fts5WriteDlidxClear(p, pWriter, bFlag); + pWriter->nEmpty = 0; + return bFlag; +} + +/* +** This function is called whenever processing of the doclist for the +** last term on leaf page (pWriter->iBtPage) is completed. +** +** The doclist-index for that term is currently stored in-memory within the +** Fts5SegWriter.aDlidx[] array. If it is large enough, this function +** writes it out to disk. Or, if it is too small to bother with, discards +** it. +** +** Fts5SegWriter.btterm currently contains the first term on page iBtPage. +*/ +static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){ + int bFlag; + + assert( pWriter->iBtPage || pWriter->nEmpty==0 ); + if( pWriter->iBtPage==0 ) return; + bFlag = fts5WriteFlushDlidx(p, pWriter); + + if( p->rc==SQLITE_OK ){ + const char *z = (pWriter->btterm.n>0?(const char*)pWriter->btterm.p:""); + /* The following was already done in fts5WriteInit(): */ + /* sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); */ + sqlite3_bind_blob(p->pIdxWriter, 2, z, pWriter->btterm.n, SQLITE_STATIC); + sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1)); + sqlite3_step(p->pIdxWriter); + p->rc = sqlite3_reset(p->pIdxWriter); + } + pWriter->iBtPage = 0; +} + +/* +** This is called once for each leaf page except the first that contains +** at least one term. Argument (nTerm/pTerm) is the split-key - a term that +** is larger than all terms written to earlier leaves, and equal to or +** smaller than the first term on the new leaf. +** +** If an error occurs, an error code is left in Fts5Index.rc. If an error +** has already occurred when this function is called, it is a no-op. +*/ +static void fts5WriteBtreeTerm( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegWriter *pWriter, /* Writer object */ + int nTerm, const u8 *pTerm /* First term on new page */ +){ + fts5WriteFlushBtree(p, pWriter); + fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); + pWriter->iBtPage = pWriter->writer.pgno; +} + +/* +** This function is called when flushing a leaf page that contains no +** terms at all to disk. +*/ +static void fts5WriteBtreeNoTerm( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegWriter *pWriter /* Writer object */ +){ + /* If there were no rowids on the leaf page either and the doclist-index + ** has already been started, append an 0x00 byte to it. */ + if( pWriter->bFirstRowidInPage && pWriter->aDlidx[0].buf.n>0 ){ + Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[0]; + assert( pDlidx->bPrevValid ); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, 0); + } + + /* Increment the "number of sequential leaves without a term" counter. */ + pWriter->nEmpty++; +} + +static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){ + i64 iRowid; + int iOff; + + iOff = 1 + fts5GetVarint(&pBuf->p[1], (u64*)&iRowid); + fts5GetVarint(&pBuf->p[iOff], (u64*)&iRowid); + return iRowid; +} + +/* +** Rowid iRowid has just been appended to the current leaf page. It is the +** first on the page. This function appends an appropriate entry to the current +** doclist-index. +*/ +static void fts5WriteDlidxAppend( + Fts5Index *p, + Fts5SegWriter *pWriter, + i64 iRowid +){ + int i; + int bDone = 0; + + for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ + i64 iVal; + Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i]; + + if( pDlidx->buf.n>=p->pConfig->pgsz ){ + /* The current doclist-index page is full. Write it to disk and push + ** a copy of iRowid (which will become the first rowid on the next + ** doclist-index leaf page) up into the next level of the b-tree + ** hierarchy. If the node being flushed is currently the root node, + ** also push its first rowid upwards. */ + pDlidx->buf.p[0] = 0x01; /* Not the root node */ + fts5DataWrite(p, + FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno), + pDlidx->buf.p, pDlidx->buf.n + ); + fts5WriteDlidxGrow(p, pWriter, i+2); + pDlidx = &pWriter->aDlidx[i]; + if( p->rc==SQLITE_OK && pDlidx[1].buf.n==0 ){ + i64 iFirst = fts5DlidxExtractFirstRowid(&pDlidx->buf); + + /* This was the root node. Push its first rowid up to the new root. */ + pDlidx[1].pgno = pDlidx->pgno; + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, 0); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, pDlidx->pgno); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, iFirst); + pDlidx[1].bPrevValid = 1; + pDlidx[1].iPrev = iFirst; + } + + sqlite3Fts5BufferZero(&pDlidx->buf); + pDlidx->bPrevValid = 0; + pDlidx->pgno++; + }else{ + bDone = 1; + } + + if( pDlidx->bPrevValid ){ + iVal = iRowid - pDlidx->iPrev; + }else{ + i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno); + assert( pDlidx->buf.n==0 ); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone); + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno); + iVal = iRowid; + } + + sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iVal); + pDlidx->bPrevValid = 1; + pDlidx->iPrev = iRowid; + } +} + +static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){ + static const u8 zero[] = { 0x00, 0x00, 0x00, 0x00 }; + Fts5PageWriter *pPage = &pWriter->writer; + i64 iRowid; + +static int nCall = 0; +nCall++; + + assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) ); + + /* Set the szLeaf header field. */ + assert( 0==fts5GetU16(&pPage->buf.p[2]) ); + fts5PutU16(&pPage->buf.p[2], (u16)pPage->buf.n); + + if( pWriter->bFirstTermInPage ){ + /* No term was written to this page. */ + assert( pPage->pgidx.n==0 ); + fts5WriteBtreeNoTerm(p, pWriter); + }else{ + /* Append the pgidx to the page buffer. Set the szLeaf header field. */ + fts5BufferAppendBlob(&p->rc, &pPage->buf, pPage->pgidx.n, pPage->pgidx.p); + } + + /* Write the page out to disk */ + iRowid = FTS5_SEGMENT_ROWID(pWriter->iSegid, pPage->pgno); + fts5DataWrite(p, iRowid, pPage->buf.p, pPage->buf.n); + + /* Initialize the next page. */ + fts5BufferZero(&pPage->buf); + fts5BufferZero(&pPage->pgidx); + fts5BufferAppendBlob(&p->rc, &pPage->buf, 4, zero); + pPage->iPrevPgidx = 0; + pPage->pgno++; + + /* Increase the leaves written counter */ + pWriter->nLeafWritten++; + + /* The new leaf holds no terms or rowids */ + pWriter->bFirstTermInPage = 1; + pWriter->bFirstRowidInPage = 1; +} + +/* +** Append term pTerm/nTerm to the segment being written by the writer passed +** as the second argument. +** +** If an error occurs, set the Fts5Index.rc error code. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5WriteAppendTerm( + Fts5Index *p, + Fts5SegWriter *pWriter, + int nTerm, const u8 *pTerm +){ + int nPrefix; /* Bytes of prefix compression for term */ + Fts5PageWriter *pPage = &pWriter->writer; + Fts5Buffer *pPgidx = &pWriter->writer.pgidx; + + assert( p->rc==SQLITE_OK ); + assert( pPage->buf.n>=4 ); + assert( pPage->buf.n>4 || pWriter->bFirstTermInPage ); + + /* If the current leaf page is full, flush it to disk. */ + if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){ + if( pPage->buf.n>4 ){ + fts5WriteFlushLeaf(p, pWriter); + } + fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING); + } + + /* TODO1: Updating pgidx here. */ + pPgidx->n += sqlite3Fts5PutVarint( + &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx + ); + pPage->iPrevPgidx = pPage->buf.n; +#if 0 + fts5PutU16(&pPgidx->p[pPgidx->n], pPage->buf.n); + pPgidx->n += 2; +#endif + + if( pWriter->bFirstTermInPage ){ + nPrefix = 0; + if( pPage->pgno!=1 ){ + /* This is the first term on a leaf that is not the leftmost leaf in + ** the segment b-tree. In this case it is necessary to add a term to + ** the b-tree hierarchy that is (a) larger than the largest term + ** already written to the segment and (b) smaller than or equal to + ** this term. In other words, a prefix of (pTerm/nTerm) that is one + ** byte longer than the longest prefix (pTerm/nTerm) shares with the + ** previous term. + ** + ** Usually, the previous term is available in pPage->term. The exception + ** is if this is the first term written in an incremental-merge step. + ** In this case the previous term is not available, so just write a + ** copy of (pTerm/nTerm) into the parent node. This is slightly + ** inefficient, but still correct. */ + int n = nTerm; + if( pPage->term.n ){ + n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + } + fts5WriteBtreeTerm(p, pWriter, n, pTerm); + pPage = &pWriter->writer; + } + }else{ + nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix); + } + + /* Append the number of bytes of new data, then the term data itself + ** to the page. */ + fts5BufferAppendVarint(&p->rc, &pPage->buf, nTerm - nPrefix); + fts5BufferAppendBlob(&p->rc, &pPage->buf, nTerm - nPrefix, &pTerm[nPrefix]); + + /* Update the Fts5PageWriter.term field. */ + fts5BufferSet(&p->rc, &pPage->term, nTerm, pTerm); + pWriter->bFirstTermInPage = 0; + + pWriter->bFirstRowidInPage = 0; + pWriter->bFirstRowidInDoclist = 1; + + assert( p->rc || (pWriter->nDlidx>0 && pWriter->aDlidx[0].buf.n==0) ); + pWriter->aDlidx[0].pgno = pPage->pgno; +} + +/* +** Append a rowid and position-list size field to the writers output. +*/ +static void fts5WriteAppendRowid( + Fts5Index *p, + Fts5SegWriter *pWriter, + i64 iRowid +){ + if( p->rc==SQLITE_OK ){ + Fts5PageWriter *pPage = &pWriter->writer; + + if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){ + fts5WriteFlushLeaf(p, pWriter); + } + + /* If this is to be the first rowid written to the page, set the + ** rowid-pointer in the page-header. Also append a value to the dlidx + ** buffer, in case a doclist-index is required. */ + if( pWriter->bFirstRowidInPage ){ + fts5PutU16(pPage->buf.p, (u16)pPage->buf.n); + fts5WriteDlidxAppend(p, pWriter, iRowid); + } + + /* Write the rowid. */ + if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ + fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); + }else{ + assert( p->rc || iRowid>pWriter->iPrevRowid ); + fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); + } + pWriter->iPrevRowid = iRowid; + pWriter->bFirstRowidInDoclist = 0; + pWriter->bFirstRowidInPage = 0; + } +} + +static void fts5WriteAppendPoslistData( + Fts5Index *p, + Fts5SegWriter *pWriter, + const u8 *aData, + int nData +){ + Fts5PageWriter *pPage = &pWriter->writer; + const u8 *a = aData; + int n = nData; + + assert( p->pConfig->pgsz>0 ); + while( p->rc==SQLITE_OK + && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz + ){ + int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n; + int nCopy = 0; + while( nCopyrc, &pPage->buf, nCopy, a); + a += nCopy; + n -= nCopy; + fts5WriteFlushLeaf(p, pWriter); + } + if( n>0 ){ + fts5BufferAppendBlob(&p->rc, &pPage->buf, n, a); + } +} + +/* +** Flush any data cached by the writer object to the database. Free any +** allocations associated with the writer. +*/ +static void fts5WriteFinish( + Fts5Index *p, + Fts5SegWriter *pWriter, /* Writer object */ + int *pnLeaf /* OUT: Number of leaf pages in b-tree */ +){ + int i; + Fts5PageWriter *pLeaf = &pWriter->writer; + if( p->rc==SQLITE_OK ){ + assert( pLeaf->pgno>=1 ); + if( pLeaf->buf.n>4 ){ + fts5WriteFlushLeaf(p, pWriter); + } + *pnLeaf = pLeaf->pgno-1; + if( pLeaf->pgno>1 ){ + fts5WriteFlushBtree(p, pWriter); + } + } + fts5BufferFree(&pLeaf->term); + fts5BufferFree(&pLeaf->buf); + fts5BufferFree(&pLeaf->pgidx); + fts5BufferFree(&pWriter->btterm); + + for(i=0; inDlidx; i++){ + sqlite3Fts5BufferFree(&pWriter->aDlidx[i].buf); + } + sqlite3_free(pWriter->aDlidx); +} + +static void fts5WriteInit( + Fts5Index *p, + Fts5SegWriter *pWriter, + int iSegid +){ + const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING; + + memset(pWriter, 0, sizeof(Fts5SegWriter)); + pWriter->iSegid = iSegid; + + fts5WriteDlidxGrow(p, pWriter, 1); + pWriter->writer.pgno = 1; + pWriter->bFirstTermInPage = 1; + pWriter->iBtPage = 1; + + assert( pWriter->writer.buf.n==0 ); + assert( pWriter->writer.pgidx.n==0 ); + + /* Grow the two buffers to pgsz + padding bytes in size. */ + sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.pgidx, nBuffer); + sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.buf, nBuffer); + + if( p->pIdxWriter==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf( + "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)", + pConfig->zDb, pConfig->zName + )); + } + + if( p->rc==SQLITE_OK ){ + /* Initialize the 4-byte leaf-page header to 0x00. */ + memset(pWriter->writer.buf.p, 0, 4); + pWriter->writer.buf.n = 4; + + /* Bind the current output segment id to the index-writer. This is an + ** optimization over binding the same value over and over as rows are + ** inserted into %_idx by the current writer. */ + sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); + } +} + +/* +** Iterator pIter was used to iterate through the input segments of on an +** incremental merge operation. This function is called if the incremental +** merge step has finished but the input has not been completely exhausted. +*/ +static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ + int i; + Fts5Buffer buf; + memset(&buf, 0, sizeof(Fts5Buffer)); + for(i=0; inSeg; i++){ + Fts5SegIter *pSeg = &pIter->aSeg[i]; + if( pSeg->pSeg==0 ){ + /* no-op */ + }else if( pSeg->pLeaf==0 ){ + /* All keys from this input segment have been transfered to the output. + ** Set both the first and last page-numbers to 0 to indicate that the + ** segment is now empty. */ + pSeg->pSeg->pgnoLast = 0; + pSeg->pSeg->pgnoFirst = 0; + }else{ + int iOff = pSeg->iTermLeafOffset; /* Offset on new first leaf page */ + i64 iLeafRowid; + Fts5Data *pData; + int iId = pSeg->pSeg->iSegid; + u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00}; + + iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno); + pData = fts5DataRead(p, iLeafRowid); + if( pData ){ + fts5BufferZero(&buf); + fts5BufferGrow(&p->rc, &buf, pData->nn); + fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); + fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); + fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); + fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]); + if( p->rc==SQLITE_OK ){ + /* Set the szLeaf field */ + fts5PutU16(&buf.p[2], (u16)buf.n); + } + + /* Set up the new page-index array */ + fts5BufferAppendVarint(&p->rc, &buf, 4); + if( pSeg->iLeafPgno==pSeg->iTermLeafPgno + && pSeg->iEndofDoclistszLeaf + ){ + int nDiff = pData->szLeaf - pSeg->iEndofDoclist; + fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); + fts5BufferAppendBlob(&p->rc, &buf, + pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] + ); + } + + fts5DataRelease(pData); + pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; + fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); + fts5DataWrite(p, iLeafRowid, buf.p, buf.n); + } + } + } + fts5BufferFree(&buf); +} + +static void fts5MergeChunkCallback( + Fts5Index *p, + void *pCtx, + const u8 *pChunk, int nChunk +){ + Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx; + fts5WriteAppendPoslistData(p, pWriter, pChunk, nChunk); +} + +/* +** +*/ +static void fts5IndexMergeLevel( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct, /* IN/OUT: Stucture of index */ + int iLvl, /* Level to read input from */ + int *pnRem /* Write up to this many output leaves */ +){ + Fts5Structure *pStruct = *ppStruct; + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + Fts5StructureLevel *pLvlOut; + Fts5Iter *pIter = 0; /* Iterator to read input data */ + int nRem = pnRem ? *pnRem : 0; /* Output leaf pages left to write */ + int nInput; /* Number of input segments */ + Fts5SegWriter writer; /* Writer object */ + Fts5StructureSegment *pSeg; /* Output segment */ + Fts5Buffer term; + int bOldest; /* True if the output segment is the oldest */ + int eDetail = p->pConfig->eDetail; + const int flags = FTS5INDEX_QUERY_NOOUTPUT; + + assert( iLvlnLevel ); + assert( pLvl->nMerge<=pLvl->nSeg ); + + memset(&writer, 0, sizeof(Fts5SegWriter)); + memset(&term, 0, sizeof(Fts5Buffer)); + if( pLvl->nMerge ){ + pLvlOut = &pStruct->aLevel[iLvl+1]; + assert( pLvlOut->nSeg>0 ); + nInput = pLvl->nMerge; + pSeg = &pLvlOut->aSeg[pLvlOut->nSeg-1]; + + fts5WriteInit(p, &writer, pSeg->iSegid); + writer.writer.pgno = pSeg->pgnoLast+1; + writer.iBtPage = 0; + }else{ + int iSegid = fts5AllocateSegid(p, pStruct); + + /* Extend the Fts5Structure object as required to ensure the output + ** segment exists. */ + if( iLvl==pStruct->nLevel-1 ){ + fts5StructureAddLevel(&p->rc, ppStruct); + pStruct = *ppStruct; + } + fts5StructureExtendLevel(&p->rc, pStruct, iLvl+1, 1, 0); + if( p->rc ) return; + pLvl = &pStruct->aLevel[iLvl]; + pLvlOut = &pStruct->aLevel[iLvl+1]; + + fts5WriteInit(p, &writer, iSegid); + + /* Add the new segment to the output level */ + pSeg = &pLvlOut->aSeg[pLvlOut->nSeg]; + pLvlOut->nSeg++; + pSeg->pgnoFirst = 1; + pSeg->iSegid = iSegid; + pStruct->nSegment++; + + /* Read input from all segments in the input level */ + nInput = pLvl->nSeg; + } + bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2); + + assert( iLvl>=0 ); + for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, iLvl, nInput, &pIter); + fts5MultiIterEof(p, pIter)==0; + fts5MultiIterNext(p, pIter, 0, 0) + ){ + Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + int nPos; /* position-list size field value */ + int nTerm; + const u8 *pTerm; + + /* Check for key annihilation. */ + if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; + + pTerm = fts5MultiIterTerm(pIter, &nTerm); + if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){ + if( pnRem && writer.nLeafWritten>nRem ){ + break; + } + + /* This is a new term. Append a term to the output segment. */ + fts5WriteAppendTerm(p, &writer, nTerm, pTerm); + fts5BufferSet(&p->rc, &term, nTerm, pTerm); + } + + /* Append the rowid to the output */ + /* WRITEPOSLISTSIZE */ + fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter)); + + if( eDetail==FTS5_DETAIL_NONE ){ + if( pSegIter->bDel ){ + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); + if( pSegIter->nPos>0 ){ + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); + } + } + }else{ + /* Append the position-list data to the output */ + nPos = pSegIter->nPos*2 + pSegIter->bDel; + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos); + fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback); + } + } + + /* Flush the last leaf page to disk. Set the output segment b-tree height + ** and last leaf page number at the same time. */ + fts5WriteFinish(p, &writer, &pSeg->pgnoLast); + + if( fts5MultiIterEof(p, pIter) ){ + int i; + + /* Remove the redundant segments from the %_data table */ + for(i=0; iaSeg[i].iSegid); + } + + /* Remove the redundant segments from the input level */ + if( pLvl->nSeg!=nInput ){ + int nMove = (pLvl->nSeg - nInput) * sizeof(Fts5StructureSegment); + memmove(pLvl->aSeg, &pLvl->aSeg[nInput], nMove); + } + pStruct->nSegment -= nInput; + pLvl->nSeg -= nInput; + pLvl->nMerge = 0; + if( pSeg->pgnoLast==0 ){ + pLvlOut->nSeg--; + pStruct->nSegment--; + } + }else{ + assert( pSeg->pgnoLast>0 ); + fts5TrimSegments(p, pIter); + pLvl->nMerge = nInput; + } + + fts5MultiIterFree(pIter); + fts5BufferFree(&term); + if( pnRem ) *pnRem -= writer.nLeafWritten; +} + +/* +** Do up to nPg pages of automerge work on the index. +** +** Return true if any changes were actually made, or false otherwise. +*/ +static int fts5IndexMerge( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ + int nPg, /* Pages of work to do */ + int nMin /* Minimum number of segments to merge */ +){ + int nRem = nPg; + int bRet = 0; + Fts5Structure *pStruct = *ppStruct; + while( nRem>0 && p->rc==SQLITE_OK ){ + int iLvl; /* To iterate through levels */ + int iBestLvl = 0; /* Level offering the most input segments */ + int nBest = 0; /* Number of input segments on best level */ + + /* Set iBestLvl to the level to read input segments from. */ + assert( pStruct->nLevel>0 ); + for(iLvl=0; iLvlnLevel; iLvl++){ + Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; + if( pLvl->nMerge ){ + if( pLvl->nMerge>nBest ){ + iBestLvl = iLvl; + nBest = pLvl->nMerge; + } + break; + } + if( pLvl->nSeg>nBest ){ + nBest = pLvl->nSeg; + iBestLvl = iLvl; + } + } + + /* If nBest is still 0, then the index must be empty. */ +#ifdef SQLITE_DEBUG + for(iLvl=0; nBest==0 && iLvlnLevel; iLvl++){ + assert( pStruct->aLevel[iLvl].nSeg==0 ); + } +#endif + + if( nBestaLevel[iBestLvl].nMerge==0 ){ + break; + } + bRet = 1; + fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem); + if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){ + fts5StructurePromote(p, iBestLvl+1, pStruct); + } + } + *ppStruct = pStruct; + return bRet; +} + +/* +** A total of nLeaf leaf pages of data has just been flushed to a level-0 +** segment. This function updates the write-counter accordingly and, if +** necessary, performs incremental merge work. +** +** If an error occurs, set the Fts5Index.rc error code. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5IndexAutomerge( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ + int nLeaf /* Number of output leaves just written */ +){ + if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){ + Fts5Structure *pStruct = *ppStruct; + u64 nWrite; /* Initial value of write-counter */ + int nWork; /* Number of work-quanta to perform */ + int nRem; /* Number of leaf pages left to write */ + + /* Update the write-counter. While doing so, set nWork. */ + nWrite = pStruct->nWriteCounter; + nWork = (int)(((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit)); + pStruct->nWriteCounter += nLeaf; + nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel); + + fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge); + } +} + +static void fts5IndexCrisismerge( + Fts5Index *p, /* FTS5 backend object */ + Fts5Structure **ppStruct /* IN/OUT: Current structure of index */ +){ + const int nCrisis = p->pConfig->nCrisisMerge; + Fts5Structure *pStruct = *ppStruct; + int iLvl = 0; + + assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 ); + while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){ + fts5IndexMergeLevel(p, &pStruct, iLvl, 0); + assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) ); + fts5StructurePromote(p, iLvl+1, pStruct); + iLvl++; + } + *ppStruct = pStruct; +} + +static int fts5IndexReturn(Fts5Index *p){ + int rc = p->rc; + p->rc = SQLITE_OK; + return rc; +} + +typedef struct Fts5FlushCtx Fts5FlushCtx; +struct Fts5FlushCtx { + Fts5Index *pIdx; + Fts5SegWriter writer; +}; + +/* +** Buffer aBuf[] contains a list of varints, all small enough to fit +** in a 32-bit integer. Return the size of the largest prefix of this +** list nMax bytes or less in size. +*/ +static int fts5PoslistPrefix(const u8 *aBuf, int nMax){ + int ret; + u32 dummy; + ret = fts5GetVarint32(aBuf, dummy); + if( ret nMax ) break; + ret += i; + } + } + return ret; +} + +/* +** Flush the contents of in-memory hash table iHash to a new level-0 +** segment on disk. Also update the corresponding structure record. +** +** If an error occurs, set the Fts5Index.rc error code. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5FlushOneHash(Fts5Index *p){ + Fts5Hash *pHash = p->pHash; + Fts5Structure *pStruct; + int iSegid; + int pgnoLast = 0; /* Last leaf page number in segment */ + + /* Obtain a reference to the index structure and allocate a new segment-id + ** for the new level-0 segment. */ + pStruct = fts5StructureRead(p); + iSegid = fts5AllocateSegid(p, pStruct); + fts5StructureInvalidate(p); + + if( iSegid ){ + const int pgsz = p->pConfig->pgsz; + int eDetail = p->pConfig->eDetail; + Fts5StructureSegment *pSeg; /* New segment within pStruct */ + Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */ + Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */ + + Fts5SegWriter writer; + fts5WriteInit(p, &writer, iSegid); + + pBuf = &writer.writer.buf; + pPgidx = &writer.writer.pgidx; + + /* fts5WriteInit() should have initialized the buffers to (most likely) + ** the maximum space required. */ + assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) ); + assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) ); + + /* Begin scanning through hash table entries. This loop runs once for each + ** term/doclist currently stored within the hash table. */ + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0); + } + while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){ + const char *zTerm; /* Buffer containing term */ + const u8 *pDoclist; /* Pointer to doclist for this term */ + int nDoclist; /* Size of doclist in bytes */ + + /* Write the term for this entry to disk. */ + sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); + fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); + + assert( writer.bFirstRowidInPage==0 ); + if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ + /* The entire doclist will fit on the current leaf. */ + fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); + }else{ + i64 iRowid = 0; + i64 iDelta = 0; + int iOff = 0; + + /* The entire doclist will not fit on this leaf. The following + ** loop iterates through the poslists that make up the current + ** doclist. */ + while( p->rc==SQLITE_OK && iOffp[0], (u16)pBuf->n); /* first rowid on page */ + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); + writer.bFirstRowidInPage = 0; + fts5WriteDlidxAppend(p, &writer, iRowid); + }else{ + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); + } + assert( pBuf->n<=pBuf->nSpace ); + + if( eDetail==FTS5_DETAIL_NONE ){ + if( iOffp[pBuf->n++] = 0; + iOff++; + if( iOffp[pBuf->n++] = 0; + iOff++; + } + } + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + }else{ + int bDummy; + int nPos; + int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy); + nCopy += nPos; + if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ + /* The entire poslist will fit on the current leaf. So copy + ** it in one go. */ + fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy); + }else{ + /* The entire poslist will not fit on this leaf. So it needs + ** to be broken into sections. The only qualification being + ** that each varint must be stored contiguously. */ + const u8 *pPoslist = &pDoclist[iOff]; + int iPos = 0; + while( p->rc==SQLITE_OK ){ + int nSpace = pgsz - pBuf->n - pPgidx->n; + int n = 0; + if( (nCopy - iPos)<=nSpace ){ + n = nCopy - iPos; + }else{ + n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); + } + assert( n>0 ); + fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); + iPos += n; + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + if( iPos>=nCopy ) break; + } + } + iOff += nCopy; + } + } + } + + /* TODO2: Doclist terminator written here. */ + /* pBuf->p[pBuf->n++] = '\0'; */ + assert( pBuf->n<=pBuf->nSpace ); + sqlite3Fts5HashScanNext(pHash); + } + sqlite3Fts5HashClear(pHash); + fts5WriteFinish(p, &writer, &pgnoLast); + + /* Update the Fts5Structure. It is written back to the database by the + ** fts5StructureRelease() call below. */ + if( pStruct->nLevel==0 ){ + fts5StructureAddLevel(&p->rc, &pStruct); + } + fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0); + if( p->rc==SQLITE_OK ){ + pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ]; + pSeg->iSegid = iSegid; + pSeg->pgnoFirst = 1; + pSeg->pgnoLast = pgnoLast; + pStruct->nSegment++; + } + fts5StructurePromote(p, 0, pStruct); + } + + fts5IndexAutomerge(p, &pStruct, pgnoLast); + fts5IndexCrisismerge(p, &pStruct); + fts5StructureWrite(p, pStruct); + fts5StructureRelease(pStruct); +} + +/* +** Flush any data stored in the in-memory hash tables to the database. +*/ +static void fts5IndexFlush(Fts5Index *p){ + /* Unless it is empty, flush the hash table to disk */ + if( p->nPendingData ){ + assert( p->pHash ); + p->nPendingData = 0; + fts5FlushOneHash(p); + } +} + +static Fts5Structure *fts5IndexOptimizeStruct( + Fts5Index *p, + Fts5Structure *pStruct +){ + Fts5Structure *pNew = 0; + int nByte = sizeof(Fts5Structure); + int nSeg = pStruct->nSegment; + int i; + + /* Figure out if this structure requires optimization. A structure does + ** not require optimization if either: + ** + ** + it consists of fewer than two segments, or + ** + all segments are on the same level, or + ** + all segments except one are currently inputs to a merge operation. + ** + ** In the first case, return NULL. In the second, increment the ref-count + ** on *pStruct and return a copy of the pointer to it. + */ + if( nSeg<2 ) return 0; + for(i=0; inLevel; i++){ + int nThis = pStruct->aLevel[i].nSeg; + if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){ + fts5StructureRef(pStruct); + return pStruct; + } + assert( pStruct->aLevel[i].nMerge<=nThis ); + } + + nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); + pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); + + if( pNew ){ + Fts5StructureLevel *pLvl; + nByte = nSeg * sizeof(Fts5StructureSegment); + pNew->nLevel = pStruct->nLevel+1; + pNew->nRef = 1; + pNew->nWriteCounter = pStruct->nWriteCounter; + pLvl = &pNew->aLevel[pStruct->nLevel]; + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte); + if( pLvl->aSeg ){ + int iLvl, iSeg; + int iSegOut = 0; + /* Iterate through all segments, from oldest to newest. Add them to + ** the new Fts5Level object so that pLvl->aSeg[0] is the oldest + ** segment in the data structure. */ + for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg]; + iSegOut++; + } + } + pNew->nSegment = pLvl->nSeg = nSeg; + }else{ + sqlite3_free(pNew); + pNew = 0; + } + } + + return pNew; +} + +static int sqlite3Fts5IndexOptimize(Fts5Index *p){ + Fts5Structure *pStruct; + Fts5Structure *pNew = 0; + + assert( p->rc==SQLITE_OK ); + fts5IndexFlush(p); + pStruct = fts5StructureRead(p); + fts5StructureInvalidate(p); + + if( pStruct ){ + pNew = fts5IndexOptimizeStruct(p, pStruct); + } + fts5StructureRelease(pStruct); + + assert( pNew==0 || pNew->nSegment>0 ); + if( pNew ){ + int iLvl; + for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){} + while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){ + int nRem = FTS5_OPT_WORK_UNIT; + fts5IndexMergeLevel(p, &pNew, iLvl, &nRem); + } + + fts5StructureWrite(p, pNew); + fts5StructureRelease(pNew); + } + + return fts5IndexReturn(p); +} + +/* +** This is called to implement the special "VALUES('merge', $nMerge)" +** INSERT command. +*/ +static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){ + Fts5Structure *pStruct = fts5StructureRead(p); + if( pStruct ){ + int nMin = p->pConfig->nUsermerge; + fts5StructureInvalidate(p); + if( nMerge<0 ){ + Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct); + fts5StructureRelease(pStruct); + pStruct = pNew; + nMin = 2; + nMerge = nMerge*-1; + } + if( pStruct && pStruct->nLevel ){ + if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){ + fts5StructureWrite(p, pStruct); + } + } + fts5StructureRelease(pStruct); + } + return fts5IndexReturn(p); +} + +static void fts5AppendRowid( + Fts5Index *p, + i64 iDelta, + Fts5Iter *pUnused, + Fts5Buffer *pBuf +){ + UNUSED_PARAM(pUnused); + fts5BufferAppendVarint(&p->rc, pBuf, iDelta); +} + +static void fts5AppendPoslist( + Fts5Index *p, + i64 iDelta, + Fts5Iter *pMulti, + Fts5Buffer *pBuf +){ + int nData = pMulti->base.nData; + assert( nData>0 ); + if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){ + fts5BufferSafeAppendVarint(pBuf, iDelta); + fts5BufferSafeAppendVarint(pBuf, nData*2); + fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData); + } +} + + +static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ + u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; + + assert( pIter->aPoslist ); + if( p>=pIter->aEof ){ + pIter->aPoslist = 0; + }else{ + i64 iDelta; + + p += fts5GetVarint(p, (u64*)&iDelta); + pIter->iRowid += iDelta; + + /* Read position list size */ + if( p[0] & 0x80 ){ + int nPos; + pIter->nSize = fts5GetVarint32(p, nPos); + pIter->nPoslist = (nPos>>1); + }else{ + pIter->nPoslist = ((int)(p[0])) >> 1; + pIter->nSize = 1; + } + + pIter->aPoslist = p; + } +} + +static void fts5DoclistIterInit( + Fts5Buffer *pBuf, + Fts5DoclistIter *pIter +){ + memset(pIter, 0, sizeof(*pIter)); + pIter->aPoslist = pBuf->p; + pIter->aEof = &pBuf->p[pBuf->n]; + fts5DoclistIterNext(pIter); +} + +#if 0 +/* +** Append a doclist to buffer pBuf. +** +** This function assumes that space within the buffer has already been +** allocated. +*/ +static void fts5MergeAppendDocid( + Fts5Buffer *pBuf, /* Buffer to write to */ + i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */ + i64 iRowid /* Rowid to append */ +){ + assert( pBuf->n!=0 || (*piLastRowid)==0 ); + fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid); + *piLastRowid = iRowid; +} +#endif + +#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \ + assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \ + fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \ + (iLastRowid) = (iRowid); \ +} + +/* +** Swap the contents of buffer *p1 with that of *p2. +*/ +static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ + Fts5Buffer tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){ + int i = *piOff; + if( i>=pBuf->n ){ + *piOff = -1; + }else{ + u64 iVal; + *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal); + *piRowid += iVal; + } +} + +/* +** This is the equivalent of fts5MergePrefixLists() for detail=none mode. +** In this case the buffers consist of a delta-encoded list of rowids only. +*/ +static void fts5MergeRowidLists( + Fts5Index *p, /* FTS5 backend object */ + Fts5Buffer *p1, /* First list to merge */ + Fts5Buffer *p2 /* Second list to merge */ +){ + int i1 = 0; + int i2 = 0; + i64 iRowid1 = 0; + i64 iRowid2 = 0; + i64 iOut = 0; + + Fts5Buffer out; + memset(&out, 0, sizeof(out)); + sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); + if( p->rc ) return; + + fts5NextRowid(p1, &i1, &iRowid1); + fts5NextRowid(p2, &i2, &iRowid2); + while( i1>=0 || i2>=0 ){ + if( i1>=0 && (i2<0 || iRowid1iOut ); + fts5BufferSafeAppendVarint(&out, iRowid1 - iOut); + iOut = iRowid1; + fts5NextRowid(p1, &i1, &iRowid1); + }else{ + assert( iOut==0 || iRowid2>iOut ); + fts5BufferSafeAppendVarint(&out, iRowid2 - iOut); + iOut = iRowid2; + if( i1>=0 && iRowid1==iRowid2 ){ + fts5NextRowid(p1, &i1, &iRowid1); + } + fts5NextRowid(p2, &i2, &iRowid2); + } + } + + fts5BufferSwap(&out, p1); + fts5BufferFree(&out); +} + +/* +** Buffers p1 and p2 contain doclists. This function merges the content +** of the two doclists together and sets buffer p1 to the result before +** returning. +** +** If an error occurs, an error code is left in p->rc. If an error has +** already occurred, this function is a no-op. +*/ +static void fts5MergePrefixLists( + Fts5Index *p, /* FTS5 backend object */ + Fts5Buffer *p1, /* First list to merge */ + Fts5Buffer *p2 /* Second list to merge */ +){ + if( p2->n ){ + i64 iLastRowid = 0; + Fts5DoclistIter i1; + Fts5DoclistIter i2; + Fts5Buffer out = {0, 0, 0}; + Fts5Buffer tmp = {0, 0, 0}; + + if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return; + fts5DoclistIterInit(p1, &i1); + fts5DoclistIterInit(p2, &i2); + + while( 1 ){ + if( i1.iRowidrc, &tmp, i1.nPoslist + i2.nPoslist); + if( p->rc ) break; + + sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); + sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); + assert( iPos1>=0 && iPos2>=0 ); + + if( iPos1=0 && iPos2>=0 ){ + while( 1 ){ + if( iPos1=0 ){ + if( iPos1!=iPrev ){ + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); + } + fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1); + }else{ + assert( iPos2>=0 && iPos2!=iPrev ); + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); + fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2); + } + + /* WRITEPOSLISTSIZE */ + fts5BufferSafeAppendVarint(&out, tmp.n * 2); + fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); + fts5DoclistIterNext(&i1); + fts5DoclistIterNext(&i2); + if( i1.aPoslist==0 || i2.aPoslist==0 ) break; + } + } + + if( i1.aPoslist ){ + fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); + fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist); + } + else if( i2.aPoslist ){ + fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); + fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); + } + + fts5BufferSet(&p->rc, p1, out.n, out.p); + fts5BufferFree(&tmp); + fts5BufferFree(&out); + } +} + +static void fts5SetupPrefixIter( + Fts5Index *p, /* Index to read from */ + int bDesc, /* True for "ORDER BY rowid DESC" */ + const u8 *pToken, /* Buffer containing prefix to match */ + int nToken, /* Size of buffer pToken in bytes */ + Fts5Colset *pColset, /* Restrict matches to these columns */ + Fts5Iter **ppIter /* OUT: New iterator */ +){ + Fts5Structure *pStruct; + Fts5Buffer *aBuf; + const int nBuf = 32; + + void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*); + void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*); + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + xMerge = fts5MergeRowidLists; + xAppend = fts5AppendRowid; + }else{ + xMerge = fts5MergePrefixLists; + xAppend = fts5AppendPoslist; + } + + aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); + pStruct = fts5StructureRead(p); + + if( aBuf && pStruct ){ + const int flags = FTS5INDEX_QUERY_SCAN + | FTS5INDEX_QUERY_SKIPEMPTY + | FTS5INDEX_QUERY_NOOUTPUT; + int i; + i64 iLastRowid = 0; + Fts5Iter *p1 = 0; /* Iterator used to gather data from index */ + Fts5Data *pData; + Fts5Buffer doclist; + int bNewTerm = 1; + + memset(&doclist, 0, sizeof(doclist)); + fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); + fts5IterSetOutputCb(&p->rc, p1); + for( /* no-op */ ; + fts5MultiIterEof(p, p1)==0; + fts5MultiIterNext2(p, p1, &bNewTerm) + ){ + Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; + int nTerm = pSeg->term.n; + const u8 *pTerm = pSeg->term.p; + p1->xSetOutputs(p1, pSeg); + + assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 ); + if( bNewTerm ){ + if( nTermbase.nData==0 ) continue; + + if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ + for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ + assert( ibase.iRowid-iLastRowid, p1, &doclist); + iLastRowid = p1->base.iRowid; + } + + for(i=0; irc==SQLITE_OK ){ + xMerge(p, &doclist, &aBuf[i]); + } + fts5BufferFree(&aBuf[i]); + } + fts5MultiIterFree(p1); + + pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n); + if( pData ){ + pData->p = (u8*)&pData[1]; + pData->nn = pData->szLeaf = doclist.n; + memcpy(pData->p, doclist.p, doclist.n); + fts5MultiIterNew2(p, pData, bDesc, ppIter); + } + fts5BufferFree(&doclist); + } + + fts5StructureRelease(pStruct); + sqlite3_free(aBuf); +} + + +/* +** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain +** to the document with rowid iRowid. +*/ +static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ + assert( p->rc==SQLITE_OK ); + + /* Allocate the hash table if it has not already been allocated */ + if( p->pHash==0 ){ + p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData); + } + + /* Flush the hash table to disk if required */ + if( iRowidiWriteRowid + || (iRowid==p->iWriteRowid && p->bDelete==0) + || (p->nPendingData > p->pConfig->nHashSize) + ){ + fts5IndexFlush(p); + } + + p->iWriteRowid = iRowid; + p->bDelete = bDelete; + return fts5IndexReturn(p); +} + +/* +** Commit data to disk. +*/ +static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ + assert( p->rc==SQLITE_OK ); + fts5IndexFlush(p); + if( bCommit ) fts5CloseReader(p); + return fts5IndexReturn(p); +} + +/* +** Discard any data stored in the in-memory hash tables. Do not write it +** to the database. Additionally, assume that the contents of the %_data +** table may have changed on disk. So any in-memory caches of %_data +** records must be invalidated. +*/ +static int sqlite3Fts5IndexRollback(Fts5Index *p){ + fts5CloseReader(p); + fts5IndexDiscardData(p); + fts5StructureInvalidate(p); + /* assert( p->rc==SQLITE_OK ); */ + return SQLITE_OK; +} + +/* +** The %_data table is completely empty when this function is called. This +** function populates it with the initial structure objects for each index, +** and the initial version of the "averages" record (a zero-byte blob). +*/ +static int sqlite3Fts5IndexReinit(Fts5Index *p){ + Fts5Structure s; + fts5StructureInvalidate(p); + memset(&s, 0, sizeof(Fts5Structure)); + fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); + fts5StructureWrite(p, &s); + return fts5IndexReturn(p); +} + +/* +** Open a new Fts5Index handle. If the bCreate argument is true, create +** and initialize the underlying %_data table. +** +** If successful, set *pp to point to the new object and return SQLITE_OK. +** Otherwise, set *pp to NULL and return an SQLite error code. +*/ +static int sqlite3Fts5IndexOpen( + Fts5Config *pConfig, + int bCreate, + Fts5Index **pp, + char **pzErr +){ + int rc = SQLITE_OK; + Fts5Index *p; /* New object */ + + *pp = p = (Fts5Index*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Index)); + if( rc==SQLITE_OK ){ + p->pConfig = pConfig; + p->nWorkUnit = FTS5_WORK_UNIT; + p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName); + if( p->zDataTbl && bCreate ){ + rc = sqlite3Fts5CreateTable( + pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5CreateTable(pConfig, "idx", + "segid, term, pgno, PRIMARY KEY(segid, term)", + 1, pzErr + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexReinit(p); + } + } + } + + assert( rc!=SQLITE_OK || p->rc==SQLITE_OK ); + if( rc ){ + sqlite3Fts5IndexClose(p); + *pp = 0; + } + return rc; +} + +/* +** Close a handle opened by an earlier call to sqlite3Fts5IndexOpen(). +*/ +static int sqlite3Fts5IndexClose(Fts5Index *p){ + int rc = SQLITE_OK; + if( p ){ + assert( p->pReader==0 ); + fts5StructureInvalidate(p); + sqlite3_finalize(p->pWriter); + sqlite3_finalize(p->pDeleter); + sqlite3_finalize(p->pIdxWriter); + sqlite3_finalize(p->pIdxDeleter); + sqlite3_finalize(p->pIdxSelect); + sqlite3_finalize(p->pDataVersion); + sqlite3Fts5HashFree(p->pHash); + sqlite3_free(p->zDataTbl); + sqlite3_free(p); + } + return rc; +} + +/* +** Argument p points to a buffer containing utf-8 text that is n bytes in +** size. Return the number of bytes in the nChar character prefix of the +** buffer, or 0 if there are less than nChar characters in total. +*/ +static int sqlite3Fts5IndexCharlenToBytelen( + const char *p, + int nByte, + int nChar +){ + int n = 0; + int i; + for(i=0; i=nByte ) return 0; /* Input contains fewer than nChar chars */ + if( (unsigned char)p[n++]>=0xc0 ){ + while( (p[n] & 0xc0)==0x80 ) n++; + } + } + return n; +} + +/* +** pIn is a UTF-8 encoded string, nIn bytes in size. Return the number of +** unicode characters in the string. +*/ +static int fts5IndexCharlen(const char *pIn, int nIn){ + int nChar = 0; + int i = 0; + while( i=0xc0 ){ + while( i delete) */ + int iPos, /* Position of token within column */ + const char *pToken, int nToken /* Token to add or remove to or from index */ +){ + int i; /* Used to iterate through indexes */ + int rc = SQLITE_OK; /* Return code */ + Fts5Config *pConfig = p->pConfig; + + assert( p->rc==SQLITE_OK ); + assert( (iCol<0)==p->bDelete ); + + /* Add the entry to the main terms index. */ + rc = sqlite3Fts5HashWrite( + p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken + ); + + for(i=0; inPrefix && rc==SQLITE_OK; i++){ + const int nChar = pConfig->aPrefix[i]; + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); + if( nByte ){ + rc = sqlite3Fts5HashWrite(p->pHash, + p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken, + nByte + ); + } + } + + return rc; +} + +/* +** Open a new iterator to iterate though all rowid that match the +** specified token or token prefix. +*/ +static int sqlite3Fts5IndexQuery( + Fts5Index *p, /* FTS index to query */ + const char *pToken, int nToken, /* Token (or prefix) to query for */ + int flags, /* Mask of FTS5INDEX_QUERY_X flags */ + Fts5Colset *pColset, /* Match these columns only */ + Fts5IndexIter **ppIter /* OUT: New iterator object */ +){ + Fts5Config *pConfig = p->pConfig; + Fts5Iter *pRet = 0; + Fts5Buffer buf = {0, 0, 0}; + + /* If the QUERY_SCAN flag is set, all other flags must be clear. */ + assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); + + if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ + int iIdx = 0; /* Index to search */ + memcpy(&buf.p[1], pToken, nToken); + + /* Figure out which index to search and set iIdx accordingly. If this + ** is a prefix query for which there is no prefix index, set iIdx to + ** greater than pConfig->nPrefix to indicate that the query will be + ** satisfied by scanning multiple terms in the main index. + ** + ** If the QUERY_TEST_NOIDX flag was specified, then this must be a + ** prefix-query. Instead of using a prefix-index (if one exists), + ** evaluate the prefix query using the main FTS index. This is used + ** for internal sanity checking by the integrity-check in debug + ** mode only. */ +#ifdef SQLITE_DEBUG + if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){ + assert( flags & FTS5INDEX_QUERY_PREFIX ); + iIdx = 1+pConfig->nPrefix; + }else +#endif + if( flags & FTS5INDEX_QUERY_PREFIX ){ + int nChar = fts5IndexCharlen(pToken, nToken); + for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){ + if( pConfig->aPrefix[iIdx-1]==nChar ) break; + } + } + + if( iIdx<=pConfig->nPrefix ){ + /* Straight index lookup */ + Fts5Structure *pStruct = fts5StructureRead(p); + buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); + if( pStruct ){ + fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, + pColset, buf.p, nToken+1, -1, 0, &pRet + ); + fts5StructureRelease(pStruct); + } + }else{ + /* Scan multiple terms in the main index */ + int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; + buf.p[0] = FTS5_MAIN_PREFIX; + fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet); + assert( p->rc!=SQLITE_OK || pRet->pColset==0 ); + fts5IterSetOutputCb(&p->rc, pRet); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; + if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + } + } + + if( p->rc ){ + sqlite3Fts5IterClose(&pRet->base); + pRet = 0; + fts5CloseReader(p); + } + + *ppIter = &pRet->base; + sqlite3Fts5BufferFree(&buf); + } + return fts5IndexReturn(p); +} + +/* +** Return true if the iterator passed as the only argument is at EOF. +*/ +/* +** Move to the next matching rowid. +*/ +static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + assert( pIter->pIndex->rc==SQLITE_OK ); + fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); + return fts5IndexReturn(pIter->pIndex); +} + +/* +** Move to the next matching term/rowid. Used by the fts5vocab module. +*/ +static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + Fts5Index *p = pIter->pIndex; + + assert( pIter->pIndex->rc==SQLITE_OK ); + + fts5MultiIterNext(p, pIter, 0, 0); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; + if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){ + fts5DataRelease(pSeg->pLeaf); + pSeg->pLeaf = 0; + pIter->base.bEof = 1; + } + } + + return fts5IndexReturn(pIter->pIndex); +} + +/* +** Move to the next matching rowid that occurs at or after iMatch. The +** definition of "at or after" depends on whether this iterator iterates +** in ascending or descending rowid order. +*/ +static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); + return fts5IndexReturn(pIter->pIndex); +} + +/* +** Return the current term. +*/ +static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ + int n; + const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); + *pn = n-1; + return &z[1]; +} + +/* +** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). +*/ +static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ + if( pIndexIter ){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + Fts5Index *pIndex = pIter->pIndex; + fts5MultiIterFree(pIter); + fts5CloseReader(pIndex); + } +} + +/* +** Read and decode the "averages" record from the database. +** +** Parameter anSize must point to an array of size nCol, where nCol is +** the number of user defined columns in the FTS table. +*/ +static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){ + int nCol = p->pConfig->nCol; + Fts5Data *pData; + + *pnRow = 0; + memset(anSize, 0, sizeof(i64) * nCol); + pData = fts5DataRead(p, FTS5_AVERAGES_ROWID); + if( p->rc==SQLITE_OK && pData->nn ){ + int i = 0; + int iCol; + i += fts5GetVarint(&pData->p[i], (u64*)pnRow); + for(iCol=0; inn && iColp[i], (u64*)&anSize[iCol]); + } + } + + fts5DataRelease(pData); + return fts5IndexReturn(p); +} + +/* +** Replace the current "averages" record with the contents of the buffer +** supplied as the second argument. +*/ +static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){ + assert( p->rc==SQLITE_OK ); + fts5DataWrite(p, FTS5_AVERAGES_ROWID, pData, nData); + return fts5IndexReturn(p); +} + +/* +** Return the total number of blocks this module has read from the %_data +** table since it was created. +*/ +static int sqlite3Fts5IndexReads(Fts5Index *p){ + return p->nRead; +} + +/* +** Set the 32-bit cookie value stored at the start of all structure +** records to the value passed as the second argument. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){ + int rc; /* Return code */ + Fts5Config *pConfig = p->pConfig; /* Configuration object */ + u8 aCookie[4]; /* Binary representation of iNew */ + sqlite3_blob *pBlob = 0; + + assert( p->rc==SQLITE_OK ); + sqlite3Fts5Put32(aCookie, iNew); + + rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, + "block", FTS5_STRUCTURE_ROWID, 1, &pBlob + ); + if( rc==SQLITE_OK ){ + sqlite3_blob_write(pBlob, aCookie, 4, 0); + rc = sqlite3_blob_close(pBlob); + } + + return rc; +} + +static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){ + Fts5Structure *pStruct; + pStruct = fts5StructureRead(p); + fts5StructureRelease(pStruct); + return fts5IndexReturn(p); +} + + +/************************************************************************* +************************************************************************** +** Below this point is the implementation of the integrity-check +** functionality. +*/ + +/* +** Return a simple checksum value based on the arguments. +*/ +static u64 sqlite3Fts5IndexEntryCksum( + i64 iRowid, + int iCol, + int iPos, + int iIdx, + const char *pTerm, + int nTerm +){ + int i; + u64 ret = iRowid; + ret += (ret<<3) + iCol; + ret += (ret<<3) + iPos; + if( iIdx>=0 ) ret += (ret<<3) + (FTS5_MAIN_PREFIX + iIdx); + for(i=0; iiLeaf ); + cksum1 += iRowid + ((i64)pgno<<32); + } + fts5DlidxIterFree(pDlidx); + pDlidx = 0; + + for(pDlidx=fts5DlidxIterInit(p, 1, iSegid, iLeaf); + fts5DlidxIterEof(p, pDlidx)==0; + fts5DlidxIterPrev(p, pDlidx) + ){ + i64 iRowid = fts5DlidxIterRowid(pDlidx); + int pgno = fts5DlidxIterPgno(pDlidx); + assert( fts5DlidxIterPgno(pDlidx)>iLeaf ); + cksum2 += iRowid + ((i64)pgno<<32); + } + fts5DlidxIterFree(pDlidx); + pDlidx = 0; + + if( p->rc==SQLITE_OK && cksum1!=cksum2 ) p->rc = FTS5_CORRUPT; +} + +static int fts5QueryCksum( + Fts5Index *p, /* Fts5 index object */ + int iIdx, + const char *z, /* Index key to query for */ + int n, /* Size of index key in bytes */ + int flags, /* Flags for Fts5IndexQuery */ + u64 *pCksum /* IN/OUT: Checksum value */ +){ + int eDetail = p->pConfig->eDetail; + u64 cksum = *pCksum; + Fts5IndexIter *pIter = 0; + int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); + + while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){ + i64 rowid = pIter->iRowid; + + if( eDetail==FTS5_DETAIL_NONE ){ + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n); + }else{ + Fts5PoslistReader sReader; + for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader); + sReader.bEof==0; + sqlite3Fts5PoslistReaderNext(&sReader) + ){ + int iCol = FTS5_POS2COLUMN(sReader.iPos); + int iOff = FTS5_POS2OFFSET(sReader.iPos); + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n); + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IterNext(pIter); + } + } + sqlite3Fts5IterClose(pIter); + + *pCksum = cksum; + return rc; +} + + +/* +** This function is also purely an internal test. It does not contribute to +** FTS functionality, or even the integrity-check, in any way. +*/ +static void fts5TestTerm( + Fts5Index *p, + Fts5Buffer *pPrev, /* Previous term */ + const char *z, int n, /* Possibly new term to test */ + u64 expected, + u64 *pCksum +){ + int rc = p->rc; + if( pPrev->n==0 ){ + fts5BufferSet(&rc, pPrev, n, (const u8*)z); + }else + if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){ + u64 cksum3 = *pCksum; + const char *zTerm = (const char*)&pPrev->p[1]; /* term sans prefix-byte */ + int nTerm = pPrev->n-1; /* Size of zTerm in bytes */ + int iIdx = (pPrev->p[0] - FTS5_MAIN_PREFIX); + int flags = (iIdx==0 ? 0 : FTS5INDEX_QUERY_PREFIX); + u64 ck1 = 0; + u64 ck2 = 0; + + /* Check that the results returned for ASC and DESC queries are + ** the same. If not, call this corruption. */ + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, flags, &ck1); + if( rc==SQLITE_OK ){ + int f = flags|FTS5INDEX_QUERY_DESC; + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); + } + if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; + + /* If this is a prefix query, check that the results returned if the + ** the index is disabled are the same. In both ASC and DESC order. + ** + ** This check may only be performed if the hash table is empty. This + ** is because the hash table only supports a single scan query at + ** a time, and the multi-iter loop from which this function is called + ** is already performing such a scan. */ + if( p->nPendingData==0 ){ + if( iIdx>0 && rc==SQLITE_OK ){ + int f = flags|FTS5INDEX_QUERY_TEST_NOIDX; + ck2 = 0; + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); + if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; + } + if( iIdx>0 && rc==SQLITE_OK ){ + int f = flags|FTS5INDEX_QUERY_TEST_NOIDX|FTS5INDEX_QUERY_DESC; + ck2 = 0; + rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); + if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; + } + } + + cksum3 ^= ck1; + fts5BufferSet(&rc, pPrev, n, (const u8*)z); + + if( rc==SQLITE_OK && cksum3!=expected ){ + rc = FTS5_CORRUPT; + } + *pCksum = cksum3; + } + p->rc = rc; +} + +#else +# define fts5TestDlidxReverse(x,y,z) +# define fts5TestTerm(u,v,w,x,y,z) +#endif + +/* +** Check that: +** +** 1) All leaves of pSeg between iFirst and iLast (inclusive) exist and +** contain zero terms. +** 2) All leaves of pSeg between iNoRowid and iLast (inclusive) exist and +** contain zero rowids. +*/ +static void fts5IndexIntegrityCheckEmpty( + Fts5Index *p, + Fts5StructureSegment *pSeg, /* Segment to check internal consistency */ + int iFirst, + int iNoRowid, + int iLast +){ + int i; + + /* Now check that the iter.nEmpty leaves following the current leaf + ** (a) exist and (b) contain no terms. */ + for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){ + Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); + if( pLeaf ){ + if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT; + if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT; + } + fts5DataRelease(pLeaf); + } +} + +static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ + int iTermOff = 0; + int ii; + + Fts5Buffer buf1 = {0,0,0}; + Fts5Buffer buf2 = {0,0,0}; + + ii = pLeaf->szLeaf; + while( iinn && p->rc==SQLITE_OK ){ + int res; + int iOff; + int nIncr; + + ii += fts5GetVarint32(&pLeaf->p[ii], nIncr); + iTermOff += nIncr; + iOff = iTermOff; + + if( iOff>=pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else if( iTermOff==nIncr ){ + int nByte; + iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); + if( (iOff+nByte)>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); + } + }else{ + int nKeep, nByte; + iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep); + iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); + if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + buf1.n = nKeep; + fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); + } + + if( p->rc==SQLITE_OK ){ + res = fts5BufferCompare(&buf1, &buf2); + if( res<=0 ) p->rc = FTS5_CORRUPT; + } + } + fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p); + } + + fts5BufferFree(&buf1); + fts5BufferFree(&buf2); +} + +static void fts5IndexIntegrityCheckSegment( + Fts5Index *p, /* FTS5 backend object */ + Fts5StructureSegment *pSeg /* Segment to check internal consistency */ +){ + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pStmt = 0; + int rc2; + int iIdxPrevLeaf = pSeg->pgnoFirst-1; + int iDlidxPrevLeaf = pSeg->pgnoLast; + + if( pSeg->pgnoFirst==0 ) return; + + fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( + "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d", + pConfig->zDb, pConfig->zName, pSeg->iSegid + )); + + /* Iterate through the b-tree hierarchy. */ + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + i64 iRow; /* Rowid for this leaf */ + Fts5Data *pLeaf; /* Data for this leaf */ + + int nIdxTerm = sqlite3_column_bytes(pStmt, 1); + const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1); + int iIdxLeaf = sqlite3_column_int(pStmt, 2); + int bIdxDlidx = sqlite3_column_int(pStmt, 3); + + /* If the leaf in question has already been trimmed from the segment, + ** ignore this b-tree entry. Otherwise, load it into memory. */ + if( iIdxLeafpgnoFirst ) continue; + iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf); + pLeaf = fts5DataRead(p, iRow); + if( pLeaf==0 ) break; + + /* Check that the leaf contains at least one term, and that it is equal + ** to or larger than the split-key in zIdxTerm. Also check that if there + ** is also a rowid pointer within the leaf page header, it points to a + ** location before the term. */ + if( pLeaf->nn<=pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + int iOff; /* Offset of first term on leaf */ + int iRowidOff; /* Offset of first rowid on leaf */ + int nTerm; /* Size of term on leaf in bytes */ + int res; /* Comparison of term and split-key */ + + iOff = fts5LeafFirstTermOff(pLeaf); + iRowidOff = fts5LeafFirstRowidOff(pLeaf); + if( iRowidOff>=iOff ){ + p->rc = FTS5_CORRUPT; + }else{ + iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); + res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); + if( res==0 ) res = nTerm - nIdxTerm; + if( res<0 ) p->rc = FTS5_CORRUPT; + } + + fts5IntegrityCheckPgidx(p, pLeaf); + } + fts5DataRelease(pLeaf); + if( p->rc ) break; + + /* Now check that the iter.nEmpty leaves following the current leaf + ** (a) exist and (b) contain no terms. */ + fts5IndexIntegrityCheckEmpty( + p, pSeg, iIdxPrevLeaf+1, iDlidxPrevLeaf+1, iIdxLeaf-1 + ); + if( p->rc ) break; + + /* If there is a doclist-index, check that it looks right. */ + if( bIdxDlidx ){ + Fts5DlidxIter *pDlidx = 0; /* For iterating through doclist index */ + int iPrevLeaf = iIdxLeaf; + int iSegid = pSeg->iSegid; + int iPg = 0; + i64 iKey; + + for(pDlidx=fts5DlidxIterInit(p, 0, iSegid, iIdxLeaf); + fts5DlidxIterEof(p, pDlidx)==0; + fts5DlidxIterNext(p, pDlidx) + ){ + + /* Check any rowid-less pages that occur before the current leaf. */ + for(iPg=iPrevLeaf+1; iPgrc = FTS5_CORRUPT; + fts5DataRelease(pLeaf); + } + } + iPrevLeaf = fts5DlidxIterPgno(pDlidx); + + /* Check that the leaf page indicated by the iterator really does + ** contain the rowid suggested by the same. */ + iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf); + pLeaf = fts5DataRead(p, iKey); + if( pLeaf ){ + i64 iRowid; + int iRowidOff = fts5LeafFirstRowidOff(pLeaf); + ASSERT_SZLEAF_OK(pLeaf); + if( iRowidOff>=pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid); + if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT; + } + fts5DataRelease(pLeaf); + } + } + + iDlidxPrevLeaf = iPg; + fts5DlidxIterFree(pDlidx); + fts5TestDlidxReverse(p, iSegid, iIdxLeaf); + }else{ + iDlidxPrevLeaf = pSeg->pgnoLast; + /* TODO: Check there is no doclist index */ + } + + iIdxPrevLeaf = iIdxLeaf; + } + + rc2 = sqlite3_finalize(pStmt); + if( p->rc==SQLITE_OK ) p->rc = rc2; + + /* Page iter.iLeaf must now be the rightmost leaf-page in the segment */ +#if 0 + if( p->rc==SQLITE_OK && iter.iLeaf!=pSeg->pgnoLast ){ + p->rc = FTS5_CORRUPT; + } +#endif +} + + +/* +** Run internal checks to ensure that the FTS index (a) is internally +** consistent and (b) contains entries for which the XOR of the checksums +** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. +** +** Return SQLITE_CORRUPT if any of the internal checks fail, or if the +** checksum does not match. Return SQLITE_OK if all checks pass without +** error, or some other SQLite error code if another error (e.g. OOM) +** occurs. +*/ +static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ + int eDetail = p->pConfig->eDetail; + u64 cksum2 = 0; /* Checksum based on contents of indexes */ + Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ + Fts5Iter *pIter; /* Used to iterate through entire index */ + Fts5Structure *pStruct; /* Index structure */ + +#ifdef SQLITE_DEBUG + /* Used by extra internal tests only run if NDEBUG is not defined */ + u64 cksum3 = 0; /* Checksum based on contents of indexes */ + Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */ +#endif + const int flags = FTS5INDEX_QUERY_NOOUTPUT; + + /* Load the FTS index structure */ + pStruct = fts5StructureRead(p); + + /* Check that the internal nodes of each segment match the leaves */ + if( pStruct ){ + int iLvl, iSeg; + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; + fts5IndexIntegrityCheckSegment(p, pSeg); + } + } + } + + /* The cksum argument passed to this function is a checksum calculated + ** based on all expected entries in the FTS index (including prefix index + ** entries). This block checks that a checksum calculated based on the + ** actual contents of FTS index is identical. + ** + ** Two versions of the same checksum are calculated. The first (stack + ** variable cksum2) based on entries extracted from the full-text index + ** while doing a linear scan of each individual index in turn. + ** + ** As each term visited by the linear scans, a separate query for the + ** same term is performed. cksum3 is calculated based on the entries + ** extracted by these queries. + */ + for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, -1, 0, &pIter); + fts5MultiIterEof(p, pIter)==0; + fts5MultiIterNext(p, pIter, 0, 0) + ){ + int n; /* Size of term in bytes */ + i64 iPos = 0; /* Position read from poslist */ + int iOff = 0; /* Offset within poslist */ + i64 iRowid = fts5MultiIterRowid(pIter); + char *z = (char*)fts5MultiIterTerm(pIter, &n); + + /* If this is a new term, query for it. Update cksum3 with the results. */ + fts5TestTerm(p, &term, z, n, cksum2, &cksum3); + + if( eDetail==FTS5_DETAIL_NONE ){ + if( 0==fts5MultiIterIsEmpty(p, pIter) ){ + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n); + } + }else{ + poslist.n = 0; + fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); + while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ + int iCol = FTS5_POS2COLUMN(iPos); + int iTokOff = FTS5_POS2OFFSET(iPos); + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); + } + } + } + fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); + + fts5MultiIterFree(pIter); + if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; + + fts5StructureRelease(pStruct); +#ifdef SQLITE_DEBUG + fts5BufferFree(&term); +#endif + fts5BufferFree(&poslist); + return fts5IndexReturn(p); +} + +/************************************************************************* +************************************************************************** +** Below this point is the implementation of the fts5_decode() scalar +** function only. +*/ + +/* +** Decode a segment-data rowid from the %_data table. This function is +** the opposite of macro FTS5_SEGMENT_ROWID(). +*/ +static void fts5DecodeRowid( + i64 iRowid, /* Rowid from %_data table */ + int *piSegid, /* OUT: Segment id */ + int *pbDlidx, /* OUT: Dlidx flag */ + int *piHeight, /* OUT: Height */ + int *piPgno /* OUT: Page number */ +){ + *piPgno = (int)(iRowid & (((i64)1 << FTS5_DATA_PAGE_B) - 1)); + iRowid >>= FTS5_DATA_PAGE_B; + + *piHeight = (int)(iRowid & (((i64)1 << FTS5_DATA_HEIGHT_B) - 1)); + iRowid >>= FTS5_DATA_HEIGHT_B; + + *pbDlidx = (int)(iRowid & 0x0001); + iRowid >>= FTS5_DATA_DLI_B; + + *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); +} + +static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ + int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ + fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); + + if( iSegid==0 ){ + if( iKey==FTS5_AVERAGES_ROWID ){ + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} "); + }else{ + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}"); + } + } + else{ + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}", + bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno + ); + } +} + +static void fts5DebugStructure( + int *pRc, /* IN/OUT: error code */ + Fts5Buffer *pBuf, + Fts5Structure *p +){ + int iLvl, iSeg; /* Iterate through levels, segments */ + + for(iLvl=0; iLvlnLevel; iLvl++){ + Fts5StructureLevel *pLvl = &p->aLevel[iLvl]; + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, + " {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg + ); + for(iSeg=0; iSegnSeg; iSeg++){ + Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", + pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast + ); + } + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); + } +} + +/* +** This is part of the fts5_decode() debugging aid. +** +** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This +** function appends a human-readable representation of the same object +** to the buffer passed as the second argument. +*/ +static void fts5DecodeStructure( + int *pRc, /* IN/OUT: error code */ + Fts5Buffer *pBuf, + const u8 *pBlob, int nBlob +){ + int rc; /* Return code */ + Fts5Structure *p = 0; /* Decoded structure object */ + + rc = fts5StructureDecode(pBlob, nBlob, 0, &p); + if( rc!=SQLITE_OK ){ + *pRc = rc; + return; + } + + fts5DebugStructure(pRc, pBuf, p); + fts5StructureRelease(p); +} + +/* +** This is part of the fts5_decode() debugging aid. +** +** Arguments pBlob/nBlob contain an "averages" record. This function +** appends a human-readable representation of record to the buffer passed +** as the second argument. +*/ +static void fts5DecodeAverages( + int *pRc, /* IN/OUT: error code */ + Fts5Buffer *pBuf, + const u8 *pBlob, int nBlob +){ + int i = 0; + const char *zSpace = ""; + + while( i0 ){ + iOff = sqlite3Fts5GetVarint(a, (u64*)&iDocid); + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid); + } + while( iOffpStruct==0 || p->iStructVersion!=0 ); + if( fts5IndexDataVersion(p)!=p->iStructVersion ){ + fts5StructureInvalidate(p); + } + return fts5IndexReturn(p); +} + +#line 1 "fts5_main.c" +/* +** 2014 Jun 09 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This is an SQLite module implementing full-text search. +*/ + + +/* #include "fts5Int.h" */ + +/* +** This variable is set to false when running tests for which the on disk +** structures should not be corrupt. Otherwise, true. If it is false, extra +** assert() conditions in the fts5 code are activated - conditions that are +** only true if it is guaranteed that the fts5 database is not corrupt. +*/ +int sqlite3_fts5_may_be_corrupt = 1; + + +typedef struct Fts5Auxdata Fts5Auxdata; +typedef struct Fts5Auxiliary Fts5Auxiliary; +typedef struct Fts5Cursor Fts5Cursor; +typedef struct Fts5Sorter Fts5Sorter; +typedef struct Fts5Table Fts5Table; +typedef struct Fts5TokenizerModule Fts5TokenizerModule; + +/* +** NOTES ON TRANSACTIONS: +** +** SQLite invokes the following virtual table methods as transactions are +** opened and closed by the user: +** +** xBegin(): Start of a new transaction. +** xSync(): Initial part of two-phase commit. +** xCommit(): Final part of two-phase commit. +** xRollback(): Rollback the transaction. +** +** Anything that is required as part of a commit that may fail is performed +** in the xSync() callback. Current versions of SQLite ignore any errors +** returned by xCommit(). +** +** And as sub-transactions are opened/closed: +** +** xSavepoint(int S): Open savepoint S. +** xRelease(int S): Commit and close savepoint S. +** xRollbackTo(int S): Rollback to start of savepoint S. +** +** During a write-transaction the fts5_index.c module may cache some data +** in-memory. It is flushed to disk whenever xSync(), xRelease() or +** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo() +** is called. +** +** Additionally, if SQLITE_DEBUG is defined, an instance of the following +** structure is used to record the current transaction state. This information +** is not required, but it is used in the assert() statements executed by +** function fts5CheckTransactionState() (see below). +*/ +struct Fts5TransactionState { + int eState; /* 0==closed, 1==open, 2==synced */ + int iSavepoint; /* Number of open savepoints (0 -> none) */ +}; + +/* +** A single object of this type is allocated when the FTS5 module is +** registered with a database handle. It is used to store pointers to +** all registered FTS5 extensions - tokenizers and auxiliary functions. +*/ +struct Fts5Global { + fts5_api api; /* User visible part of object (see fts5.h) */ + sqlite3 *db; /* Associated database connection */ + i64 iNextId; /* Used to allocate unique cursor ids */ + Fts5Auxiliary *pAux; /* First in list of all aux. functions */ + Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */ + Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */ + Fts5Cursor *pCsr; /* First in list of all open cursors */ +}; + +/* +** Each auxiliary function registered with the FTS5 module is represented +** by an object of the following type. All such objects are stored as part +** of the Fts5Global.pAux list. +*/ +struct Fts5Auxiliary { + Fts5Global *pGlobal; /* Global context for this function */ + char *zFunc; /* Function name (nul-terminated) */ + void *pUserData; /* User-data pointer */ + fts5_extension_function xFunc; /* Callback function */ + void (*xDestroy)(void*); /* Destructor function */ + Fts5Auxiliary *pNext; /* Next registered auxiliary function */ +}; + +/* +** Each tokenizer module registered with the FTS5 module is represented +** by an object of the following type. All such objects are stored as part +** of the Fts5Global.pTok list. +*/ +struct Fts5TokenizerModule { + char *zName; /* Name of tokenizer */ + void *pUserData; /* User pointer passed to xCreate() */ + fts5_tokenizer x; /* Tokenizer functions */ + void (*xDestroy)(void*); /* Destructor function */ + Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ +}; + +/* +** Virtual-table object. +*/ +struct Fts5Table { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts5Config *pConfig; /* Virtual table configuration */ + Fts5Index *pIndex; /* Full-text index */ + Fts5Storage *pStorage; /* Document store */ + Fts5Global *pGlobal; /* Global (connection wide) data */ + Fts5Cursor *pSortCsr; /* Sort data from this cursor */ +#ifdef SQLITE_DEBUG + struct Fts5TransactionState ts; +#endif +}; + +struct Fts5MatchPhrase { + Fts5Buffer *pPoslist; /* Pointer to current poslist */ + int nTerm; /* Size of phrase in terms */ +}; + +/* +** pStmt: +** SELECT rowid, FROM ORDER BY +rank; +** +** aIdx[]: +** There is one entry in the aIdx[] array for each phrase in the query, +** the value of which is the offset within aPoslist[] following the last +** byte of the position list for the corresponding phrase. +*/ +struct Fts5Sorter { + sqlite3_stmt *pStmt; + i64 iRowid; /* Current rowid */ + const u8 *aPoslist; /* Position lists for current row */ + int nIdx; /* Number of entries in aIdx[] */ + int aIdx[1]; /* Offsets into aPoslist for current row */ +}; + + +/* +** Virtual-table cursor object. +** +** iSpecial: +** If this is a 'special' query (refer to function fts5SpecialMatch()), +** then this variable contains the result of the query. +** +** iFirstRowid, iLastRowid: +** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the +** cursor iterates in ascending order of rowids, iFirstRowid is the lower +** limit of rowids to return, and iLastRowid the upper. In other words, the +** WHERE clause in the user's query might have been: +** +** MATCH AND rowid BETWEEN $iFirstRowid AND $iLastRowid +** +** If the cursor iterates in descending order of rowid, iFirstRowid +** is the upper limit (i.e. the "first" rowid visited) and iLastRowid +** the lower. +*/ +struct Fts5Cursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */ + int *aColumnSize; /* Values for xColumnSize() */ + i64 iCsrId; /* Cursor id */ + + /* Zero from this point onwards on cursor reset */ + int ePlan; /* FTS5_PLAN_XXX value */ + int bDesc; /* True for "ORDER BY rowid DESC" queries */ + i64 iFirstRowid; /* Return no rowids earlier than this */ + i64 iLastRowid; /* Return no rowids later than this */ + sqlite3_stmt *pStmt; /* Statement used to read %_content */ + Fts5Expr *pExpr; /* Expression for MATCH queries */ + Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */ + int csrflags; /* Mask of cursor flags (see below) */ + i64 iSpecial; /* Result of special query */ + + /* "rank" function. Populated on demand from vtab.xColumn(). */ + char *zRank; /* Custom rank function */ + char *zRankArgs; /* Custom rank function args */ + Fts5Auxiliary *pRank; /* Rank callback (or NULL) */ + int nRankArg; /* Number of trailing arguments for rank() */ + sqlite3_value **apRankArg; /* Array of trailing arguments */ + sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */ + + /* Auxiliary data storage */ + Fts5Auxiliary *pAux; /* Currently executing extension function */ + Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */ + + /* Cache used by auxiliary functions xInst() and xInstCount() */ + Fts5PoslistReader *aInstIter; /* One for each phrase */ + int nInstAlloc; /* Size of aInst[] array (entries / 3) */ + int nInstCount; /* Number of phrase instances */ + int *aInst; /* 3 integers per phrase instance */ +}; + +/* +** Bits that make up the "idxNum" parameter passed indirectly by +** xBestIndex() to xFilter(). +*/ +#define FTS5_BI_MATCH 0x0001 /* MATCH ? */ +#define FTS5_BI_RANK 0x0002 /* rank MATCH ? */ +#define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */ +#define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */ +#define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */ + +#define FTS5_BI_ORDER_RANK 0x0020 +#define FTS5_BI_ORDER_ROWID 0x0040 +#define FTS5_BI_ORDER_DESC 0x0080 + +/* +** Values for Fts5Cursor.csrflags +*/ +#define FTS5CSR_EOF 0x01 +#define FTS5CSR_REQUIRE_CONTENT 0x02 +#define FTS5CSR_REQUIRE_DOCSIZE 0x04 +#define FTS5CSR_REQUIRE_INST 0x08 +#define FTS5CSR_FREE_ZRANK 0x10 +#define FTS5CSR_REQUIRE_RESEEK 0x20 +#define FTS5CSR_REQUIRE_POSLIST 0x40 + +#define BitFlagAllTest(x,y) (((x) & (y))==(y)) +#define BitFlagTest(x,y) (((x) & (y))!=0) + + +/* +** Macros to Set(), Clear() and Test() cursor flags. +*/ +#define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag)) +#define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag)) +#define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag)) + +struct Fts5Auxdata { + Fts5Auxiliary *pAux; /* Extension to which this belongs */ + void *pPtr; /* Pointer value */ + void(*xDelete)(void*); /* Destructor */ + Fts5Auxdata *pNext; /* Next object in linked list */ +}; + +#ifdef SQLITE_DEBUG +#define FTS5_BEGIN 1 +#define FTS5_SYNC 2 +#define FTS5_COMMIT 3 +#define FTS5_ROLLBACK 4 +#define FTS5_SAVEPOINT 5 +#define FTS5_RELEASE 6 +#define FTS5_ROLLBACKTO 7 +static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ + switch( op ){ + case FTS5_BEGIN: + assert( p->ts.eState==0 ); + p->ts.eState = 1; + p->ts.iSavepoint = -1; + break; + + case FTS5_SYNC: + assert( p->ts.eState==1 ); + p->ts.eState = 2; + break; + + case FTS5_COMMIT: + assert( p->ts.eState==2 ); + p->ts.eState = 0; + break; + + case FTS5_ROLLBACK: + assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 ); + p->ts.eState = 0; + break; + + case FTS5_SAVEPOINT: + assert( p->ts.eState==1 ); + assert( iSavepoint>=0 ); + assert( iSavepoint>p->ts.iSavepoint ); + p->ts.iSavepoint = iSavepoint; + break; + + case FTS5_RELEASE: + assert( p->ts.eState==1 ); + assert( iSavepoint>=0 ); + assert( iSavepoint<=p->ts.iSavepoint ); + p->ts.iSavepoint = iSavepoint-1; + break; + + case FTS5_ROLLBACKTO: + assert( p->ts.eState==1 ); + assert( iSavepoint>=0 ); + assert( iSavepoint<=p->ts.iSavepoint ); + p->ts.iSavepoint = iSavepoint; + break; + } +} +#else +# define fts5CheckTransactionState(x,y,z) +#endif + +/* +** Return true if pTab is a contentless table. +*/ +static int fts5IsContentless(Fts5Table *pTab){ + return pTab->pConfig->eContent==FTS5_CONTENT_NONE; +} + +/* +** Delete a virtual table handle allocated by fts5InitVtab(). +*/ +static void fts5FreeVtab(Fts5Table *pTab){ + if( pTab ){ + sqlite3Fts5IndexClose(pTab->pIndex); + sqlite3Fts5StorageClose(pTab->pStorage); + sqlite3Fts5ConfigFree(pTab->pConfig); + sqlite3_free(pTab); + } +} + +/* +** The xDisconnect() virtual table method. +*/ +static int fts5DisconnectMethod(sqlite3_vtab *pVtab){ + fts5FreeVtab((Fts5Table*)pVtab); + return SQLITE_OK; +} + +/* +** The xDestroy() virtual table method. +*/ +static int fts5DestroyMethod(sqlite3_vtab *pVtab){ + Fts5Table *pTab = (Fts5Table*)pVtab; + int rc = sqlite3Fts5DropAll(pTab->pConfig); + if( rc==SQLITE_OK ){ + fts5FreeVtab((Fts5Table*)pVtab); + } + return rc; +} + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the FTS3 virtual table. +** +** The argv[] array contains the following: +** +** argv[0] -> module name ("fts5") +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> "column name" and other module argument fields. +*/ +static int fts5InitVtab( + int bCreate, /* True for xCreate, false for xConnect */ + sqlite3 *db, /* The SQLite database connection */ + void *pAux, /* Hash table containing tokenizers */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ + char **pzErr /* Write any error message here */ +){ + Fts5Global *pGlobal = (Fts5Global*)pAux; + const char **azConfig = (const char**)argv; + int rc = SQLITE_OK; /* Return code */ + Fts5Config *pConfig = 0; /* Results of parsing argc/argv */ + Fts5Table *pTab = 0; /* New virtual table object */ + + /* Allocate the new vtab object and parse the configuration */ + pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table)); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr); + assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 ); + } + if( rc==SQLITE_OK ){ + pTab->pConfig = pConfig; + pTab->pGlobal = pGlobal; + } + + /* Open the index sub-system */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr); + } + + /* Open the storage sub-system */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageOpen( + pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr + ); + } + + /* Call sqlite3_declare_vtab() */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ConfigDeclareVtab(pConfig); + } + + /* Load the initial configuration */ + if( rc==SQLITE_OK ){ + assert( pConfig->pzErrmsg==0 ); + pConfig->pzErrmsg = pzErr; + rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); + sqlite3Fts5IndexRollback(pTab->pIndex); + pConfig->pzErrmsg = 0; + } + + if( rc!=SQLITE_OK ){ + fts5FreeVtab(pTab); + pTab = 0; + }else if( bCreate ){ + fts5CheckTransactionState(pTab, FTS5_BEGIN, 0); + } + *ppVTab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** The xConnect() and xCreate() methods for the virtual table. All the +** work is done in function fts5InitVtab(). +*/ +static int fts5ConnectMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr); +} +static int fts5CreateMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); +} + +/* +** The different query plans. +*/ +#define FTS5_PLAN_MATCH 1 /* ( MATCH ?) */ +#define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */ +#define FTS5_PLAN_SPECIAL 3 /* An internal query */ +#define FTS5_PLAN_SORTED_MATCH 4 /* ( MATCH ? ORDER BY rank) */ +#define FTS5_PLAN_SCAN 5 /* No usable constraint */ +#define FTS5_PLAN_ROWID 6 /* (rowid = ?) */ + +/* +** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this +** extension is currently being used by a version of SQLite too old to +** support index-info flags. In that case this function is a no-op. +*/ +static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ +#if SQLITE_VERSION_NUMBER>=3008012 +#ifndef SQLITE_CORE + if( sqlite3_libversion_number()>=3008012 ) +#endif + { + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; + } +#endif +} + +/* +** Implementation of the xBestIndex method for FTS5 tables. Within the +** WHERE constraint, it searches for the following: +** +** 1. A MATCH constraint against the special column. +** 2. A MATCH constraint against the "rank" column. +** 3. An == constraint against the rowid column. +** 4. A < or <= constraint against the rowid column. +** 5. A > or >= constraint against the rowid column. +** +** Within the ORDER BY, either: +** +** 5. ORDER BY rank [ASC|DESC] +** 6. ORDER BY rowid [ASC|DESC] +** +** Costs are assigned as follows: +** +** a) If an unusable MATCH operator is present in the WHERE clause, the +** cost is unconditionally set to 1e50 (a really big number). +** +** a) If a MATCH operator is present, the cost depends on the other +** constraints also present. As follows: +** +** * No other constraints: cost=1000.0 +** * One rowid range constraint: cost=750.0 +** * Both rowid range constraints: cost=500.0 +** * An == rowid constraint: cost=100.0 +** +** b) Otherwise, if there is no MATCH: +** +** * No other constraints: cost=1000000.0 +** * One rowid range constraint: cost=750000.0 +** * Both rowid range constraints: cost=250000.0 +** * An == rowid constraint: cost=10.0 +** +** Costs are not modified by the ORDER BY clause. +*/ +static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ + Fts5Table *pTab = (Fts5Table*)pVTab; + Fts5Config *pConfig = pTab->pConfig; + int idxFlags = 0; /* Parameter passed through to xFilter() */ + int bHasMatch; + int iNext; + int i; + + struct Constraint { + int op; /* Mask against sqlite3_index_constraint.op */ + int fts5op; /* FTS5 mask for idxFlags */ + int iCol; /* 0==rowid, 1==tbl, 2==rank */ + int omit; /* True to omit this if found */ + int iConsIndex; /* Index in pInfo->aConstraint[] */ + } aConstraint[] = { + {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, + FTS5_BI_MATCH, 1, 1, -1}, + {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, + FTS5_BI_RANK, 2, 1, -1}, + {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1}, + {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE, + FTS5_BI_ROWID_LE, 0, 0, -1}, + {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, + FTS5_BI_ROWID_GE, 0, 0, -1}, + }; + + int aColMap[3]; + aColMap[0] = -1; + aColMap[1] = pConfig->nCol; + aColMap[2] = pConfig->nCol+1; + + /* Set idxFlags flags for all WHERE clause terms that will be used. */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; + int j; + for(j=0; jiColumn==aColMap[pC->iCol] && p->op & pC->op ){ + if( p->usable ){ + pC->iConsIndex = i; + idxFlags |= pC->fts5op; + }else if( j==0 ){ + /* As there exists an unusable MATCH constraint this is an + ** unusable plan. Set a prohibitively high cost. */ + pInfo->estimatedCost = 1e50; + return SQLITE_OK; + } + } + } + } + + /* Set idxFlags flags for the ORDER BY clause */ + if( pInfo->nOrderBy==1 ){ + int iSort = pInfo->aOrderBy[0].iColumn; + if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){ + idxFlags |= FTS5_BI_ORDER_RANK; + }else if( iSort==-1 ){ + idxFlags |= FTS5_BI_ORDER_ROWID; + } + if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){ + pInfo->orderByConsumed = 1; + if( pInfo->aOrderBy[0].desc ){ + idxFlags |= FTS5_BI_ORDER_DESC; + } + } + } + + /* Calculate the estimated cost based on the flags set in idxFlags. */ + bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH); + if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){ + pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0; + if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo); + }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ + pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; + }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ + pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; + }else{ + pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; + } + + /* Assign argvIndex values to each constraint in use. */ + iNext = 1; + for(i=0; iiConsIndex>=0 ){ + pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; + pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit; + } + } + + pInfo->idxNum = idxFlags; + return SQLITE_OK; +} + +static int fts5NewTransaction(Fts5Table *pTab){ + Fts5Cursor *pCsr; + for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ + if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK; + } + return sqlite3Fts5StorageReset(pTab->pStorage); +} + +/* +** Implementation of xOpen method. +*/ +static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts5Table *pTab = (Fts5Table*)pVTab; + Fts5Config *pConfig = pTab->pConfig; + Fts5Cursor *pCsr = 0; /* New cursor object */ + int nByte; /* Bytes of space to allocate */ + int rc; /* Return code */ + + rc = fts5NewTransaction(pTab); + if( rc==SQLITE_OK ){ + nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); + pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); + if( pCsr ){ + Fts5Global *pGlobal = pTab->pGlobal; + memset(pCsr, 0, nByte); + pCsr->aColumnSize = (int*)&pCsr[1]; + pCsr->pNext = pGlobal->pCsr; + pGlobal->pCsr = pCsr; + pCsr->iCsrId = ++pGlobal->iNextId; + }else{ + rc = SQLITE_NOMEM; + } + } + *ppCsr = (sqlite3_vtab_cursor*)pCsr; + return rc; +} + +static int fts5StmtType(Fts5Cursor *pCsr){ + if( pCsr->ePlan==FTS5_PLAN_SCAN ){ + return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC; + } + return FTS5_STMT_LOOKUP; +} + +/* +** This function is called after the cursor passed as the only argument +** is moved to point at a different row. It clears all cached data +** specific to the previous row stored by the cursor object. +*/ +static void fts5CsrNewrow(Fts5Cursor *pCsr){ + CsrFlagSet(pCsr, + FTS5CSR_REQUIRE_CONTENT + | FTS5CSR_REQUIRE_DOCSIZE + | FTS5CSR_REQUIRE_INST + | FTS5CSR_REQUIRE_POSLIST + ); +} + +static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5Auxdata *pData; + Fts5Auxdata *pNext; + + sqlite3_free(pCsr->aInstIter); + sqlite3_free(pCsr->aInst); + if( pCsr->pStmt ){ + int eStmt = fts5StmtType(pCsr); + sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt); + } + if( pCsr->pSorter ){ + Fts5Sorter *pSorter = pCsr->pSorter; + sqlite3_finalize(pSorter->pStmt); + sqlite3_free(pSorter); + } + + if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){ + sqlite3Fts5ExprFree(pCsr->pExpr); + } + + for(pData=pCsr->pAuxdata; pData; pData=pNext){ + pNext = pData->pNext; + if( pData->xDelete ) pData->xDelete(pData->pPtr); + sqlite3_free(pData); + } + + sqlite3_finalize(pCsr->pRankArgStmt); + sqlite3_free(pCsr->apRankArg); + + if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){ + sqlite3_free(pCsr->zRank); + sqlite3_free(pCsr->zRankArgs); + } + + memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr)); +} + + +/* +** Close the cursor. For additional information see the documentation +** on the xClose method of the virtual table interface. +*/ +static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){ + if( pCursor ){ + Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + Fts5Cursor **pp; + + fts5FreeCursorComponents(pCsr); + /* Remove the cursor from the Fts5Global.pCsr list */ + for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext); + *pp = pCsr->pNext; + + sqlite3_free(pCsr); + } + return SQLITE_OK; +} + +static int fts5SorterNext(Fts5Cursor *pCsr){ + Fts5Sorter *pSorter = pCsr->pSorter; + int rc; + + rc = sqlite3_step(pSorter->pStmt); + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + CsrFlagSet(pCsr, FTS5CSR_EOF); + }else if( rc==SQLITE_ROW ){ + const u8 *a; + const u8 *aBlob; + int nBlob; + int i; + int iOff = 0; + rc = SQLITE_OK; + + pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0); + nBlob = sqlite3_column_bytes(pSorter->pStmt, 1); + aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1); + + /* nBlob==0 in detail=none mode. */ + if( nBlob>0 ){ + for(i=0; i<(pSorter->nIdx-1); i++){ + int iVal; + a += fts5GetVarint32(a, iVal); + iOff += iVal; + pSorter->aIdx[i] = iOff; + } + pSorter->aIdx[i] = &aBlob[nBlob] - a; + pSorter->aPoslist = a; + } + + fts5CsrNewrow(pCsr); + } + + return rc; +} + + +/* +** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors +** open on table pTab. +*/ +static void fts5TripCursors(Fts5Table *pTab){ + Fts5Cursor *pCsr; + for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ + if( pCsr->ePlan==FTS5_PLAN_MATCH + && pCsr->base.pVtab==(sqlite3_vtab*)pTab + ){ + CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK); + } + } +} + +/* +** If the REQUIRE_RESEEK flag is set on the cursor passed as the first +** argument, close and reopen all Fts5IndexIter iterators that the cursor +** is using. Then attempt to move the cursor to a rowid equal to or laster +** (in the cursors sort order - ASC or DESC) than the current rowid. +** +** If the new rowid is not equal to the old, set output parameter *pbSkip +** to 1 before returning. Otherwise, leave it unchanged. +** +** Return SQLITE_OK if successful or if no reseek was required, or an +** error code if an error occurred. +*/ +static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ + int rc = SQLITE_OK; + assert( *pbSkip==0 ); + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + int bDesc = pCsr->bDesc; + i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); + + rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); + if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ + *pbSkip = 1; + } + + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK); + fts5CsrNewrow(pCsr); + if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ + CsrFlagSet(pCsr, FTS5CSR_EOF); + *pbSkip = 1; + } + } + return rc; +} + + +/* +** Advance the cursor to the next row in the table that matches the +** search criteria. +** +** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned +** even if we reach end-of-file. The fts5EofMethod() will be called +** subsequently to determine whether or not an EOF was hit. +*/ +static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int rc; + + assert( (pCsr->ePlan<3)== + (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) + ); + assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); + + if( pCsr->ePlan<3 ){ + int bSkip = 0; + if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; + rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); + CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr)); + fts5CsrNewrow(pCsr); + }else{ + switch( pCsr->ePlan ){ + case FTS5_PLAN_SPECIAL: { + CsrFlagSet(pCsr, FTS5CSR_EOF); + rc = SQLITE_OK; + break; + } + + case FTS5_PLAN_SORTED_MATCH: { + rc = fts5SorterNext(pCsr); + break; + } + + default: + rc = sqlite3_step(pCsr->pStmt); + if( rc!=SQLITE_ROW ){ + CsrFlagSet(pCsr, FTS5CSR_EOF); + rc = sqlite3_reset(pCsr->pStmt); + }else{ + rc = SQLITE_OK; + } + break; + } + } + + return rc; +} + + +static int fts5PrepareStatement( + sqlite3_stmt **ppStmt, + Fts5Config *pConfig, + const char *zFmt, + ... +){ + sqlite3_stmt *pRet = 0; + int rc; + char *zSql; + va_list ap; + + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); + if( rc!=SQLITE_OK ){ + *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); + } + sqlite3_free(zSql); + } + + va_end(ap); + *ppStmt = pRet; + return rc; +} + +static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ + Fts5Config *pConfig = pTab->pConfig; + Fts5Sorter *pSorter; + int nPhrase; + int nByte; + int rc; + const char *zRank = pCsr->zRank; + const char *zRankArgs = pCsr->zRankArgs; + + nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); + nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); + pSorter = (Fts5Sorter*)sqlite3_malloc(nByte); + if( pSorter==0 ) return SQLITE_NOMEM; + memset(pSorter, 0, nByte); + pSorter->nIdx = nPhrase; + + /* TODO: It would be better to have some system for reusing statement + ** handles here, rather than preparing a new one for each query. But that + ** is not possible as SQLite reference counts the virtual table objects. + ** And since the statement required here reads from this very virtual + ** table, saving it creates a circular reference. + ** + ** If SQLite a built-in statement cache, this wouldn't be a problem. */ + rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, + "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", + pConfig->zDb, pConfig->zName, zRank, pConfig->zName, + (zRankArgs ? ", " : ""), + (zRankArgs ? zRankArgs : ""), + bDesc ? "DESC" : "ASC" + ); + + pCsr->pSorter = pSorter; + if( rc==SQLITE_OK ){ + assert( pTab->pSortCsr==0 ); + pTab->pSortCsr = pCsr; + rc = fts5SorterNext(pCsr); + pTab->pSortCsr = 0; + } + + if( rc!=SQLITE_OK ){ + sqlite3_finalize(pSorter->pStmt); + sqlite3_free(pSorter); + pCsr->pSorter = 0; + } + + return rc; +} + +static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ + int rc; + Fts5Expr *pExpr = pCsr->pExpr; + rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc); + if( sqlite3Fts5ExprEof(pExpr) ){ + CsrFlagSet(pCsr, FTS5CSR_EOF); + } + fts5CsrNewrow(pCsr); + return rc; +} + +/* +** Process a "special" query. A special query is identified as one with a +** MATCH expression that begins with a '*' character. The remainder of +** the text passed to the MATCH operator are used as the special query +** parameters. +*/ +static int fts5SpecialMatch( + Fts5Table *pTab, + Fts5Cursor *pCsr, + const char *zQuery +){ + int rc = SQLITE_OK; /* Return code */ + const char *z = zQuery; /* Special query text */ + int n; /* Number of bytes in text at z */ + + while( z[0]==' ' ) z++; + for(n=0; z[n] && z[n]!=' '; n++); + + assert( pTab->base.zErrMsg==0 ); + pCsr->ePlan = FTS5_PLAN_SPECIAL; + + if( 0==sqlite3_strnicmp("reads", z, n) ){ + pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex); + } + else if( 0==sqlite3_strnicmp("id", z, n) ){ + pCsr->iSpecial = pCsr->iCsrId; + } + else{ + /* An unrecognized directive. Return an error message. */ + pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); + rc = SQLITE_ERROR; + } + + return rc; +} + +/* +** Search for an auxiliary function named zName that can be used with table +** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary +** structure. Otherwise, if no such function exists, return NULL. +*/ +static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){ + Fts5Auxiliary *pAux; + + for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){ + if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux; + } + + /* No function of the specified name was found. Return 0. */ + return 0; +} + + +static int fts5FindRankFunction(Fts5Cursor *pCsr){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->pConfig; + int rc = SQLITE_OK; + Fts5Auxiliary *pAux = 0; + const char *zRank = pCsr->zRank; + const char *zRankArgs = pCsr->zRankArgs; + + if( zRankArgs ){ + char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); + if( zSql ){ + sqlite3_stmt *pStmt = 0; + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + int nByte; + pCsr->nRankArg = sqlite3_column_count(pStmt); + nByte = sizeof(sqlite3_value*)*pCsr->nRankArg; + pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte); + if( rc==SQLITE_OK ){ + int i; + for(i=0; inRankArg; i++){ + pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i); + } + } + pCsr->pRankArgStmt = pStmt; + }else{ + rc = sqlite3_finalize(pStmt); + assert( rc!=SQLITE_OK ); + } + } + } + } + + if( rc==SQLITE_OK ){ + pAux = fts5FindAuxiliary(pTab, zRank); + if( pAux==0 ){ + assert( pTab->base.zErrMsg==0 ); + pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); + rc = SQLITE_ERROR; + } + } + + pCsr->pRank = pAux; + return rc; +} + + +static int fts5CursorParseRank( + Fts5Config *pConfig, + Fts5Cursor *pCsr, + sqlite3_value *pRank +){ + int rc = SQLITE_OK; + if( pRank ){ + const char *z = (const char*)sqlite3_value_text(pRank); + char *zRank = 0; + char *zRankArgs = 0; + + if( z==0 ){ + if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs); + } + if( rc==SQLITE_OK ){ + pCsr->zRank = zRank; + pCsr->zRankArgs = zRankArgs; + CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK); + }else if( rc==SQLITE_ERROR ){ + pCsr->base.pVtab->zErrMsg = sqlite3_mprintf( + "parse error in rank function: %s", z + ); + } + }else{ + if( pConfig->zRank ){ + pCsr->zRank = (char*)pConfig->zRank; + pCsr->zRankArgs = (char*)pConfig->zRankArgs; + }else{ + pCsr->zRank = (char*)FTS5_DEFAULT_RANK; + pCsr->zRankArgs = 0; + } + } + return rc; +} + +static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ + if( pVal ){ + int eType = sqlite3_value_numeric_type(pVal); + if( eType==SQLITE_INTEGER ){ + return sqlite3_value_int64(pVal); + } + } + return iDefault; +} + +/* +** This is the xFilter interface for the virtual table. See +** the virtual table xFilter method documentation for additional +** information. +** +** There are three possible query strategies: +** +** 1. Full-text search using a MATCH operator. +** 2. A by-rowid lookup. +** 3. A full-table scan. +*/ +static int fts5FilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *zUnused, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->pConfig; + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int rc = SQLITE_OK; /* Error code */ + int iVal = 0; /* Counter for apVal[] */ + int bDesc; /* True if ORDER BY [rank|rowid] DESC */ + int bOrderByRank; /* True if ORDER BY rank */ + sqlite3_value *pMatch = 0; /* MATCH ? expression (or NULL) */ + sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */ + sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ + sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ + sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ + char **pzErrmsg = pConfig->pzErrmsg; + + UNUSED_PARAM(zUnused); + UNUSED_PARAM(nVal); + + if( pCsr->ePlan ){ + fts5FreeCursorComponents(pCsr); + memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); + } + + assert( pCsr->pStmt==0 ); + assert( pCsr->pExpr==0 ); + assert( pCsr->csrflags==0 ); + assert( pCsr->pRank==0 ); + assert( pCsr->zRank==0 ); + assert( pCsr->zRankArgs==0 ); + + assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg ); + pConfig->pzErrmsg = &pTab->base.zErrMsg; + + /* Decode the arguments passed through to this function. + ** + ** Note: The following set of if(...) statements must be in the same + ** order as the corresponding entries in the struct at the top of + ** fts5BestIndexMethod(). */ + if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++]; + if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++]; + assert( iVal==nVal ); + bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0); + pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0); + + /* Set the cursor upper and lower rowid limits. Only some strategies + ** actually use them. This is ok, as the xBestIndex() method leaves the + ** sqlite3_index_constraint.omit flag clear for range constraints + ** on the rowid field. */ + if( pRowidEq ){ + pRowidLe = pRowidGe = pRowidEq; + } + if( bDesc ){ + pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64); + pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64); + }else{ + pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64); + pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64); + } + + if( pTab->pSortCsr ){ + /* If pSortCsr is non-NULL, then this call is being made as part of + ** processing for a "... MATCH ORDER BY rank" query (ePlan is + ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will + ** return results to the user for this query. The current cursor + ** (pCursor) is used to execute the query issued by function + ** fts5CursorFirstSorted() above. */ + assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); + assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); + assert( pCsr->iLastRowid==LARGEST_INT64 ); + assert( pCsr->iFirstRowid==SMALLEST_INT64 ); + pCsr->ePlan = FTS5_PLAN_SOURCE; + pCsr->pExpr = pTab->pSortCsr->pExpr; + rc = fts5CursorFirst(pTab, pCsr, bDesc); + }else if( pMatch ){ + const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); + if( zExpr==0 ) zExpr = ""; + + rc = fts5CursorParseRank(pConfig, pCsr, pRank); + if( rc==SQLITE_OK ){ + if( zExpr[0]=='*' ){ + /* The user has issued a query of the form "MATCH '*...'". This + ** indicates that the MATCH expression is not a full text query, + ** but a request for an internal parameter. */ + rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]); + }else{ + char **pzErr = &pTab->base.zErrMsg; + rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr); + if( rc==SQLITE_OK ){ + if( bOrderByRank ){ + pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; + rc = fts5CursorFirstSorted(pTab, pCsr, bDesc); + }else{ + pCsr->ePlan = FTS5_PLAN_MATCH; + rc = fts5CursorFirst(pTab, pCsr, bDesc); + } + } + } + } + }else if( pConfig->zContent==0 ){ + *pConfig->pzErrmsg = sqlite3_mprintf( + "%s: table does not support scanning", pConfig->zName + ); + rc = SQLITE_ERROR; + }else{ + /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup + ** by rowid (ePlan==FTS5_PLAN_ROWID). */ + pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN); + rc = sqlite3Fts5StorageStmt( + pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg + ); + if( rc==SQLITE_OK ){ + if( pCsr->ePlan==FTS5_PLAN_ROWID ){ + sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); + }else{ + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid); + sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid); + } + rc = fts5NextMethod(pCursor); + } + } + + pConfig->pzErrmsg = pzErrmsg; + return rc; +} + +/* +** This is the xEof method of the virtual table. SQLite calls this +** routine to find out if it has reached the end of a result set. +*/ +static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0); +} + +/* +** Return the rowid that the cursor currently points to. +*/ +static i64 fts5CursorRowid(Fts5Cursor *pCsr){ + assert( pCsr->ePlan==FTS5_PLAN_MATCH + || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH + || pCsr->ePlan==FTS5_PLAN_SOURCE + ); + if( pCsr->pSorter ){ + return pCsr->pSorter->iRowid; + }else{ + return sqlite3Fts5ExprRowid(pCsr->pExpr); + } +} + +/* +** This is the xRowid method. The SQLite core calls this routine to +** retrieve the rowid for the current row of the result set. fts5 +** exposes %_content.rowid as the rowid for the virtual table. The +** rowid should be written to *pRowid. +*/ +static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int ePlan = pCsr->ePlan; + + assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); + switch( ePlan ){ + case FTS5_PLAN_SPECIAL: + *pRowid = 0; + break; + + case FTS5_PLAN_SOURCE: + case FTS5_PLAN_MATCH: + case FTS5_PLAN_SORTED_MATCH: + *pRowid = fts5CursorRowid(pCsr); + break; + + default: + *pRowid = sqlite3_column_int64(pCsr->pStmt, 0); + break; + } + + return SQLITE_OK; +} + +/* +** If the cursor requires seeking (bSeekRequired flag is set), seek it. +** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. +** +** If argument bErrormsg is true and an error occurs, an error message may +** be left in sqlite3_vtab.zErrMsg. +*/ +static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ + int rc = SQLITE_OK; + + /* If the cursor does not yet have a statement handle, obtain one now. */ + if( pCsr->pStmt==0 ){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + int eStmt = fts5StmtType(pCsr); + rc = sqlite3Fts5StorageStmt( + pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0) + ); + assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 ); + assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ); + } + + if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){ + assert( pCsr->pExpr ); + sqlite3_reset(pCsr->pStmt); + sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr)); + rc = sqlite3_step(pCsr->pStmt); + if( rc==SQLITE_ROW ){ + rc = SQLITE_OK; + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT); + }else{ + rc = sqlite3_reset(pCsr->pStmt); + if( rc==SQLITE_OK ){ + rc = FTS5_CORRUPT; + } + } + } + return rc; +} + +static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ + va_list ap; /* ... printf arguments */ + va_start(ap, zFormat); + assert( p->base.zErrMsg==0 ); + p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** This function is called to handle an FTS INSERT command. In other words, +** an INSERT statement of the form: +** +** INSERT INTO fts(fts) VALUES($pCmd) +** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal) +** +** Argument pVal is the value assigned to column "fts" by the INSERT +** statement. This function returns SQLITE_OK if successful, or an SQLite +** error code if an error occurs. +** +** The commands implemented by this function are documented in the "Special +** INSERT Directives" section of the documentation. It should be updated if +** more commands are added to this function. +*/ +static int fts5SpecialInsert( + Fts5Table *pTab, /* Fts5 table object */ + const char *zCmd, /* Text inserted into table-name column */ + sqlite3_value *pVal /* Value inserted into rank column */ +){ + Fts5Config *pConfig = pTab->pConfig; + int rc = SQLITE_OK; + int bError = 0; + + if( 0==sqlite3_stricmp("delete-all", zCmd) ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + fts5SetVtabError(pTab, + "'delete-all' may only be used with a " + "contentless or external content fts5 table" + ); + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage); + } + }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ + if( pConfig->eContent==FTS5_CONTENT_NONE ){ + fts5SetVtabError(pTab, + "'rebuild' may not be used with a contentless fts5 table" + ); + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5StorageRebuild(pTab->pStorage); + } + }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ + rc = sqlite3Fts5StorageOptimize(pTab->pStorage); + }else if( 0==sqlite3_stricmp("merge", zCmd) ){ + int nMerge = sqlite3_value_int(pVal); + rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); + }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ + rc = sqlite3Fts5StorageIntegrity(pTab->pStorage); +#ifdef SQLITE_DEBUG + }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ + pConfig->bPrefixIndex = sqlite3_value_int(pVal); +#endif + }else{ + rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError); + } + if( rc==SQLITE_OK ){ + if( bError ){ + rc = SQLITE_ERROR; + }else{ + rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0); + } + } + } + return rc; +} + +static int fts5SpecialDelete( + Fts5Table *pTab, + sqlite3_value **apVal +){ + int rc = SQLITE_OK; + int eType1 = sqlite3_value_type(apVal[1]); + if( eType1==SQLITE_INTEGER ){ + sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); + } + return rc; +} + +static void fts5StorageInsert( + int *pRc, + Fts5Table *pTab, + sqlite3_value **apVal, + i64 *piRowid +){ + int rc = *pRc; + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid); + } + *pRc = rc; +} + +/* +** This function is the implementation of the xUpdate callback used by +** FTS3 virtual tables. It is invoked by SQLite each time a row is to be +** inserted, updated or deleted. +** +** A delete specifies a single argument - the rowid of the row to remove. +** +** Update and insert operations pass: +** +** 1. The "old" rowid, or NULL. +** 2. The "new" rowid. +** 3. Values for each of the nCol matchable columns. +** 4. Values for the two hidden columns ( and "rank"). +*/ +static int fts5UpdateMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Size of argument array */ + sqlite3_value **apVal, /* Array of arguments */ + sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +){ + Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5Config *pConfig = pTab->pConfig; + int eType0; /* value_type() of apVal[0] */ + int rc = SQLITE_OK; /* Return code */ + + /* A transaction must be open when this is called. */ + assert( pTab->ts.eState==1 ); + + assert( pVtab->zErrMsg==0 ); + assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); + assert( nArg==1 + || sqlite3_value_type(apVal[1])==SQLITE_INTEGER + || sqlite3_value_type(apVal[1])==SQLITE_NULL + ); + assert( pTab->pConfig->pzErrmsg==0 ); + pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + + /* Put any active cursors into REQUIRE_SEEK state. */ + fts5TripCursors(pTab); + + eType0 = sqlite3_value_type(apVal[0]); + if( eType0==SQLITE_NULL + && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL + ){ + /* A "special" INSERT op. These are handled separately. */ + const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]); + if( pConfig->eContent!=FTS5_CONTENT_NORMAL + && 0==sqlite3_stricmp("delete", z) + ){ + rc = fts5SpecialDelete(pTab, apVal); + }else{ + rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); + } + }else{ + /* A regular INSERT, UPDATE or DELETE statement. The trick here is that + ** any conflict on the rowid value must be detected before any + ** modifications are made to the database file. There are 4 cases: + ** + ** 1) DELETE + ** 2) UPDATE (rowid not modified) + ** 3) UPDATE (rowid modified) + ** 4) INSERT + ** + ** Cases 3 and 4 may violate the rowid constraint. + */ + int eConflict = SQLITE_ABORT; + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + eConflict = sqlite3_vtab_on_conflict(pConfig->db); + } + + assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); + assert( nArg!=1 || eType0==SQLITE_INTEGER ); + + /* Filter out attempts to run UPDATE or DELETE on contentless tables. + ** This is not suported. */ + if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ + pTab->base.zErrMsg = sqlite3_mprintf( + "cannot %s contentless fts5 table: %s", + (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName + ); + rc = SQLITE_ERROR; + } + + /* DELETE */ + else if( nArg==1 ){ + i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); + } + + /* INSERT */ + else if( eType0!=SQLITE_INTEGER ){ + /* If this is a REPLACE, first remove the current entry (if any) */ + if( eConflict==SQLITE_REPLACE + && sqlite3_value_type(apVal[1])==SQLITE_INTEGER + ){ + i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + } + + /* UPDATE */ + else{ + i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ + i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ + if( iOld!=iNew ){ + if( eConflict==SQLITE_REPLACE ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + }else{ + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); + } + } + }else{ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + fts5StorageInsert(&rc, pTab, apVal, pRowid); + } + } + } + + pTab->pConfig->pzErrmsg = 0; + return rc; +} + +/* +** Implementation of xSync() method. +*/ +static int fts5SyncMethod(sqlite3_vtab *pVtab){ + int rc; + Fts5Table *pTab = (Fts5Table*)pVtab; + fts5CheckTransactionState(pTab, FTS5_SYNC, 0); + pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + fts5TripCursors(pTab); + rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); + pTab->pConfig->pzErrmsg = 0; + return rc; +} + +/* +** Implementation of xBegin() method. +*/ +static int fts5BeginMethod(sqlite3_vtab *pVtab){ + fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); + fts5NewTransaction((Fts5Table*)pVtab); + return SQLITE_OK; +} + +/* +** Implementation of xCommit() method. This is a no-op. The contents of +** the pending-terms hash-table have already been flushed into the database +** by fts5SyncMethod(). +*/ +static int fts5CommitMethod(sqlite3_vtab *pVtab){ + UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); + return SQLITE_OK; +} + +/* +** Implementation of xRollback(). Discard the contents of the pending-terms +** hash-table. Any changes made to the database are reverted by SQLite. +*/ +static int fts5RollbackMethod(sqlite3_vtab *pVtab){ + int rc; + Fts5Table *pTab = (Fts5Table*)pVtab; + fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); + rc = sqlite3Fts5StorageRollback(pTab->pStorage); + return rc; +} + +static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*); + +static void *fts5ApiUserData(Fts5Context *pCtx){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return pCsr->pAux->pUserData; +} + +static int fts5ApiColumnCount(Fts5Context *pCtx){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol; +} + +static int fts5ApiColumnTotalSize( + Fts5Context *pCtx, + int iCol, + sqlite3_int64 *pnToken +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken); +} + +static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); +} + +static int fts5ApiTokenize( + Fts5Context *pCtx, + const char *pText, int nText, + void *pUserData, + int (*xToken)(void*, int, const char*, int, int, int) +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + return sqlite3Fts5Tokenize( + pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken + ); +} + +static int fts5ApiPhraseCount(Fts5Context *pCtx){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return sqlite3Fts5ExprPhraseCount(pCsr->pExpr); +} + +static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); +} + +static int fts5ApiColumnText( + Fts5Context *pCtx, + int iCol, + const char **pz, + int *pn +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ + *pz = 0; + *pn = 0; + }else{ + rc = fts5SeekCursor(pCsr, 0); + if( rc==SQLITE_OK ){ + *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); + *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); + } + } + return rc; +} + +static int fts5CsrPoslist( + Fts5Cursor *pCsr, + int iPhrase, + const u8 **pa, + int *pn +){ + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + int rc = SQLITE_OK; + int bLive = (pCsr->pSorter==0); + + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5PoslistPopulator *aPopulator; + int i; + aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); + if( aPopulator==0 ) rc = SQLITE_NOMEM; + for(i=0; inCol && rc==SQLITE_OK; i++){ + int n; const char *z; + rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ExprPopulatePoslists( + pConfig, pCsr->pExpr, aPopulator, i, z, n + ); + } + } + sqlite3_free(aPopulator); + + if( pCsr->pSorter ){ + sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid); + } + } + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); + } + + if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ + Fts5Sorter *pSorter = pCsr->pSorter; + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + *pn = pSorter->aIdx[iPhrase] - i1; + *pa = &pSorter->aPoslist[i1]; + }else{ + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); + } + + return rc; +} + +/* +** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated +** correctly for the current view. Return SQLITE_OK if successful, or an +** SQLite error code otherwise. +*/ +static int fts5CacheInstArray(Fts5Cursor *pCsr){ + int rc = SQLITE_OK; + Fts5PoslistReader *aIter; /* One iterator for each phrase */ + int nIter; /* Number of iterators/phrases */ + + nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); + if( pCsr->aInstIter==0 ){ + int nByte = sizeof(Fts5PoslistReader) * nIter; + pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); + } + aIter = pCsr->aInstIter; + + if( aIter ){ + int nInst = 0; /* Number instances seen so far */ + int i; + + /* Initialize all iterators */ + for(i=0; i=pCsr->nInstAlloc ){ + pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; + aInst = (int*)sqlite3_realloc( + pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 + ); + if( aInst ){ + pCsr->aInst = aInst; + }else{ + rc = SQLITE_NOMEM; + break; + } + } + + aInst = &pCsr->aInst[3 * (nInst-1)]; + aInst[0] = iBest; + aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); + aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); + sqlite3Fts5PoslistReaderNext(&aIter[iBest]); + } + } + + pCsr->nInstCount = nInst; + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST); + } + return rc; +} + +static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + int rc = SQLITE_OK; + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 + || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){ + *pnInst = pCsr->nInstCount; + } + return rc; +} + +static int fts5ApiInst( + Fts5Context *pCtx, + int iIdx, + int *piPhrase, + int *piCol, + int *piOff +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + int rc = SQLITE_OK; + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 + || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) + ){ + if( iIdx<0 || iIdx>=pCsr->nInstCount ){ + rc = SQLITE_RANGE; +#if 0 + }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ + *piPhrase = pCsr->aInst[iIdx*3]; + *piCol = pCsr->aInst[iIdx*3 + 2]; + *piOff = -1; +#endif + }else{ + *piPhrase = pCsr->aInst[iIdx*3]; + *piCol = pCsr->aInst[iIdx*3 + 1]; + *piOff = pCsr->aInst[iIdx*3 + 2]; + } + } + return rc; +} + +static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){ + return fts5CursorRowid((Fts5Cursor*)pCtx); +} + +static int fts5ColumnSizeCb( + void *pContext, /* Pointer to int */ + int tflags, + const char *pUnused, /* Buffer containing token */ + int nUnused, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + int *pCnt = (int*)pContext; + UNUSED_PARAM2(pUnused, nUnused); + UNUSED_PARAM2(iUnused1, iUnused2); + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ + (*pCnt)++; + } + return SQLITE_OK; +} + +static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->pConfig; + int rc = SQLITE_OK; + + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){ + if( pConfig->bColumnsize ){ + i64 iRowid = fts5CursorRowid(pCsr); + rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize); + }else if( pConfig->zContent==0 ){ + int i; + for(i=0; inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + pCsr->aColumnSize[i] = -1; + } + } + }else{ + int i; + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + const char *z; int n; + void *p = (void*)(&pCsr->aColumnSize[i]); + pCsr->aColumnSize[i] = 0; + rc = fts5ApiColumnText(pCtx, i, &z, &n); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5Tokenize( + pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb + ); + } + } + } + } + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE); + } + if( iCol<0 ){ + int i; + *pnToken = 0; + for(i=0; inCol; i++){ + *pnToken += pCsr->aColumnSize[i]; + } + }else if( iColnCol ){ + *pnToken = pCsr->aColumnSize[iCol]; + }else{ + *pnToken = 0; + rc = SQLITE_RANGE; + } + return rc; +} + +/* +** Implementation of the xSetAuxdata() method. +*/ +static int fts5ApiSetAuxdata( + Fts5Context *pCtx, /* Fts5 context */ + void *pPtr, /* Pointer to save as auxdata */ + void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */ +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Auxdata *pData; + + /* Search through the cursors list of Fts5Auxdata objects for one that + ** corresponds to the currently executing auxiliary function. */ + for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){ + if( pData->pAux==pCsr->pAux ) break; + } + + if( pData ){ + if( pData->xDelete ){ + pData->xDelete(pData->pPtr); + } + }else{ + int rc = SQLITE_OK; + pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata)); + if( pData==0 ){ + if( xDelete ) xDelete(pPtr); + return rc; + } + pData->pAux = pCsr->pAux; + pData->pNext = pCsr->pAuxdata; + pCsr->pAuxdata = pData; + } + + pData->xDelete = xDelete; + pData->pPtr = pPtr; + return SQLITE_OK; +} + +static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Auxdata *pData; + void *pRet = 0; + + for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){ + if( pData->pAux==pCsr->pAux ) break; + } + + if( pData ){ + pRet = pData->pPtr; + if( bClear ){ + pData->pPtr = 0; + pData->xDelete = 0; + } + } + + return pRet; +} + +static void fts5ApiPhraseNext( + Fts5Context *pUnused, + Fts5PhraseIter *pIter, + int *piCol, int *piOff +){ + UNUSED_PARAM(pUnused); + if( pIter->a>=pIter->b ){ + *piCol = -1; + *piOff = -1; + }else{ + int iVal; + pIter->a += fts5GetVarint32(pIter->a, iVal); + if( iVal==1 ){ + pIter->a += fts5GetVarint32(pIter->a, iVal); + *piCol = iVal; + *piOff = 0; + pIter->a += fts5GetVarint32(pIter->a, iVal); + } + *piOff += (iVal-2); + } +} + +static int fts5ApiPhraseFirst( + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, + int *piCol, int *piOff +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + int n; + int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + *piCol = 0; + *piOff = 0; + fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); + } + return rc; +} + +static void fts5ApiPhraseNextColumn( + Fts5Context *pCtx, + Fts5PhraseIter *pIter, + int *piCol +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + if( pIter->a>=pIter->b ){ + *piCol = -1; + }else{ + int iIncr; + pIter->a += fts5GetVarint32(&pIter->a[0], iIncr); + *piCol += (iIncr-2); + } + }else{ + while( 1 ){ + int dummy; + if( pIter->a>=pIter->b ){ + *piCol = -1; + return; + } + if( pIter->a[0]==0x01 ) break; + pIter->a += fts5GetVarint32(pIter->a, dummy); + } + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); + } +} + +static int fts5ApiPhraseFirstColumn( + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, + int *piCol +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + Fts5Sorter *pSorter = pCsr->pSorter; + int n; + if( pSorter ){ + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + n = pSorter->aIdx[iPhrase] - i1; + pIter->a = &pSorter->aPoslist[i1]; + }else{ + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); + } + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + *piCol = 0; + fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + } + }else{ + int n; + rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + if( n<=0 ){ + *piCol = -1; + }else if( pIter->a[0]==0x01 ){ + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); + }else{ + *piCol = 0; + } + } + } + + return rc; +} + + +static int fts5ApiQueryPhrase(Fts5Context*, int, void*, + int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) +); + +static const Fts5ExtensionApi sFts5Api = { + 2, /* iVersion */ + fts5ApiUserData, + fts5ApiColumnCount, + fts5ApiRowCount, + fts5ApiColumnTotalSize, + fts5ApiTokenize, + fts5ApiPhraseCount, + fts5ApiPhraseSize, + fts5ApiInstCount, + fts5ApiInst, + fts5ApiRowid, + fts5ApiColumnText, + fts5ApiColumnSize, + fts5ApiQueryPhrase, + fts5ApiSetAuxdata, + fts5ApiGetAuxdata, + fts5ApiPhraseFirst, + fts5ApiPhraseNext, + fts5ApiPhraseFirstColumn, + fts5ApiPhraseNextColumn, +}; + +/* +** Implementation of API function xQueryPhrase(). +*/ +static int fts5ApiQueryPhrase( + Fts5Context *pCtx, + int iPhrase, + void *pUserData, + int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + int rc; + Fts5Cursor *pNew = 0; + + rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew); + if( rc==SQLITE_OK ){ + pNew->ePlan = FTS5_PLAN_MATCH; + pNew->iFirstRowid = SMALLEST_INT64; + pNew->iLastRowid = LARGEST_INT64; + pNew->base.pVtab = (sqlite3_vtab*)pTab; + rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr); + } + + if( rc==SQLITE_OK ){ + for(rc = fts5CursorFirst(pTab, pNew, 0); + rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0; + rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew) + ){ + rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + break; + } + } + } + + fts5CloseMethod((sqlite3_vtab_cursor*)pNew); + return rc; +} + +static void fts5ApiInvoke( + Fts5Auxiliary *pAux, + Fts5Cursor *pCsr, + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + assert( pCsr->pAux==0 ); + pCsr->pAux = pAux; + pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv); + pCsr->pAux = 0; +} + +static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){ + Fts5Cursor *pCsr; + for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ + if( pCsr->iCsrId==iCsrId ) break; + } + return pCsr; +} + +static void fts5ApiCallback( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + + Fts5Auxiliary *pAux; + Fts5Cursor *pCsr; + i64 iCsrId; + + assert( argc>=1 ); + pAux = (Fts5Auxiliary*)sqlite3_user_data(context); + iCsrId = sqlite3_value_int64(argv[0]); + + pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); + if( pCsr==0 ){ + char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else{ + fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); + } +} + + +/* +** Given cursor id iId, return a pointer to the corresponding Fts5Index +** object. Or NULL If the cursor id does not exist. +** +** If successful, set *ppConfig to point to the associated config object +** before returning. +*/ +static Fts5Index *sqlite3Fts5IndexFromCsrid( + Fts5Global *pGlobal, /* FTS5 global context for db handle */ + i64 iCsrId, /* Id of cursor to find */ + Fts5Config **ppConfig /* OUT: Configuration object */ +){ + Fts5Cursor *pCsr; + Fts5Table *pTab; + + pCsr = fts5CursorFromCsrid(pGlobal, iCsrId); + pTab = (Fts5Table*)pCsr->base.pVtab; + *ppConfig = pTab->pConfig; + + return pTab->pIndex; +} + +/* +** Return a "position-list blob" corresponding to the current position of +** cursor pCsr via sqlite3_result_blob(). A position-list blob contains +** the current position-list for each phrase in the query associated with +** cursor pCsr. +** +** A position-list blob begins with (nPhrase-1) varints, where nPhrase is +** the number of phrases in the query. Following the varints are the +** concatenated position lists for each phrase, in order. +** +** The first varint (if it exists) contains the size of the position list +** for phrase 0. The second (same disclaimer) contains the size of position +** list 1. And so on. There is no size field for the final position list, +** as it can be derived from the total size of the blob. +*/ +static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ + int i; + int rc = SQLITE_OK; + int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); + Fts5Buffer val; + + memset(&val, 0, sizeof(Fts5Buffer)); + switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + + /* Append the varints */ + for(i=0; i<(nPhrase-1); i++){ + const u8 *dummy; + int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); + } + + /* Append the position lists */ + for(i=0; ipExpr, i, &pPoslist); + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + } + break; + + case FTS5_DETAIL_COLUMNS: + + /* Append the varints */ + for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){ + const u8 *dummy; + int nByte; + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte); + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); + } + + /* Append the position lists */ + for(i=0; rc==SQLITE_OK && ipExpr, i, &pPoslist, &nPoslist); + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + } + break; + + default: + break; + } + + sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); + return rc; +} + +/* +** This is the xColumn method, called by SQLite to request a value from +** the row that the supplied cursor currently points to. +*/ +static int fts5ColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ +){ + Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->pConfig; + Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; + int rc = SQLITE_OK; + + assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); + + if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){ + if( iCol==pConfig->nCol ){ + sqlite3_result_int64(pCtx, pCsr->iSpecial); + } + }else + + if( iCol==pConfig->nCol ){ + /* User is requesting the value of the special column with the same name + ** as the table. Return the cursor integer id number. This value is only + ** useful in that it may be passed as the first argument to an FTS5 + ** auxiliary function. */ + sqlite3_result_int64(pCtx, pCsr->iCsrId); + }else if( iCol==pConfig->nCol+1 ){ + + /* The value of the "rank" column. */ + if( pCsr->ePlan==FTS5_PLAN_SOURCE ){ + fts5PoslistBlob(pCtx, pCsr); + }else if( + pCsr->ePlan==FTS5_PLAN_MATCH + || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH + ){ + if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ + fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); + } + } + }else if( !fts5IsContentless(pTab) ){ + rc = fts5SeekCursor(pCsr, 1); + if( rc==SQLITE_OK ){ + sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); + } + } + return rc; +} + + +/* +** This routine implements the xFindFunction method for the FTS3 +** virtual table. +*/ +static int fts5FindFunctionMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nUnused, /* Number of SQL function arguments */ + const char *zName, /* Name of SQL function */ + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ + void **ppArg /* OUT: User data for *pxFunc */ +){ + Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5Auxiliary *pAux; + + UNUSED_PARAM(nUnused); + pAux = fts5FindAuxiliary(pTab, zName); + if( pAux ){ + *pxFunc = fts5ApiCallback; + *ppArg = (void*)pAux; + return 1; + } + + /* No function of the specified name was found. Return 0. */ + return 0; +} + +/* +** Implementation of FTS5 xRename method. Rename an fts5 table. +*/ +static int fts5RenameMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + const char *zName /* New name of table */ +){ + Fts5Table *pTab = (Fts5Table*)pVtab; + return sqlite3Fts5StorageRename(pTab->pStorage, zName); +} + +/* +** The xSavepoint() method. +** +** Flush the contents of the pending-terms table to disk. +*/ +static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); + fts5TripCursors(pTab); + return sqlite3Fts5StorageSync(pTab->pStorage, 0); +} + +/* +** The xRelease() method. +** +** This is a no-op. +*/ +static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); + fts5TripCursors(pTab); + return sqlite3Fts5StorageSync(pTab->pStorage, 0); +} + +/* +** The xRollbackTo() method. +** +** Discard the contents of the pending terms table. +*/ +static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); + fts5TripCursors(pTab); + return sqlite3Fts5StorageRollback(pTab->pStorage); +} + +/* +** Register a new auxiliary function with global context pGlobal. +*/ +static int fts5CreateAux( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void *pUserData, /* User data for aux. function */ + fts5_extension_function xFunc, /* Aux. function implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ +){ + Fts5Global *pGlobal = (Fts5Global*)pApi; + int rc = sqlite3_overload_function(pGlobal->db, zName, -1); + if( rc==SQLITE_OK ){ + Fts5Auxiliary *pAux; + int nName; /* Size of zName in bytes, including \0 */ + int nByte; /* Bytes of space to allocate */ + + nName = (int)strlen(zName) + 1; + nByte = sizeof(Fts5Auxiliary) + nName; + pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte); + if( pAux ){ + memset(pAux, 0, nByte); + pAux->zFunc = (char*)&pAux[1]; + memcpy(pAux->zFunc, zName, nName); + pAux->pGlobal = pGlobal; + pAux->pUserData = pUserData; + pAux->xFunc = xFunc; + pAux->xDestroy = xDestroy; + pAux->pNext = pGlobal->pAux; + pGlobal->pAux = pAux; + }else{ + rc = SQLITE_NOMEM; + } + } + + return rc; +} + +/* +** Register a new tokenizer. This is the implementation of the +** fts5_api.xCreateTokenizer() method. +*/ +static int fts5CreateTokenizer( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void *pUserData, /* User data for aux. function */ + fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ + void(*xDestroy)(void*) /* Destructor for pUserData */ +){ + Fts5Global *pGlobal = (Fts5Global*)pApi; + Fts5TokenizerModule *pNew; + int nName; /* Size of zName and its \0 terminator */ + int nByte; /* Bytes of space to allocate */ + int rc = SQLITE_OK; + + nName = (int)strlen(zName) + 1; + nByte = sizeof(Fts5TokenizerModule) + nName; + pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte); + if( pNew ){ + memset(pNew, 0, nByte); + pNew->zName = (char*)&pNew[1]; + memcpy(pNew->zName, zName, nName); + pNew->pUserData = pUserData; + pNew->x = *pTokenizer; + pNew->xDestroy = xDestroy; + pNew->pNext = pGlobal->pTok; + pGlobal->pTok = pNew; + if( pNew->pNext==0 ){ + pGlobal->pDfltTok = pNew; + } + }else{ + rc = SQLITE_NOMEM; + } + + return rc; +} + +static Fts5TokenizerModule *fts5LocateTokenizer( + Fts5Global *pGlobal, + const char *zName +){ + Fts5TokenizerModule *pMod = 0; + + if( zName==0 ){ + pMod = pGlobal->pDfltTok; + }else{ + for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){ + if( sqlite3_stricmp(zName, pMod->zName)==0 ) break; + } + } + + return pMod; +} + +/* +** Find a tokenizer. This is the implementation of the +** fts5_api.xFindTokenizer() method. +*/ +static int fts5FindTokenizer( + fts5_api *pApi, /* Global context (one per db handle) */ + const char *zName, /* Name of new function */ + void **ppUserData, + fts5_tokenizer *pTokenizer /* Populate this object */ +){ + int rc = SQLITE_OK; + Fts5TokenizerModule *pMod; + + pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); + if( pMod ){ + *pTokenizer = pMod->x; + *ppUserData = pMod->pUserData; + }else{ + memset(pTokenizer, 0, sizeof(fts5_tokenizer)); + rc = SQLITE_ERROR; + } + + return rc; +} + +static int sqlite3Fts5GetTokenizer( + Fts5Global *pGlobal, + const char **azArg, + int nArg, + Fts5Tokenizer **ppTok, + fts5_tokenizer **ppTokApi, + char **pzErr +){ + Fts5TokenizerModule *pMod; + int rc = SQLITE_OK; + + pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]); + if( pMod==0 ){ + assert( nArg>0 ); + rc = SQLITE_ERROR; + *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); + }else{ + rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok); + *ppTokApi = &pMod->x; + if( rc!=SQLITE_OK && pzErr ){ + *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + } + } + + if( rc!=SQLITE_OK ){ + *ppTokApi = 0; + *ppTok = 0; + } + + return rc; +} + +static void fts5ModuleDestroy(void *pCtx){ + Fts5TokenizerModule *pTok, *pNextTok; + Fts5Auxiliary *pAux, *pNextAux; + Fts5Global *pGlobal = (Fts5Global*)pCtx; + + for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){ + pNextAux = pAux->pNext; + if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData); + sqlite3_free(pAux); + } + + for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){ + pNextTok = pTok->pNext; + if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData); + sqlite3_free(pTok); + } + + sqlite3_free(pGlobal); +} + +static void fts5Fts5Func( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apUnused /* Function arguments */ +){ + Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); + char buf[8]; + UNUSED_PARAM2(nArg, apUnused); + assert( nArg==0 ); + assert( sizeof(buf)>=sizeof(pGlobal) ); + memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); + sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); +} + +/* +** Implementation of fts5_source_id() function. +*/ +static void fts5SourceIdFunc( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apUnused /* Function arguments */ +){ + assert( nArg==0 ); + UNUSED_PARAM2(nArg, apUnused); + sqlite3_result_text(pCtx, "fts5: 2016-11-28 19:13:37 bbd85d235f7037c6a033a9690534391ffeacecc8", -1, SQLITE_TRANSIENT); +} + +static int fts5Init(sqlite3 *db){ + static const sqlite3_module fts5Mod = { + /* iVersion */ 2, + /* xCreate */ fts5CreateMethod, + /* xConnect */ fts5ConnectMethod, + /* xBestIndex */ fts5BestIndexMethod, + /* xDisconnect */ fts5DisconnectMethod, + /* xDestroy */ fts5DestroyMethod, + /* xOpen */ fts5OpenMethod, + /* xClose */ fts5CloseMethod, + /* xFilter */ fts5FilterMethod, + /* xNext */ fts5NextMethod, + /* xEof */ fts5EofMethod, + /* xColumn */ fts5ColumnMethod, + /* xRowid */ fts5RowidMethod, + /* xUpdate */ fts5UpdateMethod, + /* xBegin */ fts5BeginMethod, + /* xSync */ fts5SyncMethod, + /* xCommit */ fts5CommitMethod, + /* xRollback */ fts5RollbackMethod, + /* xFindFunction */ fts5FindFunctionMethod, + /* xRename */ fts5RenameMethod, + /* xSavepoint */ fts5SavepointMethod, + /* xRelease */ fts5ReleaseMethod, + /* xRollbackTo */ fts5RollbackToMethod, + }; + + int rc; + Fts5Global *pGlobal = 0; + + pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global)); + if( pGlobal==0 ){ + rc = SQLITE_NOMEM; + }else{ + void *p = (void*)pGlobal; + memset(pGlobal, 0, sizeof(Fts5Global)); + pGlobal->db = db; + pGlobal->api.iVersion = 2; + pGlobal->api.xCreateFunction = fts5CreateAux; + pGlobal->api.xCreateTokenizer = fts5CreateTokenizer; + pGlobal->api.xFindTokenizer = fts5FindTokenizer; + rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy); + if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db); + if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db); + if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api); + if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api); + if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 + ); + } + } + + /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file + ** fts5_test_mi.c is compiled and linked into the executable. And call + ** its entry point to enable the matchinfo() demo. */ +#ifdef SQLITE_FTS5_ENABLE_TEST_MI + if( rc==SQLITE_OK ){ + extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); + rc = sqlite3Fts5TestRegisterMatchinfo(db); + } +#endif + + return rc; +} + +/* +** The following functions are used to register the module with SQLite. If +** this module is being built as part of the SQLite core (SQLITE_CORE is +** defined), then sqlite3_open() will call sqlite3Fts5Init() directly. +** +** Or, if this module is being built as a loadable extension, +** sqlite3Fts5Init() is omitted and the two standard entry points +** sqlite3_fts_init() and sqlite3_fts5_init() defined instead. +*/ +#ifndef SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + return fts5Init(db); +} + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts5_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + return fts5Init(db); +} +#else +int sqlite3Fts5Init(sqlite3 *db){ + return fts5Init(db); +} +#endif + +#line 1 "fts5_storage.c" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ + + + +/* #include "fts5Int.h" */ + +struct Fts5Storage { + Fts5Config *pConfig; + Fts5Index *pIndex; + int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */ + i64 nTotalRow; /* Total number of rows in FTS table */ + i64 *aTotalSize; /* Total sizes of each column */ + sqlite3_stmt *aStmt[11]; +}; + + +#if FTS5_STMT_SCAN_ASC!=0 +# error "FTS5_STMT_SCAN_ASC mismatch" +#endif +#if FTS5_STMT_SCAN_DESC!=1 +# error "FTS5_STMT_SCAN_DESC mismatch" +#endif +#if FTS5_STMT_LOOKUP!=2 +# error "FTS5_STMT_LOOKUP mismatch" +#endif + +#define FTS5_STMT_INSERT_CONTENT 3 +#define FTS5_STMT_REPLACE_CONTENT 4 +#define FTS5_STMT_DELETE_CONTENT 5 +#define FTS5_STMT_REPLACE_DOCSIZE 6 +#define FTS5_STMT_DELETE_DOCSIZE 7 +#define FTS5_STMT_LOOKUP_DOCSIZE 8 +#define FTS5_STMT_REPLACE_CONFIG 9 +#define FTS5_STMT_SCAN 10 + +/* +** Prepare the two insert statements - Fts5Storage.pInsertContent and +** Fts5Storage.pInsertDocsize - if they have not already been prepared. +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageGetStmt( + Fts5Storage *p, /* Storage handle */ + int eStmt, /* FTS5_STMT_XXX constant */ + sqlite3_stmt **ppStmt, /* OUT: Prepared statement handle */ + char **pzErrMsg /* OUT: Error message (if any) */ +){ + int rc = SQLITE_OK; + + /* If there is no %_docsize table, there should be no requests for + ** statements to operate on it. */ + assert( p->pConfig->bColumnsize || ( + eStmt!=FTS5_STMT_REPLACE_DOCSIZE + && eStmt!=FTS5_STMT_DELETE_DOCSIZE + && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE + )); + + assert( eStmt>=0 && eStmtaStmt) ); + if( p->aStmt[eStmt]==0 ){ + const char *azStmt[] = { + "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC", + "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC", + "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */ + + "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */ + "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */ + "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */ + "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */ + "DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */ + + "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */ + + "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */ + "SELECT %s FROM %s AS T", /* SCAN */ + }; + Fts5Config *pC = p->pConfig; + char *zSql = 0; + + switch( eStmt ){ + case FTS5_STMT_SCAN: + zSql = sqlite3_mprintf(azStmt[eStmt], + pC->zContentExprlist, pC->zContent + ); + break; + + case FTS5_STMT_SCAN_ASC: + case FTS5_STMT_SCAN_DESC: + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, + pC->zContent, pC->zContentRowid, pC->zContentRowid, + pC->zContentRowid + ); + break; + + case FTS5_STMT_LOOKUP: + zSql = sqlite3_mprintf(azStmt[eStmt], + pC->zContentExprlist, pC->zContent, pC->zContentRowid + ); + break; + + case FTS5_STMT_INSERT_CONTENT: + case FTS5_STMT_REPLACE_CONTENT: { + int nCol = pC->nCol + 1; + char *zBind; + int i; + + zBind = sqlite3_malloc(1 + nCol*2); + if( zBind ){ + for(i=0; izDb, pC->zName, zBind); + sqlite3_free(zBind); + } + break; + } + + default: + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName); + break; + } + + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0); + sqlite3_free(zSql); + if( rc!=SQLITE_OK && pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); + } + } + } + + *ppStmt = p->aStmt[eStmt]; + sqlite3_reset(*ppStmt); + return rc; +} + + +static int fts5ExecPrintf( + sqlite3 *db, + char **pzErr, + const char *zFormat, + ... +){ + int rc; + va_list ap; /* ... printf arguments */ + char *zSql; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_exec(db, zSql, 0, 0, pzErr); + sqlite3_free(zSql); + } + + va_end(ap); + return rc; +} + +/* +** Drop all shadow tables. Return SQLITE_OK if successful or an SQLite error +** code otherwise. +*/ +static int sqlite3Fts5DropAll(Fts5Config *pConfig){ + int rc = fts5ExecPrintf(pConfig->db, 0, + "DROP TABLE IF EXISTS %Q.'%q_data';" + "DROP TABLE IF EXISTS %Q.'%q_idx';" + "DROP TABLE IF EXISTS %Q.'%q_config';", + pConfig->zDb, pConfig->zName, + pConfig->zDb, pConfig->zName, + pConfig->zDb, pConfig->zName + ); + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DROP TABLE IF EXISTS %Q.'%q_docsize';", + pConfig->zDb, pConfig->zName + ); + } + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DROP TABLE IF EXISTS %Q.'%q_content';", + pConfig->zDb, pConfig->zName + ); + } + return rc; +} + +static void fts5StorageRenameOne( + Fts5Config *pConfig, /* Current FTS5 configuration */ + int *pRc, /* IN/OUT: Error code */ + const char *zTail, /* Tail of table name e.g. "data", "config" */ + const char *zName /* New name of FTS5 table */ +){ + if( *pRc==SQLITE_OK ){ + *pRc = fts5ExecPrintf(pConfig->db, 0, + "ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';", + pConfig->zDb, pConfig->zName, zTail, zName, zTail + ); + } +} + +static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){ + Fts5Config *pConfig = pStorage->pConfig; + int rc = sqlite3Fts5StorageSync(pStorage, 1); + + fts5StorageRenameOne(pConfig, &rc, "data", zName); + fts5StorageRenameOne(pConfig, &rc, "idx", zName); + fts5StorageRenameOne(pConfig, &rc, "config", zName); + if( pConfig->bColumnsize ){ + fts5StorageRenameOne(pConfig, &rc, "docsize", zName); + } + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + fts5StorageRenameOne(pConfig, &rc, "content", zName); + } + return rc; +} + +/* +** Create the shadow table named zPost, with definition zDefn. Return +** SQLITE_OK if successful, or an SQLite error code otherwise. +*/ +static int sqlite3Fts5CreateTable( + Fts5Config *pConfig, /* FTS5 configuration */ + const char *zPost, /* Shadow table to create (e.g. "content") */ + const char *zDefn, /* Columns etc. for shadow table */ + int bWithout, /* True for without rowid */ + char **pzErr /* OUT: Error message */ +){ + int rc; + char *zErr = 0; + + rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", + pConfig->zDb, pConfig->zName, zPost, zDefn, +#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID + bWithout?" WITHOUT ROWID": +#endif + "" + ); + if( zErr ){ + *pzErr = sqlite3_mprintf( + "fts5: error creating shadow table %q_%s: %s", + pConfig->zName, zPost, zErr + ); + sqlite3_free(zErr); + } + + return rc; +} + +/* +** Open a new Fts5Index handle. If the bCreate argument is true, create +** and initialize the underlying tables +** +** If successful, set *pp to point to the new object and return SQLITE_OK. +** Otherwise, set *pp to NULL and return an SQLite error code. +*/ +static int sqlite3Fts5StorageOpen( + Fts5Config *pConfig, + Fts5Index *pIndex, + int bCreate, + Fts5Storage **pp, + char **pzErr /* OUT: Error message */ +){ + int rc = SQLITE_OK; + Fts5Storage *p; /* New object */ + int nByte; /* Bytes of space to allocate */ + + nByte = sizeof(Fts5Storage) /* Fts5Storage object */ + + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */ + *pp = p = (Fts5Storage*)sqlite3_malloc(nByte); + if( !p ) return SQLITE_NOMEM; + + memset(p, 0, nByte); + p->aTotalSize = (i64*)&p[1]; + p->pConfig = pConfig; + p->pIndex = pIndex; + + if( bCreate ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + int nDefn = 32 + pConfig->nCol*10; + char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10); + if( zDefn==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + int iOff; + sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); + iOff = (int)strlen(zDefn); + for(i=0; inCol; i++){ + sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); + iOff += (int)strlen(&zDefn[iOff]); + } + rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr); + } + sqlite3_free(zDefn); + } + + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = sqlite3Fts5CreateTable( + pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5CreateTable( + pConfig, "config", "k PRIMARY KEY, v", 1, pzErr + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION); + } + } + + if( rc ){ + sqlite3Fts5StorageClose(p); + *pp = 0; + } + return rc; +} + +/* +** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen(). +*/ +static int sqlite3Fts5StorageClose(Fts5Storage *p){ + int rc = SQLITE_OK; + if( p ){ + int i; + + /* Finalize all SQL statements */ + for(i=0; iaStmt); i++){ + sqlite3_finalize(p->aStmt[i]); + } + + sqlite3_free(p); + } + return rc; +} + +typedef struct Fts5InsertCtx Fts5InsertCtx; +struct Fts5InsertCtx { + Fts5Storage *pStorage; + int iCol; + int szCol; /* Size of column value in tokens */ +}; + +/* +** Tokenization callback used when inserting tokens into the FTS index. +*/ +static int fts5StorageInsertCallback( + void *pContext, /* Pointer to Fts5InsertCtx object */ + int tflags, + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext; + Fts5Index *pIdx = pCtx->pStorage->pIndex; + UNUSED_PARAM2(iUnused1, iUnused2); + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; + if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ + pCtx->szCol++; + } + return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); +} + +/* +** If a row with rowid iDel is present in the %_content table, add the +** delete-markers to the FTS index necessary to delete it. Do not actually +** remove the %_content row at this time though. +*/ +static int fts5StorageDeleteFromIndex( + Fts5Storage *p, + i64 iDel, + sqlite3_value **apVal +){ + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ + int rc; /* Return code */ + int rc2; /* sqlite3_reset() return code */ + int iCol; + Fts5InsertCtx ctx; + + if( apVal==0 ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pSeek, 1, iDel); + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ + return sqlite3_reset(pSeek); + } + } + + ctx.pStorage = p; + ctx.iCol = -1; + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); + for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ + if( pConfig->abUnindexed[iCol-1]==0 ){ + const char *zText; + int nText; + if( pSeek ){ + zText = (const char*)sqlite3_column_text(pSeek, iCol); + nText = sqlite3_column_bytes(pSeek, iCol); + }else{ + zText = (const char*)sqlite3_value_text(apVal[iCol-1]); + nText = sqlite3_value_bytes(apVal[iCol-1]); + } + ctx.szCol = 0; + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, + zText, nText, (void*)&ctx, fts5StorageInsertCallback + ); + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + } + } + p->nTotalRow--; + + rc2 = sqlite3_reset(pSeek); + if( rc==SQLITE_OK ) rc = rc2; + return rc; +} + + +/* +** Insert a record into the %_docsize table. Specifically, do: +** +** INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf); +** +** If there is no %_docsize table (as happens if the columnsize=0 option +** is specified when the FTS5 table is created), this function is a no-op. +*/ +static int fts5StorageInsertDocsize( + Fts5Storage *p, /* Storage module to write to */ + i64 iRowid, /* id value */ + Fts5Buffer *pBuf /* sz value */ +){ + int rc = SQLITE_OK; + if( p->pConfig->bColumnsize ){ + sqlite3_stmt *pReplace = 0; + rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pReplace, 1, iRowid); + sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + } + return rc; +} + +/* +** Load the contents of the "averages" record from disk into the +** p->nTotalRow and p->aTotalSize[] variables. If successful, and if +** argument bCache is true, set the p->bTotalsValid flag to indicate +** that the contents of aTotalSize[] and nTotalRow are valid until +** further notice. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){ + int rc = SQLITE_OK; + if( p->bTotalsValid==0 ){ + rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize); + p->bTotalsValid = bCache; + } + return rc; +} + +/* +** Store the current contents of the p->nTotalRow and p->aTotalSize[] +** variables in the "averages" record on disk. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageSaveTotals(Fts5Storage *p){ + int nCol = p->pConfig->nCol; + int i; + Fts5Buffer buf; + int rc = SQLITE_OK; + memset(&buf, 0, sizeof(buf)); + + sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow); + for(i=0; iaTotalSize[i]); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n); + } + sqlite3_free(buf.p); + + return rc; +} + +/* +** Remove a row from the FTS table. +*/ +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ + Fts5Config *pConfig = p->pConfig; + int rc; + sqlite3_stmt *pDel = 0; + + assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 ); + rc = fts5StorageLoadTotals(p, 1); + + /* Delete the index records */ + if( rc==SQLITE_OK ){ + rc = fts5StorageDeleteFromIndex(p, iDel, apVal); + } + + /* Delete the %_docsize record */ + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDel, 1, iDel); + sqlite3_step(pDel); + rc = sqlite3_reset(pDel); + } + } + + /* Delete the %_content record */ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ + if( rc==SQLITE_OK ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0); + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDel, 1, iDel); + sqlite3_step(pDel); + rc = sqlite3_reset(pDel); + } + } + + /* Write the averages record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageSaveTotals(p); + } + + return rc; +} + +/* +** Delete all entries in the FTS5 index. +*/ +static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ + Fts5Config *pConfig = p->pConfig; + int rc; + + /* Delete the contents of the %_data and %_docsize tables. */ + rc = fts5ExecPrintf(pConfig->db, 0, + "DELETE FROM %Q.'%q_data';" + "DELETE FROM %Q.'%q_idx';", + pConfig->zDb, pConfig->zName, + pConfig->zDb, pConfig->zName + ); + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + rc = fts5ExecPrintf(pConfig->db, 0, + "DELETE FROM %Q.'%q_docsize';", + pConfig->zDb, pConfig->zName + ); + } + + /* Reinitialize the %_data table. This call creates the initial structure + ** and averages records. */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexReinit(p->pIndex); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION); + } + return rc; +} + +static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ + Fts5Buffer buf = {0,0,0}; + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pScan = 0; + Fts5InsertCtx ctx; + int rc; + + memset(&ctx, 0, sizeof(Fts5InsertCtx)); + ctx.pStorage = p; + rc = sqlite3Fts5StorageDeleteAll(p); + if( rc==SQLITE_OK ){ + rc = fts5StorageLoadTotals(p, 1); + } + + if( rc==SQLITE_OK ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ + i64 iRowid = sqlite3_column_int64(pScan, 0); + + sqlite3Fts5BufferZero(&buf); + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); + for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ + ctx.szCol = 0; + if( pConfig->abUnindexed[ctx.iCol]==0 ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_column_text(pScan, ctx.iCol+1), + sqlite3_column_bytes(pScan, ctx.iCol+1), + (void*)&ctx, + fts5StorageInsertCallback + ); + } + sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); + p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; + } + p->nTotalRow++; + + if( rc==SQLITE_OK ){ + rc = fts5StorageInsertDocsize(p, iRowid, &buf); + } + } + sqlite3_free(buf.p); + + /* Write the averages record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageSaveTotals(p); + } + return rc; +} + +static int sqlite3Fts5StorageOptimize(Fts5Storage *p){ + return sqlite3Fts5IndexOptimize(p->pIndex); +} + +static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){ + return sqlite3Fts5IndexMerge(p->pIndex, nMerge); +} + +static int sqlite3Fts5StorageReset(Fts5Storage *p){ + return sqlite3Fts5IndexReset(p->pIndex); +} + +/* +** Allocate a new rowid. This is used for "external content" tables when +** a NULL value is inserted into the rowid column. The new rowid is allocated +** by inserting a dummy row into the %_docsize table. The dummy will be +** overwritten later. +** +** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In +** this case the user is required to provide a rowid explicitly. +*/ +static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ + int rc = SQLITE_MISMATCH; + if( p->pConfig->bColumnsize ){ + sqlite3_stmt *pReplace = 0; + rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_null(pReplace, 1); + sqlite3_bind_null(pReplace, 2); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + if( rc==SQLITE_OK ){ + *piRowid = sqlite3_last_insert_rowid(p->pConfig->db); + } + } + return rc; +} + +/* +** Insert a new row into the FTS content table. +*/ +static int sqlite3Fts5StorageContentInsert( + Fts5Storage *p, + sqlite3_value **apVal, + i64 *piRowid +){ + Fts5Config *pConfig = p->pConfig; + int rc = SQLITE_OK; + + /* Insert the new row into the %_content table. */ + if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ + if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){ + *piRowid = sqlite3_value_int64(apVal[1]); + }else{ + rc = fts5StorageNewRowid(p, piRowid); + } + }else{ + sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */ + int i; /* Counter variable */ + rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); + for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ + rc = sqlite3_bind_value(pInsert, i, apVal[i]); + } + if( rc==SQLITE_OK ){ + sqlite3_step(pInsert); + rc = sqlite3_reset(pInsert); + } + *piRowid = sqlite3_last_insert_rowid(pConfig->db); + } + + return rc; +} + +/* +** Insert new entries into the FTS index and %_docsize table. +*/ +static int sqlite3Fts5StorageIndexInsert( + Fts5Storage *p, + sqlite3_value **apVal, + i64 iRowid +){ + Fts5Config *pConfig = p->pConfig; + int rc = SQLITE_OK; /* Return code */ + Fts5InsertCtx ctx; /* Tokenization callback context object */ + Fts5Buffer buf; /* Buffer used to build up %_docsize blob */ + + memset(&buf, 0, sizeof(Fts5Buffer)); + ctx.pStorage = p; + rc = fts5StorageLoadTotals(p, 1); + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); + } + for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ + ctx.szCol = 0; + if( pConfig->abUnindexed[ctx.iCol]==0 ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_value_text(apVal[ctx.iCol+2]), + sqlite3_value_bytes(apVal[ctx.iCol+2]), + (void*)&ctx, + fts5StorageInsertCallback + ); + } + sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); + p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; + } + p->nTotalRow++; + + /* Write the %_docsize record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageInsertDocsize(p, iRowid, &buf); + } + sqlite3_free(buf.p); + + /* Write the averages record */ + if( rc==SQLITE_OK ){ + rc = fts5StorageSaveTotals(p); + } + + return rc; +} + +static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){ + Fts5Config *pConfig = p->pConfig; + char *zSql; + int rc; + + zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'", + pConfig->zDb, pConfig->zName, zSuffix + ); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pCnt = 0; + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pCnt, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pCnt) ){ + *pnRow = sqlite3_column_int64(pCnt, 0); + } + rc = sqlite3_finalize(pCnt); + } + } + + sqlite3_free(zSql); + return rc; +} + +/* +** Context object used by sqlite3Fts5StorageIntegrity(). +*/ +typedef struct Fts5IntegrityCtx Fts5IntegrityCtx; +struct Fts5IntegrityCtx { + i64 iRowid; + int iCol; + int szCol; + u64 cksum; + Fts5Termset *pTermset; + Fts5Config *pConfig; +}; + + +/* +** Tokenization callback used by integrity check. +*/ +static int fts5StorageIntegrityCallback( + void *pContext, /* Pointer to Fts5IntegrityCtx object */ + int tflags, + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ +){ + Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext; + Fts5Termset *pTermset = pCtx->pTermset; + int bPresent; + int ii; + int rc = SQLITE_OK; + int iPos; + int iCol; + + UNUSED_PARAM2(iUnused1, iUnused2); + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; + + if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ + pCtx->szCol++; + } + + switch( pCtx->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + iPos = pCtx->szCol-1; + iCol = pCtx->iCol; + break; + + case FTS5_DETAIL_COLUMNS: + iPos = pCtx->iCol; + iCol = 0; + break; + + default: + assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE ); + iPos = 0; + iCol = 0; + break; + } + + rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent); + if( rc==SQLITE_OK && bPresent==0 ){ + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( + pCtx->iRowid, iCol, iPos, 0, pToken, nToken + ); + } + + for(ii=0; rc==SQLITE_OK && iipConfig->nPrefix; ii++){ + const int nChar = pCtx->pConfig->aPrefix[ii]; + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); + if( nByte ){ + rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent); + if( bPresent==0 ){ + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( + pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte + ); + } + } + } + + return rc; +} + +/* +** Check that the contents of the FTS index match that of the %_content +** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return +** some other SQLite error code if an error occurs while attempting to +** determine this. +*/ +static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ + Fts5Config *pConfig = p->pConfig; + int rc; /* Return code */ + int *aColSize; /* Array of size pConfig->nCol */ + i64 *aTotalSize; /* Array of size pConfig->nCol */ + Fts5IntegrityCtx ctx; + sqlite3_stmt *pScan; + + memset(&ctx, 0, sizeof(Fts5IntegrityCtx)); + ctx.pConfig = p->pConfig; + aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64))); + if( !aTotalSize ) return SQLITE_NOMEM; + aColSize = (int*)&aTotalSize[pConfig->nCol]; + memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol); + + /* Generate the expected index checksum based on the contents of the + ** %_content table. This block stores the checksum in ctx.cksum. */ + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); + if( rc==SQLITE_OK ){ + int rc2; + while( SQLITE_ROW==sqlite3_step(pScan) ){ + int i; + ctx.iRowid = sqlite3_column_int64(pScan, 0); + ctx.szCol = 0; + if( pConfig->bColumnsize ){ + rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); + } + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pConfig->abUnindexed[i] ) continue; + ctx.iCol = i; + ctx.szCol = 0; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_column_text(pScan, i+1), + sqlite3_column_bytes(pScan, i+1), + (void*)&ctx, + fts5StorageIntegrityCallback + ); + } + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ + rc = FTS5_CORRUPT; + } + aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } + } + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + + if( rc!=SQLITE_OK ) break; + } + rc2 = sqlite3_reset(pScan); + if( rc==SQLITE_OK ) rc = rc2; + } + + /* Test that the "totals" (sometimes called "averages") record looks Ok */ + if( rc==SQLITE_OK ){ + int i; + rc = fts5StorageLoadTotals(p, 0); + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; + } + } + + /* Check that the %_docsize and %_content tables contain the expected + ** number of rows. */ + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "content", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "docsize", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } + + /* Pass the expected checksum down to the FTS index module. It will + ** verify, amongst other things, that it matches the checksum generated by + ** inspecting the index itself. */ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum); + } + + sqlite3_free(aTotalSize); + return rc; +} + +/* +** Obtain an SQLite statement handle that may be used to read data from the +** %_content table. +*/ +static int sqlite3Fts5StorageStmt( + Fts5Storage *p, + int eStmt, + sqlite3_stmt **pp, + char **pzErrMsg +){ + int rc; + assert( eStmt==FTS5_STMT_SCAN_ASC + || eStmt==FTS5_STMT_SCAN_DESC + || eStmt==FTS5_STMT_LOOKUP + ); + rc = fts5StorageGetStmt(p, eStmt, pp, pzErrMsg); + if( rc==SQLITE_OK ){ + assert( p->aStmt[eStmt]==*pp ); + p->aStmt[eStmt] = 0; + } + return rc; +} + +/* +** Release an SQLite statement handle obtained via an earlier call to +** sqlite3Fts5StorageStmt(). The eStmt parameter passed to this function +** must match that passed to the sqlite3Fts5StorageStmt() call. +*/ +static void sqlite3Fts5StorageStmtRelease( + Fts5Storage *p, + int eStmt, + sqlite3_stmt *pStmt +){ + assert( eStmt==FTS5_STMT_SCAN_ASC + || eStmt==FTS5_STMT_SCAN_DESC + || eStmt==FTS5_STMT_LOOKUP + ); + if( p->aStmt[eStmt]==0 ){ + sqlite3_reset(pStmt); + p->aStmt[eStmt] = pStmt; + }else{ + sqlite3_finalize(pStmt); + } +} + +static int fts5StorageDecodeSizeArray( + int *aCol, int nCol, /* Array to populate */ + const u8 *aBlob, int nBlob /* Record to read varints from */ +){ + int i; + int iOff = 0; + for(i=0; i=nBlob ) return 1; + iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]); + } + return (iOff!=nBlob); +} + +/* +** Argument aCol points to an array of integers containing one entry for +** each table column. This function reads the %_docsize record for the +** specified rowid and populates aCol[] with the results. +** +** An SQLite error code is returned if an error occurs, or SQLITE_OK +** otherwise. +*/ +static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ + int nCol = p->pConfig->nCol; /* Number of user columns in table */ + sqlite3_stmt *pLookup = 0; /* Statement to query %_docsize */ + int rc; /* Return Code */ + + assert( p->pConfig->bColumnsize ); + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0); + if( rc==SQLITE_OK ){ + int bCorrupt = 1; + sqlite3_bind_int64(pLookup, 1, iRowid); + if( SQLITE_ROW==sqlite3_step(pLookup) ){ + const u8 *aBlob = sqlite3_column_blob(pLookup, 0); + int nBlob = sqlite3_column_bytes(pLookup, 0); + if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){ + bCorrupt = 0; + } + } + rc = sqlite3_reset(pLookup); + if( bCorrupt && rc==SQLITE_OK ){ + rc = FTS5_CORRUPT; + } + } + + return rc; +} + +static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){ + int rc = fts5StorageLoadTotals(p, 0); + if( rc==SQLITE_OK ){ + *pnToken = 0; + if( iCol<0 ){ + int i; + for(i=0; ipConfig->nCol; i++){ + *pnToken += p->aTotalSize[i]; + } + }else if( iColpConfig->nCol ){ + *pnToken = p->aTotalSize[iCol]; + }else{ + rc = SQLITE_RANGE; + } + } + return rc; +} + +static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ + int rc = fts5StorageLoadTotals(p, 0); + if( rc==SQLITE_OK ){ + *pnRow = p->nTotalRow; + } + return rc; +} + +/* +** Flush any data currently held in-memory to disk. +*/ +static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){ + if( bCommit && p->bTotalsValid ){ + int rc = fts5StorageSaveTotals(p); + p->bTotalsValid = 0; + if( rc!=SQLITE_OK ) return rc; + } + return sqlite3Fts5IndexSync(p->pIndex, bCommit); +} + +static int sqlite3Fts5StorageRollback(Fts5Storage *p){ + p->bTotalsValid = 0; + return sqlite3Fts5IndexRollback(p->pIndex); +} + +static int sqlite3Fts5StorageConfigValue( + Fts5Storage *p, + const char *z, + sqlite3_value *pVal, + int iVal +){ + sqlite3_stmt *pReplace = 0; + int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_text(pReplace, 1, z, -1, SQLITE_STATIC); + if( pVal ){ + sqlite3_bind_value(pReplace, 2, pVal); + }else{ + sqlite3_bind_int(pReplace, 2, iVal); + } + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + if( rc==SQLITE_OK && pVal ){ + int iNew = p->pConfig->iCookie + 1; + rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew); + if( rc==SQLITE_OK ){ + p->pConfig->iCookie = iNew; + } + } + return rc; +} + +#line 1 "fts5_tokenize.c" +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +*/ + + +/* #include "fts5Int.h" */ + +/************************************************************************** +** Start of ascii tokenizer implementation. +*/ + +/* +** For tokenizers with no "unicode" modifier, the set of token characters +** is the same as the set of ASCII range alphanumeric characters. +*/ +static unsigned char aAsciiTokenChar[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10..0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20..0x2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30..0x3F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40..0x4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50..0x5F */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60..0x6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70..0x7F */ +}; + +typedef struct AsciiTokenizer AsciiTokenizer; +struct AsciiTokenizer { + unsigned char aTokenChar[128]; +}; + +static void fts5AsciiAddExceptions( + AsciiTokenizer *p, + const char *zArg, + int bTokenChars +){ + int i; + for(i=0; zArg[i]; i++){ + if( (zArg[i] & 0x80)==0 ){ + p->aTokenChar[(int)zArg[i]] = (unsigned char)bTokenChars; + } + } +} + +/* +** Delete a "ascii" tokenizer. +*/ +static void fts5AsciiDelete(Fts5Tokenizer *p){ + sqlite3_free(p); +} + +/* +** Create an "ascii" tokenizer. +*/ +static int fts5AsciiCreate( + void *pUnused, + const char **azArg, int nArg, + Fts5Tokenizer **ppOut +){ + int rc = SQLITE_OK; + AsciiTokenizer *p = 0; + UNUSED_PARAM(pUnused); + if( nArg%2 ){ + rc = SQLITE_ERROR; + }else{ + p = sqlite3_malloc(sizeof(AsciiTokenizer)); + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + memset(p, 0, sizeof(AsciiTokenizer)); + memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); + for(i=0; rc==SQLITE_OK && i='A' && c<='Z' ) c += 32; + aOut[i] = c; + } +} + +/* +** Tokenize some text using the ascii tokenizer. +*/ +static int fts5AsciiTokenize( + Fts5Tokenizer *pTokenizer, + void *pCtx, + int iUnused, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) +){ + AsciiTokenizer *p = (AsciiTokenizer*)pTokenizer; + int rc = SQLITE_OK; + int ie; + int is = 0; + + char aFold[64]; + int nFold = sizeof(aFold); + char *pFold = aFold; + unsigned char *a = p->aTokenChar; + + UNUSED_PARAM(iUnused); + + while( isnFold ){ + if( pFold!=aFold ) sqlite3_free(pFold); + pFold = sqlite3_malloc(nByte*2); + if( pFold==0 ){ + rc = SQLITE_NOMEM; + break; + } + nFold = nByte*2; + } + asciiFold(pFold, &pText[is], nByte); + + /* Invoke the token callback */ + rc = xToken(pCtx, 0, pFold, nByte, is, ie); + is = ie+1; + } + + if( pFold!=aFold ) sqlite3_free(pFold); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; +} + +/************************************************************************** +** Start of unicode61 tokenizer implementation. +*/ + + +/* +** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied +** from the sqlite3 source file utf.c. If this file is compiled as part +** of the amalgamation, they are not required. +*/ +#ifndef SQLITE_AMALGAMATION + +static const unsigned char sqlite3Utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define READ_UTF8(zIn, zTerm, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = sqlite3Utf8Trans1[c-0xc0]; \ + while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + if( c<0x80 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ + } + + +#define WRITE_UTF8(zOut, c) { \ + if( c<0x00080 ){ \ + *zOut++ = (unsigned char)(c&0xFF); \ + } \ + else if( c<0x00800 ){ \ + *zOut++ = 0xC0 + (unsigned char)((c>>6)&0x1F); \ + *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ + } \ + else if( c<0x10000 ){ \ + *zOut++ = 0xE0 + (unsigned char)((c>>12)&0x0F); \ + *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ + }else{ \ + *zOut++ = 0xF0 + (unsigned char)((c>>18) & 0x07); \ + *zOut++ = 0x80 + (unsigned char)((c>>12) & 0x3F); \ + *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ + } \ +} + +#endif /* ifndef SQLITE_AMALGAMATION */ + +typedef struct Unicode61Tokenizer Unicode61Tokenizer; +struct Unicode61Tokenizer { + unsigned char aTokenChar[128]; /* ASCII range token characters */ + char *aFold; /* Buffer to fold text into */ + int nFold; /* Size of aFold[] in bytes */ + int bRemoveDiacritic; /* True if remove_diacritics=1 is set */ + int nException; + int *aiException; +}; + +static int fts5UnicodeAddExceptions( + Unicode61Tokenizer *p, /* Tokenizer object */ + const char *z, /* Characters to treat as exceptions */ + int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */ +){ + int rc = SQLITE_OK; + int n = (int)strlen(z); + int *aNew; + + if( n>0 ){ + aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int)); + if( aNew ){ + int nNew = p->nException; + const unsigned char *zCsr = (const unsigned char*)z; + const unsigned char *zTerm = (const unsigned char*)&z[n]; + while( zCsraTokenChar[iCode] = (unsigned char)bTokenChars; + }else{ + bToken = sqlite3Fts5UnicodeIsalnum(iCode); + assert( (bToken==0 || bToken==1) ); + assert( (bTokenChars==0 || bTokenChars==1) ); + if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){ + int i; + for(i=0; iiCode ) break; + } + memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int)); + aNew[i] = iCode; + nNew++; + } + } + } + p->aiException = aNew; + p->nException = nNew; + }else{ + rc = SQLITE_NOMEM; + } + } + + return rc; +} + +/* +** Return true if the p->aiException[] array contains the value iCode. +*/ +static int fts5UnicodeIsException(Unicode61Tokenizer *p, int iCode){ + if( p->nException>0 ){ + int *a = p->aiException; + int iLo = 0; + int iHi = p->nException-1; + + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( iCode==a[iTest] ){ + return 1; + }else if( iCode>a[iTest] ){ + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + } + + return 0; +} + +/* +** Delete a "unicode61" tokenizer. +*/ +static void fts5UnicodeDelete(Fts5Tokenizer *pTok){ + if( pTok ){ + Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTok; + sqlite3_free(p->aiException); + sqlite3_free(p->aFold); + sqlite3_free(p); + } + return; +} + +/* +** Create a "unicode61" tokenizer. +*/ +static int fts5UnicodeCreate( + void *pUnused, + const char **azArg, int nArg, + Fts5Tokenizer **ppOut +){ + int rc = SQLITE_OK; /* Return code */ + Unicode61Tokenizer *p = 0; /* New tokenizer object */ + + UNUSED_PARAM(pUnused); + + if( nArg%2 ){ + rc = SQLITE_ERROR; + }else{ + p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); + if( p ){ + int i; + memset(p, 0, sizeof(Unicode61Tokenizer)); + memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); + p->bRemoveDiacritic = 1; + p->nFold = 64; + p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); + if( p->aFold==0 ){ + rc = SQLITE_NOMEM; + } + for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = (zArg[0]=='1'); + }else + if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){ + rc = fts5UnicodeAddExceptions(p, zArg, 1); + }else + if( 0==sqlite3_stricmp(azArg[i], "separators") ){ + rc = fts5UnicodeAddExceptions(p, zArg, 0); + }else{ + rc = SQLITE_ERROR; + } + } + }else{ + rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + fts5UnicodeDelete((Fts5Tokenizer*)p); + p = 0; + } + *ppOut = (Fts5Tokenizer*)p; + } + return rc; +} + +/* +** Return true if, for the purposes of tokenizing with the tokenizer +** passed as the first argument, codepoint iCode is considered a token +** character (not a separator). +*/ +static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ + assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); + return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode); +} + +static int fts5UnicodeTokenize( + Fts5Tokenizer *pTokenizer, + void *pCtx, + int iUnused, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) +){ + Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTokenizer; + int rc = SQLITE_OK; + unsigned char *a = p->aTokenChar; + + unsigned char *zTerm = (unsigned char*)&pText[nText]; + unsigned char *zCsr = (unsigned char *)pText; + + /* Output buffer */ + char *aFold = p->aFold; + int nFold = p->nFold; + const char *pEnd = &aFold[nFold-6]; + + UNUSED_PARAM(iUnused); + + /* Each iteration of this loop gobbles up a contiguous run of separators, + ** then the next token. */ + while( rc==SQLITE_OK ){ + int iCode; /* non-ASCII codepoint read from input */ + char *zOut = aFold; + int is; + int ie; + + /* Skip any separator characters. */ + while( 1 ){ + if( zCsr>=zTerm ) goto tokenize_done; + if( *zCsr & 0x80 ) { + /* A character outside of the ascii range. Skip past it if it is + ** a separator character. Or break out of the loop if it is not. */ + is = zCsr - (unsigned char*)pText; + READ_UTF8(zCsr, zTerm, iCode); + if( fts5UnicodeIsAlnum(p, iCode) ){ + goto non_ascii_tokenchar; + } + }else{ + if( a[*zCsr] ){ + is = zCsr - (unsigned char*)pText; + goto ascii_tokenchar; + } + zCsr++; + } + } + + /* Run through the tokenchars. Fold them into the output buffer along + ** the way. */ + while( zCsrpEnd ){ + aFold = sqlite3_malloc(nFold*2); + if( aFold==0 ){ + rc = SQLITE_NOMEM; + goto tokenize_done; + } + zOut = &aFold[zOut - p->aFold]; + memcpy(aFold, p->aFold, nFold); + sqlite3_free(p->aFold); + p->aFold = aFold; + p->nFold = nFold = nFold*2; + pEnd = &aFold[nFold-6]; + } + + if( *zCsr & 0x80 ){ + /* An non-ascii-range character. Fold it into the output buffer if + ** it is a token character, or break out of the loop if it is not. */ + READ_UTF8(zCsr, zTerm, iCode); + if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){ + non_ascii_tokenchar: + iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic); + if( iCode ) WRITE_UTF8(zOut, iCode); + }else{ + break; + } + }else if( a[*zCsr]==0 ){ + /* An ascii-range separator character. End of token. */ + break; + }else{ + ascii_tokenchar: + if( *zCsr>='A' && *zCsr<='Z' ){ + *zOut++ = *zCsr + 32; + }else{ + *zOut++ = *zCsr; + } + zCsr++; + } + ie = zCsr - (unsigned char*)pText; + } + + /* Invoke the token callback */ + rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie); + } + + tokenize_done: + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; +} + +/************************************************************************** +** Start of porter stemmer implementation. +*/ + +/* Any tokens larger than this (in bytes) are passed through without +** stemming. */ +#define FTS5_PORTER_MAX_TOKEN 64 + +typedef struct PorterTokenizer PorterTokenizer; +struct PorterTokenizer { + fts5_tokenizer tokenizer; /* Parent tokenizer module */ + Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */ + char aBuf[FTS5_PORTER_MAX_TOKEN + 64]; +}; + +/* +** Delete a "porter" tokenizer. +*/ +static void fts5PorterDelete(Fts5Tokenizer *pTok){ + if( pTok ){ + PorterTokenizer *p = (PorterTokenizer*)pTok; + if( p->pTokenizer ){ + p->tokenizer.xDelete(p->pTokenizer); + } + sqlite3_free(p); + } +} + +/* +** Create a "porter" tokenizer. +*/ +static int fts5PorterCreate( + void *pCtx, + const char **azArg, int nArg, + Fts5Tokenizer **ppOut +){ + fts5_api *pApi = (fts5_api*)pCtx; + int rc = SQLITE_OK; + PorterTokenizer *pRet; + void *pUserdata = 0; + const char *zBase = "unicode61"; + + if( nArg>0 ){ + zBase = azArg[0]; + } + + pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); + if( pRet ){ + memset(pRet, 0, sizeof(PorterTokenizer)); + rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer); + }else{ + rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + int nArg2 = (nArg>0 ? nArg-1 : 0); + const char **azArg2 = (nArg2 ? &azArg[1] : 0); + rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer); + } + + if( rc!=SQLITE_OK ){ + fts5PorterDelete((Fts5Tokenizer*)pRet); + pRet = 0; + } + *ppOut = (Fts5Tokenizer*)pRet; + return rc; +} + +typedef struct PorterContext PorterContext; +struct PorterContext { + void *pCtx; + int (*xToken)(void*, int, const char*, int, int, int); + char *aBuf; +}; + +typedef struct PorterRule PorterRule; +struct PorterRule { + const char *zSuffix; + int nSuffix; + int (*xCond)(char *zStem, int nStem); + const char *zOutput; + int nOutput; +}; + +#if 0 +static int fts5PorterApply(char *aBuf, int *pnBuf, PorterRule *aRule){ + int ret = -1; + int nBuf = *pnBuf; + PorterRule *p; + + for(p=aRule; p->zSuffix; p++){ + assert( strlen(p->zSuffix)==p->nSuffix ); + assert( strlen(p->zOutput)==p->nOutput ); + if( nBufnSuffix ) continue; + if( 0==memcmp(&aBuf[nBuf - p->nSuffix], p->zSuffix, p->nSuffix) ) break; + } + + if( p->zSuffix ){ + int nStem = nBuf - p->nSuffix; + if( p->xCond==0 || p->xCond(aBuf, nStem) ){ + memcpy(&aBuf[nStem], p->zOutput, p->nOutput); + *pnBuf = nStem + p->nOutput; + ret = p - aRule; + } + } + + return ret; +} +#endif + +static int fts5PorterIsVowel(char c, int bYIsVowel){ + return ( + c=='a' || c=='e' || c=='i' || c=='o' || c=='u' || (bYIsVowel && c=='y') + ); +} + +static int fts5PorterGobbleVC(char *zStem, int nStem, int bPrevCons){ + int i; + int bCons = bPrevCons; + + /* Scan for a vowel */ + for(i=0; i 0) */ +static int fts5Porter_MGt0(char *zStem, int nStem){ + return !!fts5PorterGobbleVC(zStem, nStem, 0); +} + +/* porter rule condition: (m > 1) */ +static int fts5Porter_MGt1(char *zStem, int nStem){ + int n; + n = fts5PorterGobbleVC(zStem, nStem, 0); + if( n && fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){ + return 1; + } + return 0; +} + +/* porter rule condition: (m = 1) */ +static int fts5Porter_MEq1(char *zStem, int nStem){ + int n; + n = fts5PorterGobbleVC(zStem, nStem, 0); + if( n && 0==fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){ + return 1; + } + return 0; +} + +/* porter rule condition: (*o) */ +static int fts5Porter_Ostar(char *zStem, int nStem){ + if( zStem[nStem-1]=='w' || zStem[nStem-1]=='x' || zStem[nStem-1]=='y' ){ + return 0; + }else{ + int i; + int mask = 0; + int bCons = 0; + for(i=0; i 1 and (*S or *T)) */ +static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){ + assert( nStem>0 ); + return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t') + && fts5Porter_MGt1(zStem, nStem); +} + +/* porter rule condition: (*v*) */ +static int fts5Porter_Vowel(char *zStem, int nStem){ + int i; + for(i=0; i0) ){ + return 1; + } + } + return 0; +} + + +/************************************************************************** +*************************************************************************** +** GENERATED CODE STARTS HERE (mkportersteps.tcl) +*/ + +static int fts5PorterStep4(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 'c': + if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + }else if( nBuf>4 && 0==memcmp("ence", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + } + break; + + case 'e': + if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 'i': + if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 'l': + if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + }else if( nBuf>4 && 0==memcmp("ible", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + } + break; + + case 'n': + if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + }else if( nBuf>5 && 0==memcmp("ement", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt1(aBuf, nBuf-5) ){ + *pnBuf = nBuf - 5; + } + }else if( nBuf>4 && 0==memcmp("ment", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt1(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + }else if( nBuf>3 && 0==memcmp("ent", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'o': + if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + }else if( nBuf>2 && 0==memcmp("ou", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_MGt1(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + } + } + break; + + case 's': + if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 't': + if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + }else if( nBuf>3 && 0==memcmp("iti", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'u': + if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'v': + if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'z': + if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt1(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + } + return ret; +} + + +static int fts5PorterStep1B2(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){ + memcpy(&aBuf[nBuf-2], "ate", 3); + *pnBuf = nBuf - 2 + 3; + ret = 1; + } + break; + + case 'b': + if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){ + memcpy(&aBuf[nBuf-2], "ble", 3); + *pnBuf = nBuf - 2 + 3; + ret = 1; + } + break; + + case 'i': + if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){ + memcpy(&aBuf[nBuf-2], "ize", 3); + *pnBuf = nBuf - 2 + 3; + ret = 1; + } + break; + + } + return ret; +} + + +static int fts5PorterStep2(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ate", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>6 && 0==memcmp("tional", &aBuf[nBuf-6], 6) ){ + if( fts5Porter_MGt0(aBuf, nBuf-6) ){ + memcpy(&aBuf[nBuf-6], "tion", 4); + *pnBuf = nBuf - 6 + 4; + } + } + break; + + case 'c': + if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ence", 4); + *pnBuf = nBuf - 4 + 4; + } + }else if( nBuf>4 && 0==memcmp("anci", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ance", 4); + *pnBuf = nBuf - 4 + 4; + } + } + break; + + case 'e': + if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ize", 3); + *pnBuf = nBuf - 4 + 3; + } + } + break; + + case 'g': + if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "log", 3); + *pnBuf = nBuf - 4 + 3; + } + } + break; + + case 'l': + if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + memcpy(&aBuf[nBuf-3], "ble", 3); + *pnBuf = nBuf - 3 + 3; + } + }else if( nBuf>4 && 0==memcmp("alli", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "al", 2); + *pnBuf = nBuf - 4 + 2; + } + }else if( nBuf>5 && 0==memcmp("entli", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ent", 3); + *pnBuf = nBuf - 5 + 3; + } + }else if( nBuf>3 && 0==memcmp("eli", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + memcpy(&aBuf[nBuf-3], "e", 1); + *pnBuf = nBuf - 3 + 1; + } + }else if( nBuf>5 && 0==memcmp("ousli", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ous", 3); + *pnBuf = nBuf - 5 + 3; + } + } + break; + + case 'o': + if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ize", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>5 && 0==memcmp("ation", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ate", 3); + *pnBuf = nBuf - 5 + 3; + } + }else if( nBuf>4 && 0==memcmp("ator", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ate", 3); + *pnBuf = nBuf - 4 + 3; + } + } + break; + + case 's': + if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "al", 2); + *pnBuf = nBuf - 5 + 2; + } + }else if( nBuf>7 && 0==memcmp("iveness", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ive", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>7 && 0==memcmp("fulness", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ful", 3); + *pnBuf = nBuf - 7 + 3; + } + }else if( nBuf>7 && 0==memcmp("ousness", &aBuf[nBuf-7], 7) ){ + if( fts5Porter_MGt0(aBuf, nBuf-7) ){ + memcpy(&aBuf[nBuf-7], "ous", 3); + *pnBuf = nBuf - 7 + 3; + } + } + break; + + case 't': + if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "al", 2); + *pnBuf = nBuf - 5 + 2; + } + }else if( nBuf>5 && 0==memcmp("iviti", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ive", 3); + *pnBuf = nBuf - 5 + 3; + } + }else if( nBuf>6 && 0==memcmp("biliti", &aBuf[nBuf-6], 6) ){ + if( fts5Porter_MGt0(aBuf, nBuf-6) ){ + memcpy(&aBuf[nBuf-6], "ble", 3); + *pnBuf = nBuf - 6 + 3; + } + } + break; + + } + return ret; +} + + +static int fts5PorterStep3(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'a': + if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + memcpy(&aBuf[nBuf-4], "ic", 2); + *pnBuf = nBuf - 4 + 2; + } + } + break; + + case 's': + if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){ + if( fts5Porter_MGt0(aBuf, nBuf-4) ){ + *pnBuf = nBuf - 4; + } + } + break; + + case 't': + if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ic", 2); + *pnBuf = nBuf - 5 + 2; + } + }else if( nBuf>5 && 0==memcmp("iciti", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "ic", 2); + *pnBuf = nBuf - 5 + 2; + } + } + break; + + case 'u': + if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + } + } + break; + + case 'v': + if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + *pnBuf = nBuf - 5; + } + } + break; + + case 'z': + if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){ + if( fts5Porter_MGt0(aBuf, nBuf-5) ){ + memcpy(&aBuf[nBuf-5], "al", 2); + *pnBuf = nBuf - 5 + 2; + } + } + break; + + } + return ret; +} + + +static int fts5PorterStep1B(char *aBuf, int *pnBuf){ + int ret = 0; + int nBuf = *pnBuf; + switch( aBuf[nBuf-2] ){ + + case 'e': + if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_MGt0(aBuf, nBuf-3) ){ + memcpy(&aBuf[nBuf-3], "ee", 2); + *pnBuf = nBuf - 3 + 2; + } + }else if( nBuf>2 && 0==memcmp("ed", &aBuf[nBuf-2], 2) ){ + if( fts5Porter_Vowel(aBuf, nBuf-2) ){ + *pnBuf = nBuf - 2; + ret = 1; + } + } + break; + + case 'n': + if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){ + if( fts5Porter_Vowel(aBuf, nBuf-3) ){ + *pnBuf = nBuf - 3; + ret = 1; + } + } + break; + + } + return ret; +} + +/* +** GENERATED CODE ENDS HERE (mkportersteps.tcl) +*************************************************************************** +**************************************************************************/ + +static void fts5PorterStep1A(char *aBuf, int *pnBuf){ + int nBuf = *pnBuf; + if( aBuf[nBuf-1]=='s' ){ + if( aBuf[nBuf-2]=='e' ){ + if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s') + || (nBuf>3 && aBuf[nBuf-3]=='i' ) + ){ + *pnBuf = nBuf-2; + }else{ + *pnBuf = nBuf-1; + } + } + else if( aBuf[nBuf-2]!='s' ){ + *pnBuf = nBuf-1; + } + } +} + +static int fts5PorterCb( + void *pCtx, + int tflags, + const char *pToken, + int nToken, + int iStart, + int iEnd +){ + PorterContext *p = (PorterContext*)pCtx; + + char *aBuf; + int nBuf; + + if( nToken>FTS5_PORTER_MAX_TOKEN || nToken<3 ) goto pass_through; + aBuf = p->aBuf; + nBuf = nToken; + memcpy(aBuf, pToken, nBuf); + + /* Step 1. */ + fts5PorterStep1A(aBuf, &nBuf); + if( fts5PorterStep1B(aBuf, &nBuf) ){ + if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){ + char c = aBuf[nBuf-1]; + if( fts5PorterIsVowel(c, 0)==0 + && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2] + ){ + nBuf--; + }else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){ + aBuf[nBuf++] = 'e'; + } + } + } + + /* Step 1C. */ + if( aBuf[nBuf-1]=='y' && fts5Porter_Vowel(aBuf, nBuf-1) ){ + aBuf[nBuf-1] = 'i'; + } + + /* Steps 2 through 4. */ + fts5PorterStep2(aBuf, &nBuf); + fts5PorterStep3(aBuf, &nBuf); + fts5PorterStep4(aBuf, &nBuf); + + /* Step 5a. */ + assert( nBuf>0 ); + if( aBuf[nBuf-1]=='e' ){ + if( fts5Porter_MGt1(aBuf, nBuf-1) + || (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1)) + ){ + nBuf--; + } + } + + /* Step 5b. */ + if( nBuf>1 && aBuf[nBuf-1]=='l' + && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1) + ){ + nBuf--; + } + + return p->xToken(p->pCtx, tflags, aBuf, nBuf, iStart, iEnd); + + pass_through: + return p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd); +} + +/* +** Tokenize using the porter tokenizer. +*/ +static int fts5PorterTokenize( + Fts5Tokenizer *pTokenizer, + void *pCtx, + int flags, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) +){ + PorterTokenizer *p = (PorterTokenizer*)pTokenizer; + PorterContext sCtx; + sCtx.xToken = xToken; + sCtx.pCtx = pCtx; + sCtx.aBuf = p->aBuf; + return p->tokenizer.xTokenize( + p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb + ); +} + +/* +** Register all built-in tokenizers with FTS5. +*/ +static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ + struct BuiltinTokenizer { + const char *zName; + fts5_tokenizer x; + } aBuiltin[] = { + { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, + { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, + { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, + }; + + int rc = SQLITE_OK; /* Return code */ + int i; /* To iterate through builtin functions */ + + for(i=0; rc==SQLITE_OK && ixCreateTokenizer(pApi, + aBuiltin[i].zName, + (void*)pApi, + &aBuiltin[i].x, + 0 + ); + } + + return rc; +} + + + +#line 1 "fts5_unicode2.c" +/* +** 2012 May 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +*/ + +/* +** DO NOT EDIT THIS MACHINE GENERATED FILE. +*/ + + +#include + +/* +** Return true if the argument corresponds to a unicode codepoint +** classified as either a letter or a number. Otherwise false. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +static int sqlite3Fts5UnicodeIsalnum(int c){ + /* Each unsigned integer in the following array corresponds to a contiguous + ** range of unicode codepoints that are not either letters or numbers (i.e. + ** codepoints for which this function should return 0). + ** + ** The most significant 22 bits in each 32-bit value contain the first + ** codepoint in the range. The least significant 10 bits are used to store + ** the size of the range (always at least 1). In other words, the value + ** ((C<<22) + N) represents a range of N codepoints starting with codepoint + ** C. It is not possible to represent a range larger than 1023 codepoints + ** using this format. + */ + static const unsigned int aEntry[] = { + 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, + 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, + 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, + 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, + 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, + 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, + 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, + 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, + 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, + 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, + 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, + 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, + 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, + 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, + 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, + 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, + 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, + 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, + 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, + 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, + 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, + 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, + 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, + 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, + 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, + 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, + 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, + 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, + 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, + 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, + 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, + 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, + 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, + 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, + 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, + 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, + 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, + 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, + 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, + 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, + 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, + 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, + 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, + 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, + 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, + 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, + 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, + 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, + 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, + 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, + 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, + 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, + 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, + 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, + 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, + 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, + 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, + 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, + 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, + 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, + 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, + 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, + 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, + 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, + 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, + 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, + 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, + 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, + 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, + 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, + 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, + 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, + 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, + 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, + 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, + 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, + 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, + 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, + 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, + 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, + 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, + 0x380400F0, + }; + static const unsigned int aAscii[4] = { + 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, + }; + + if( (unsigned int)c<128 ){ + return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); + }else if( (unsigned int)c<(1<<22) ){ + unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; + int iRes = 0; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aEntry[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + assert( aEntry[0]=aEntry[iRes] ); + return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); + } + return 1; +} + + +/* +** If the argument is a codepoint corresponding to a lowercase letter +** in the ASCII range with a diacritic added, return the codepoint +** of the ASCII letter only. For example, if passed 235 - "LATIN +** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER +** E"). The resuls of passing a codepoint that corresponds to an +** uppercase letter are undefined. +*/ +static int fts5_remove_diacritic(int c){ + unsigned short aDia[] = { + 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, + 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, + 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, + 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, + 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, + 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, + 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, + 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, + 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, + 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, + 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, + 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, + 62924, 63050, 63082, 63274, 63390, + }; + char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', + 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', + 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', + 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', + 'e', 'i', 'o', 'u', 'y', + }; + + unsigned int key = (((unsigned int)c)<<3) | 0x00000007; + int iRes = 0; + int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aDia[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + assert( key>=aDia[iRes] ); + return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); +} + + +/* +** Return true if the argument interpreted as a unicode codepoint +** is a diacritical modifier character. +*/ +static int sqlite3Fts5UnicodeIsdiacritic(int c){ + unsigned int mask0 = 0x08029FDF; + unsigned int mask1 = 0x000361F8; + if( c<768 || c>817 ) return 0; + return (c < 768+32) ? + (mask0 & (1 << (c-768))) : + (mask1 & (1 << (c-768-32))); +} + + +/* +** Interpret the argument as a unicode codepoint. If the codepoint +** is an upper case character that has a lower case equivalent, +** return the codepoint corresponding to the lower case version. +** Otherwise, return a copy of the argument. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ + /* Each entry in the following array defines a rule for folding a range + ** of codepoints to lower case. The rule applies to a range of nRange + ** codepoints starting at codepoint iCode. + ** + ** If the least significant bit in flags is clear, then the rule applies + ** to all nRange codepoints (i.e. all nRange codepoints are upper case and + ** need to be folded). Or, if it is set, then the rule only applies to + ** every second codepoint in the range, starting with codepoint C. + ** + ** The 7 most significant bits in flags are an index into the aiOff[] + ** array. If a specific codepoint C does require folding, then its lower + ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF). + ** + ** The contents of this array are generated by parsing the CaseFolding.txt + ** file distributed as part of the "Unicode Character Database". See + ** http://www.unicode.org for details. + */ + static const struct TableEntry { + unsigned short iCode; + unsigned char flags; + unsigned char nRange; + } aEntry[] = { + {65, 14, 26}, {181, 64, 1}, {192, 14, 23}, + {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, + {313, 1, 16}, {330, 1, 46}, {376, 116, 1}, + {377, 1, 6}, {383, 104, 1}, {385, 50, 1}, + {386, 1, 4}, {390, 44, 1}, {391, 0, 1}, + {393, 42, 2}, {395, 0, 1}, {398, 32, 1}, + {399, 38, 1}, {400, 40, 1}, {401, 0, 1}, + {403, 42, 1}, {404, 46, 1}, {406, 52, 1}, + {407, 48, 1}, {408, 0, 1}, {412, 52, 1}, + {413, 54, 1}, {415, 56, 1}, {416, 1, 6}, + {422, 60, 1}, {423, 0, 1}, {425, 60, 1}, + {428, 0, 1}, {430, 60, 1}, {431, 0, 1}, + {433, 58, 2}, {435, 1, 4}, {439, 62, 1}, + {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, + {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, + {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, + {497, 2, 1}, {498, 1, 4}, {502, 122, 1}, + {503, 134, 1}, {504, 1, 40}, {544, 110, 1}, + {546, 1, 18}, {570, 70, 1}, {571, 0, 1}, + {573, 108, 1}, {574, 68, 1}, {577, 0, 1}, + {579, 106, 1}, {580, 28, 1}, {581, 30, 1}, + {582, 1, 10}, {837, 36, 1}, {880, 1, 4}, + {886, 0, 1}, {902, 18, 1}, {904, 16, 3}, + {908, 26, 1}, {910, 24, 2}, {913, 14, 17}, + {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, + {976, 140, 1}, {977, 142, 1}, {981, 146, 1}, + {982, 144, 1}, {984, 1, 24}, {1008, 136, 1}, + {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1}, + {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1}, + {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32}, + {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, + {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38}, + {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1}, + {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1}, + {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6}, + {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6}, + {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8}, + {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2}, + {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1}, + {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2}, + {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2}, + {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2}, + {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1}, + {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16}, + {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47}, + {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1}, + {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1}, + {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1}, + {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2}, + {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, + {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14}, + {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, + {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, + {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, + {65313, 14, 26}, + }; + static const unsigned short aiOff[] = { + 1, 2, 8, 15, 16, 26, 28, 32, + 37, 38, 40, 48, 63, 64, 69, 71, + 79, 80, 116, 202, 203, 205, 206, 207, + 209, 210, 211, 213, 214, 217, 218, 219, + 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, + 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, + 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, + 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, + 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, + 65514, 65521, 65527, 65528, 65529, + }; + + int ret = c; + + assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); + + if( c<128 ){ + if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); + }else if( c<65536 ){ + const struct TableEntry *p; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + int iRes = -1; + + assert( c>aEntry[0].iCode ); + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + int cmp = (c - aEntry[iTest].iCode); + if( cmp>=0 ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + + assert( iRes>=0 && c>=aEntry[iRes].iCode ); + p = &aEntry[iRes]; + if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ + ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; + assert( ret>0 ); + } + + if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret); + } + + else if( c>=66560 && c<66600 ){ + ret = c + 40; + } + + return ret; +} + +#line 1 "fts5_varint.c" +/* +** 2015 May 30 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Routines for varint serialization and deserialization. +*/ + + +/* #include "fts5Int.h" */ + +/* +** This is a copy of the sqlite3GetVarint32() routine from the SQLite core. +** Except, this version does handle the single byte case that the core +** version depends on being handled before its function is called. +*/ +static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){ + u32 a,b; + + /* The 1-byte case. Overwhelmingly the most common. */ + a = *p; + /* a: p0 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 0 and 127 */ + *v = a; + return 1; + } + + /* The 2-byte case */ + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + /* Values between 128 and 16383 */ + a &= 0x7f; + a = a<<7; + *v = a | b; + return 2; + } + + /* The 3-byte case */ + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 16384 and 2097151 */ + a &= (0x7f<<14)|(0x7f); + b &= 0x7f; + b = b<<7; + *v = a | b; + return 3; + } + + /* A 32-bit varint is used to store size information in btrees. + ** Objects are rarely larger than 2MiB limit of a 3-byte varint. + ** A 3-byte varint is sufficient, for example, to record the size + ** of a 1048569-byte BLOB or string. + ** + ** We only unroll the first 1-, 2-, and 3- byte cases. The very + ** rare larger cases can be handled by the slower 64-bit varint + ** routine. + */ + { + u64 v64; + u8 n; + p -= 2; + n = sqlite3Fts5GetVarint(p, &v64); + *v = (u32)v64; + assert( n>3 && n<=9 ); + return n; + } +} + + +/* +** Bitmasks used by sqlite3GetVarint(). These precomputed constants +** are defined here rather than simply putting the constant expressions +** inline in order to work around bugs in the RVT compiler. +** +** SLOT_2_0 A mask for (0x7f<<14) | 0x7f +** +** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 +*/ +#define SLOT_2_0 0x001fc07f +#define SLOT_4_2_0 0xf01fc07f + +/* +** Read a 64-bit variable-length integer from memory starting at p[0]. +** Return the number of bytes read. The value is stored in *v. +*/ +static u8 sqlite3Fts5GetVarint(const unsigned char *p, u64 *v){ + u32 a,b,s; + + a = *p; + /* a: p0 (unmasked) */ + if (!(a&0x80)) + { + *v = a; + return 1; + } + + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + a &= 0x7f; + a = a<<7; + a |= b; + *v = a; + return 2; + } + + /* Verify that constants are precomputed correctly */ + assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); + assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); + + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + a &= SLOT_2_0; + b &= 0x7f; + b = b<<7; + a |= b; + *v = a; + return 3; + } + + /* CSE1 from below */ + a &= SLOT_2_0; + p++; + b = b<<14; + b |= *p; + /* b: p1<<14 | p3 (unmasked) */ + if (!(b&0x80)) + { + b &= SLOT_2_0; + /* moved CSE1 up */ + /* a &= (0x7f<<14)|(0x7f); */ + a = a<<7; + a |= b; + *v = a; + return 4; + } + + /* a: p0<<14 | p2 (masked) */ + /* b: p1<<14 | p3 (unmasked) */ + /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + /* moved CSE1 up */ + /* a &= (0x7f<<14)|(0x7f); */ + b &= SLOT_2_0; + s = a; + /* s: p0<<14 | p2 (masked) */ + + p++; + a = a<<14; + a |= *p; + /* a: p0<<28 | p2<<14 | p4 (unmasked) */ + if (!(a&0x80)) + { + /* we can skip these cause they were (effectively) done above in calc'ing s */ + /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ + /* b &= (0x7f<<14)|(0x7f); */ + b = b<<7; + a |= b; + s = s>>18; + *v = ((u64)s)<<32 | a; + return 5; + } + + /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + s = s<<7; + s |= b; + /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + + p++; + b = b<<14; + b |= *p; + /* b: p1<<28 | p3<<14 | p5 (unmasked) */ + if (!(b&0x80)) + { + /* we can skip this cause it was (effectively) done above in calc'ing s */ + /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ + a &= SLOT_2_0; + a = a<<7; + a |= b; + s = s>>18; + *v = ((u64)s)<<32 | a; + return 6; + } + + p++; + a = a<<14; + a |= *p; + /* a: p2<<28 | p4<<14 | p6 (unmasked) */ + if (!(a&0x80)) + { + a &= SLOT_4_2_0; + b &= SLOT_2_0; + b = b<<7; + a |= b; + s = s>>11; + *v = ((u64)s)<<32 | a; + return 7; + } + + /* CSE2 from below */ + a &= SLOT_2_0; + p++; + b = b<<14; + b |= *p; + /* b: p3<<28 | p5<<14 | p7 (unmasked) */ + if (!(b&0x80)) + { + b &= SLOT_4_2_0; + /* moved CSE2 up */ + /* a &= (0x7f<<14)|(0x7f); */ + a = a<<7; + a |= b; + s = s>>4; + *v = ((u64)s)<<32 | a; + return 8; + } + + p++; + a = a<<15; + a |= *p; + /* a: p4<<29 | p6<<15 | p8 (unmasked) */ + + /* moved CSE2 up */ + /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ + b &= SLOT_2_0; + b = b<<8; + a |= b; + + s = s<<4; + b = p[-4]; + b &= 0x7f; + b = b>>3; + s |= b; + + *v = ((u64)s)<<32 | a; + + return 9; +} + +/* +** The variable-length integer encoding is as follows: +** +** KEY: +** A = 0xxxxxxx 7 bits of data and one flag bit +** B = 1xxxxxxx 7 bits of data and one flag bit +** C = xxxxxxxx 8 bits of data +** +** 7 bits - A +** 14 bits - BA +** 21 bits - BBA +** 28 bits - BBBA +** 35 bits - BBBBA +** 42 bits - BBBBBA +** 49 bits - BBBBBBA +** 56 bits - BBBBBBBA +** 64 bits - BBBBBBBBC +*/ + +#ifdef SQLITE_NOINLINE +# define FTS5_NOINLINE SQLITE_NOINLINE +#else +# define FTS5_NOINLINE +#endif + +/* +** Write a 64-bit variable-length integer to memory starting at p[0]. +** The length of data write will be between 1 and 9 bytes. The number +** of bytes written is returned. +** +** A variable-length integer consists of the lower 7 bits of each byte +** for all bytes that have the 8th bit set and one byte with the 8th +** bit clear. Except, if we get to the 9th byte, it stores the full +** 8 bits and is the last byte. +*/ +static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){ + int i, j, n; + u8 buf[10]; + if( v & (((u64)0xff000000)<<32) ){ + p[8] = (u8)v; + v >>= 8; + for(i=7; i>=0; i--){ + p[i] = (u8)((v & 0x7f) | 0x80); + v >>= 7; + } + return 9; + } + n = 0; + do{ + buf[n++] = (u8)((v & 0x7f) | 0x80); + v >>= 7; + }while( v!=0 ); + buf[0] &= 0x7f; + assert( n<=9 ); + for(i=0, j=n-1; j>=0; j--, i++){ + p[i] = buf[j]; + } + return n; +} + +static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){ + if( v<=0x7f ){ + p[0] = v&0x7f; + return 1; + } + if( v<=0x3fff ){ + p[0] = ((v>>7)&0x7f)|0x80; + p[1] = v&0x7f; + return 2; + } + return fts5PutVarint64(p,v); +} + + +static int sqlite3Fts5GetVarintLen(u32 iVal){ +#if 0 + if( iVal<(1 << 7 ) ) return 1; +#endif + assert( iVal>=(1 << 7) ); + if( iVal<(1 << 14) ) return 2; + if( iVal<(1 << 21) ) return 3; + if( iVal<(1 << 28) ) return 4; + return 5; +} + + +#line 1 "fts5_vocab.c" +/* +** 2015 May 08 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This is an SQLite virtual table module implementing direct access to an +** existing FTS5 index. The module may create several different types of +** tables: +** +** col: +** CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col)); +** +** One row for each term/column combination. The value of $doc is set to +** the number of fts5 rows that contain at least one instance of term +** $term within column $col. Field $cnt is set to the total number of +** instances of term $term in column $col (in any row of the fts5 table). +** +** row: +** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term)); +** +** One row for each term in the database. The value of $doc is set to +** the number of fts5 rows that contain at least one instance of term +** $term. Field $cnt is set to the total number of instances of term +** $term in the database. +*/ + + +/* #include "fts5Int.h" */ + + +typedef struct Fts5VocabTable Fts5VocabTable; +typedef struct Fts5VocabCursor Fts5VocabCursor; + +struct Fts5VocabTable { + sqlite3_vtab base; + char *zFts5Tbl; /* Name of fts5 table */ + char *zFts5Db; /* Db containing fts5 table */ + sqlite3 *db; /* Database handle */ + Fts5Global *pGlobal; /* FTS5 global object for this database */ + int eType; /* FTS5_VOCAB_COL or ROW */ +}; + +struct Fts5VocabCursor { + sqlite3_vtab_cursor base; + sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */ + Fts5Index *pIndex; /* Associated FTS5 index */ + + int bEof; /* True if this cursor is at EOF */ + Fts5IndexIter *pIter; /* Term/rowid iterator object */ + + int nLeTerm; /* Size of zLeTerm in bytes */ + char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ + + /* These are used by 'col' tables only */ + Fts5Config *pConfig; /* Fts5 table configuration */ + int iCol; + i64 *aCnt; + i64 *aDoc; + + /* Output values used by 'row' and 'col' tables */ + i64 rowid; /* This table's current rowid value */ + Fts5Buffer term; /* Current value of 'term' column */ +}; + +#define FTS5_VOCAB_COL 0 +#define FTS5_VOCAB_ROW 1 + +#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt" +#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt" + +/* +** Bits for the mask used as the idxNum value by xBestIndex/xFilter. +*/ +#define FTS5_VOCAB_TERM_EQ 0x01 +#define FTS5_VOCAB_TERM_GE 0x02 +#define FTS5_VOCAB_TERM_LE 0x04 + + +/* +** Translate a string containing an fts5vocab table type to an +** FTS5_VOCAB_XXX constant. If successful, set *peType to the output +** value and return SQLITE_OK. Otherwise, set *pzErr to an error message +** and return SQLITE_ERROR. +*/ +static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){ + int rc = SQLITE_OK; + char *zCopy = sqlite3Fts5Strndup(&rc, zType, -1); + if( rc==SQLITE_OK ){ + sqlite3Fts5Dequote(zCopy); + if( sqlite3_stricmp(zCopy, "col")==0 ){ + *peType = FTS5_VOCAB_COL; + }else + + if( sqlite3_stricmp(zCopy, "row")==0 ){ + *peType = FTS5_VOCAB_ROW; + }else + { + *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy); + rc = SQLITE_ERROR; + } + sqlite3_free(zCopy); + } + + return rc; +} + + +/* +** The xDisconnect() virtual table method. +*/ +static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab; + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* +** The xDestroy() virtual table method. +*/ +static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab; + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the FTS3 virtual table. +** +** The argv[] array contains the following: +** +** argv[0] -> module name ("fts5vocab") +** argv[1] -> database name +** argv[2] -> table name +** +** then: +** +** argv[3] -> name of fts5 table +** argv[4] -> type of fts5vocab table +** +** or, for tables in the TEMP schema only. +** +** argv[3] -> name of fts5 tables database +** argv[4] -> name of fts5 table +** argv[5] -> type of fts5vocab table +*/ +static int fts5VocabInitVtab( + sqlite3 *db, /* The SQLite database connection */ + void *pAux, /* Pointer to Fts5Global object */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ + char **pzErr /* Write any error message here */ +){ + const char *azSchema[] = { + "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")", + "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")" + }; + + Fts5VocabTable *pRet = 0; + int rc = SQLITE_OK; /* Return code */ + int bDb; + + bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0); + + if( argc!=5 && bDb==0 ){ + *pzErr = sqlite3_mprintf("wrong number of vtable arguments"); + rc = SQLITE_ERROR; + }else{ + int nByte; /* Bytes of space to allocate */ + const char *zDb = bDb ? argv[3] : argv[1]; + const char *zTab = bDb ? argv[4] : argv[3]; + const char *zType = bDb ? argv[5] : argv[4]; + int nDb = (int)strlen(zDb)+1; + int nTab = (int)strlen(zTab)+1; + int eType = 0; + + rc = fts5VocabTableType(zType, pzErr, &eType); + if( rc==SQLITE_OK ){ + assert( eType>=0 && eTypepGlobal = (Fts5Global*)pAux; + pRet->eType = eType; + pRet->db = db; + pRet->zFts5Tbl = (char*)&pRet[1]; + pRet->zFts5Db = &pRet->zFts5Tbl[nTab]; + memcpy(pRet->zFts5Tbl, zTab, nTab); + memcpy(pRet->zFts5Db, zDb, nDb); + sqlite3Fts5Dequote(pRet->zFts5Tbl); + sqlite3Fts5Dequote(pRet->zFts5Db); + } + } + + *ppVTab = (sqlite3_vtab*)pRet; + return rc; +} + + +/* +** The xConnect() and xCreate() methods for the virtual table. All the +** work is done in function fts5VocabInitVtab(). +*/ +static int fts5VocabConnectMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr); +} +static int fts5VocabCreateMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr); +} + +/* +** Implementation of the xBestIndex method. +*/ +static int fts5VocabBestIndexMethod( + sqlite3_vtab *pUnused, + sqlite3_index_info *pInfo +){ + int i; + int iTermEq = -1; + int iTermGe = -1; + int iTermLe = -1; + int idxNum = 0; + int nArg = 0; + + UNUSED_PARAM(pUnused); + + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; + if( p->usable==0 ) continue; + if( p->iColumn==0 ){ /* term column */ + if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i; + if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i; + } + } + + if( iTermEq>=0 ){ + idxNum |= FTS5_VOCAB_TERM_EQ; + pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg; + pInfo->estimatedCost = 100; + }else{ + pInfo->estimatedCost = 1000000; + if( iTermGe>=0 ){ + idxNum |= FTS5_VOCAB_TERM_GE; + pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg; + pInfo->estimatedCost = pInfo->estimatedCost / 2; + } + if( iTermLe>=0 ){ + idxNum |= FTS5_VOCAB_TERM_LE; + pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg; + pInfo->estimatedCost = pInfo->estimatedCost / 2; + } + } + + /* This virtual table always delivers results in ascending order of + ** the "term" column (column 0). So if the user has requested this + ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the + ** sqlite3_index_info.orderByConsumed flag to tell the core the results + ** are already in sorted order. */ + if( pInfo->nOrderBy==1 + && pInfo->aOrderBy[0].iColumn==0 + && pInfo->aOrderBy[0].desc==0 + ){ + pInfo->orderByConsumed = 1; + } + + pInfo->idxNum = idxNum; + return SQLITE_OK; +} + +/* +** Implementation of xOpen method. +*/ +static int fts5VocabOpenMethod( + sqlite3_vtab *pVTab, + sqlite3_vtab_cursor **ppCsr +){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; + Fts5Index *pIndex = 0; + Fts5Config *pConfig = 0; + Fts5VocabCursor *pCsr = 0; + int rc = SQLITE_OK; + sqlite3_stmt *pStmt = 0; + char *zSql = 0; + + zSql = sqlite3Fts5Mprintf(&rc, + "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'", + pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl + ); + if( zSql ){ + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); + } + sqlite3_free(zSql); + assert( rc==SQLITE_OK || pStmt==0 ); + if( rc==SQLITE_ERROR ) rc = SQLITE_OK; + + if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ + i64 iId = sqlite3_column_int64(pStmt, 0); + pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig); + } + + if( rc==SQLITE_OK && pIndex==0 ){ + rc = sqlite3_finalize(pStmt); + pStmt = 0; + if( rc==SQLITE_OK ){ + pVTab->zErrMsg = sqlite3_mprintf( + "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl + ); + rc = SQLITE_ERROR; + } + } + + if( rc==SQLITE_OK ){ + int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor); + pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte); + } + + if( pCsr ){ + pCsr->pIndex = pIndex; + pCsr->pStmt = pStmt; + pCsr->pConfig = pConfig; + pCsr->aCnt = (i64*)&pCsr[1]; + pCsr->aDoc = &pCsr->aCnt[pConfig->nCol]; + }else{ + sqlite3_finalize(pStmt); + } + + *ppCsr = (sqlite3_vtab_cursor*)pCsr; + return rc; +} + +static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ + pCsr->rowid = 0; + sqlite3Fts5IterClose(pCsr->pIter); + pCsr->pIter = 0; + sqlite3_free(pCsr->zLeTerm); + pCsr->nLeTerm = -1; + pCsr->zLeTerm = 0; +} + +/* +** Close the cursor. For additional information see the documentation +** on the xClose method of the virtual table interface. +*/ +static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + fts5VocabResetCursor(pCsr); + sqlite3Fts5BufferFree(&pCsr->term); + sqlite3_finalize(pCsr->pStmt); + sqlite3_free(pCsr); + return SQLITE_OK; +} + + +/* +** Advance the cursor to the next row in the table. +*/ +static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; + int rc = SQLITE_OK; + int nCol = pCsr->pConfig->nCol; + + pCsr->rowid++; + + if( pTab->eType==FTS5_VOCAB_COL ){ + for(pCsr->iCol++; pCsr->iColiCol++){ + if( pCsr->aDoc[pCsr->iCol] ) break; + } + } + + if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ + if( sqlite3Fts5IterEof(pCsr->pIter) ){ + pCsr->bEof = 1; + }else{ + const char *zTerm; + int nTerm; + + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( pCsr->nLeTerm>=0 ){ + int nCmp = MIN(nTerm, pCsr->nLeTerm); + int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); + if( bCmp<0 || (bCmp==0 && pCsr->nLeTermbEof = 1; + return SQLITE_OK; + } + } + + sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); + memset(pCsr->aCnt, 0, nCol * sizeof(i64)); + memset(pCsr->aDoc, 0, nCol * sizeof(i64)); + pCsr->iCol = 0; + + assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); + while( rc==SQLITE_OK ){ + const u8 *pPos; int nPos; /* Position list */ + i64 iPos = 0; /* 64-bit position read from poslist */ + int iOff = 0; /* Current offset within position list */ + + pPos = pCsr->pIter->pData; + nPos = pCsr->pIter->nData; + switch( pCsr->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + pPos = pCsr->pIter->pData; + nPos = pCsr->pIter->nData; + if( pTab->eType==FTS5_VOCAB_ROW ){ + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ + pCsr->aCnt[0]++; + } + pCsr->aDoc[0]++; + }else{ + int iCol = -1; + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ + int ii = FTS5_POS2COLUMN(iPos); + pCsr->aCnt[ii]++; + if( iCol!=ii ){ + if( ii>=nCol ){ + rc = FTS5_CORRUPT; + break; + } + pCsr->aDoc[ii]++; + iCol = ii; + } + } + } + break; + + case FTS5_DETAIL_COLUMNS: + if( pTab->eType==FTS5_VOCAB_ROW ){ + pCsr->aDoc[0]++; + }else{ + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ + assert_nc( iPos>=0 && iPos=nCol ){ + rc = FTS5_CORRUPT; + break; + } + pCsr->aDoc[iPos]++; + } + } + break; + + default: + assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE ); + pCsr->aDoc[0]++; + break; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IterNextScan(pCsr->pIter); + } + + if( rc==SQLITE_OK ){ + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){ + break; + } + if( sqlite3Fts5IterEof(pCsr->pIter) ) break; + } + } + } + } + + if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ + while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; + assert( pCsr->iColpConfig->nCol ); + } + return rc; +} + +/* +** This is the xFilter implementation for the virtual table. +*/ +static int fts5VocabFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *zUnused, /* Unused */ + int nUnused, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int rc = SQLITE_OK; + + int iVal = 0; + int f = FTS5INDEX_QUERY_SCAN; + const char *zTerm = 0; + int nTerm = 0; + + sqlite3_value *pEq = 0; + sqlite3_value *pGe = 0; + sqlite3_value *pLe = 0; + + UNUSED_PARAM2(zUnused, nUnused); + + fts5VocabResetCursor(pCsr); + if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; + if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; + if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; + + if( pEq ){ + zTerm = (const char *)sqlite3_value_text(pEq); + nTerm = sqlite3_value_bytes(pEq); + f = 0; + }else{ + if( pGe ){ + zTerm = (const char *)sqlite3_value_text(pGe); + nTerm = sqlite3_value_bytes(pGe); + } + if( pLe ){ + const char *zCopy = (const char *)sqlite3_value_text(pLe); + pCsr->nLeTerm = sqlite3_value_bytes(pLe); + pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); + if( pCsr->zLeTerm==0 ){ + rc = SQLITE_NOMEM; + }else{ + memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1); + } + } + } + + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); + } + if( rc==SQLITE_OK ){ + rc = fts5VocabNextMethod(pCursor); + } + + return rc; +} + +/* +** This is the xEof method of the virtual table. SQLite calls this +** routine to find out if it has reached the end of a result set. +*/ +static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + return pCsr->bEof; +} + +static int fts5VocabColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ +){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int eDetail = pCsr->pConfig->eDetail; + int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; + i64 iVal = 0; + + if( iCol==0 ){ + sqlite3_result_text( + pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT + ); + }else if( eType==FTS5_VOCAB_COL ){ + assert( iCol==1 || iCol==2 || iCol==3 ); + if( iCol==1 ){ + if( eDetail!=FTS5_DETAIL_NONE ){ + const char *z = pCsr->pConfig->azCol[pCsr->iCol]; + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + } + }else if( iCol==2 ){ + iVal = pCsr->aDoc[pCsr->iCol]; + }else{ + iVal = pCsr->aCnt[pCsr->iCol]; + } + }else{ + assert( iCol==1 || iCol==2 ); + if( iCol==1 ){ + iVal = pCsr->aDoc[0]; + }else{ + iVal = pCsr->aCnt[0]; + } + } + + if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); + return SQLITE_OK; +} + +/* +** This is the xRowid method. The SQLite core calls this routine to +** retrieve the rowid for the current row of the result set. The +** rowid should be written to *pRowid. +*/ +static int fts5VocabRowidMethod( + sqlite3_vtab_cursor *pCursor, + sqlite_int64 *pRowid +){ + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + *pRowid = pCsr->rowid; + return SQLITE_OK; +} + +static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ + static const sqlite3_module fts5Vocab = { + /* iVersion */ 2, + /* xCreate */ fts5VocabCreateMethod, + /* xConnect */ fts5VocabConnectMethod, + /* xBestIndex */ fts5VocabBestIndexMethod, + /* xDisconnect */ fts5VocabDisconnectMethod, + /* xDestroy */ fts5VocabDestroyMethod, + /* xOpen */ fts5VocabOpenMethod, + /* xClose */ fts5VocabCloseMethod, + /* xFilter */ fts5VocabFilterMethod, + /* xNext */ fts5VocabNextMethod, + /* xEof */ fts5VocabEofMethod, + /* xColumn */ fts5VocabColumnMethod, + /* xRowid */ fts5VocabRowidMethod, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindFunction */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + }; + void *p = (void*)pGlobal; + + return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0); +} + + + + + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ diff --git a/fts5.h b/fts5.h new file mode 100644 index 0000000000..a45c145d38 --- /dev/null +++ b/fts5.h @@ -0,0 +1,579 @@ +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Interfaces to extend FTS5. Using the interfaces defined in this file, +** FTS5 may be extended with: +** +** * custom tokenizers, and +** * custom auxiliary functions. +*/ + + +#ifndef _FTS5_H +#define _FTS5_H + +#include "sqlite3.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************* +** CUSTOM AUXILIARY FUNCTIONS +** +** Virtual table implementations may overload SQL functions by implementing +** the sqlite3_module.xFindFunction() method. +*/ + +typedef struct Fts5ExtensionApi Fts5ExtensionApi; +typedef struct Fts5Context Fts5Context; +typedef struct Fts5PhraseIter Fts5PhraseIter; + +typedef void (*fts5_extension_function)( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +); + +struct Fts5PhraseIter { + const unsigned char *a; + const unsigned char *b; +}; + +/* +** EXTENSION API FUNCTIONS +** +** xUserData(pFts): +** Return a copy of the context pointer the extension function was +** registered with. +** +** xColumnTotalSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the FTS5 table. Or, if iCol is +** non-negative but less than the number of columns in the table, return +** the total number of tokens in column iCol, considering all rows in +** the FTS5 table. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** xColumnCount(pFts): +** Return the number of columns in the table. +** +** xColumnSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the current row. Or, if iCol is +** non-negative but less than the number of columns in the table, set +** *pnToken to the number of tokens in column iCol of the current row. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** +** xColumnText: +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer +** containing the text in utf-8 encoding, (*pn) is set to the size in bytes +** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, +** if an error occurs, an SQLite error code is returned and the final values +** of (*pz) and (*pn) are undefined. +** +** xPhraseCount: +** Returns the number of phrases in the current query expression. +** +** xPhraseSize: +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. +** +** xInstCount: +** Set *pnInst to the total number of occurrences of all phrases within +** the query within the current row. Return SQLITE_OK if successful, or +** an error code (i.e. SQLITE_NOMEM) if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** +** xInst: +** Query for the details of phrase match iIdx within the current row. +** Phrase matches are numbered starting from zero, so the iIdx argument +** should be greater than or equal to zero and smaller than the value +** output by xInstCount(). +** +** Usually, output parameter *piPhrase is set to the phrase number, *piCol +** to the column in which it occurs and *piOff the token offset of the +** first token of the phrase. The exception is if the table was created +** with the offsets=0 option specified. In this case *piOff is always +** set to -1. +** +** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) +** if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** +** xRowid: +** Returns the rowid of the current row. +** +** xTokenize: +** Tokenize text using the tokenizer belonging to the FTS5 table. +** +** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): +** This API function is used to query the FTS table for phrase iPhrase +** of the current query. Specifically, a query equivalent to: +** +** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid +** +** with $p set to a phrase equivalent to the phrase iPhrase of the +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. +** +** If the callback function returns any value other than SQLITE_OK, the +** query is abandoned and the xQueryPhrase function returns immediately. +** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. +** Otherwise, the error code is propagated upwards. +** +** If the query runs to completion without incident, SQLITE_OK is returned. +** Or, if some error occurs before the query completes or is aborted by +** the callback, an SQLite error code is returned. +** +** +** xSetAuxdata(pFts5, pAux, xDelete) +** +** Save the pointer passed as the second argument as the extension functions +** "auxiliary data". The pointer may then be retrieved by the current or any +** future invocation of the same fts5 extension function made as part of +** of the same MATCH query using the xGetAuxdata() API. +** +** Each extension function is allocated a single auxiliary data slot for +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a +** single auxiliary data context. +** +** If there is already an auxiliary data pointer when this function is +** invoked, then it is replaced by the new pointer. If an xDelete callback +** was specified along with the original pointer, it is invoked at this +** point. +** +** The xDelete callback, if one is specified, is also invoked on the +** auxiliary data pointer after the FTS5 query has finished. +** +** If an error (e.g. an OOM condition) occurs within this function, an +** the auxiliary data is set to NULL and an error code returned. If the +** xDelete parameter was not NULL, it is invoked on the auxiliary data +** pointer before returning. +** +** +** xGetAuxdata(pFts5, bClear) +** +** Returns the current auxiliary data pointer for the fts5 extension +** function. See the xSetAuxdata() method for details. +** +** If the bClear argument is non-zero, then the auxiliary data is cleared +** (set to NULL) before this function returns. In this case the xDelete, +** if any, is not invoked. +** +** +** xRowCount(pFts5, pnRow) +** +** This function is used to retrieve the total number of rows in the table. +** In other words, the same value that would be returned by: +** +** SELECT count(*) FROM ftstable; +** +** xPhraseFirst() +** This function is used, along with type Fts5PhraseIter and the xPhraseNext +** method, to iterate through all instances of a single query phrase within +** the current row. This is the same information as is accessible via the +** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient +** to use, this API may be faster under some circumstances. To iterate +** through instances of phrase iPhrase, use the following code: +** +** Fts5PhraseIter iter; +** int iCol, iOff; +** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); +** iCol>=0; +** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) +** ){ +** // An instance of phrase iPhrase at offset iOff of column iCol +** } +** +** The Fts5PhraseIter structure is defined above. Applications should not +** modify this structure directly - it should only be used as shown above +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). +** +** xPhraseNext() +** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. +*/ +struct Fts5ExtensionApi { + int iVersion; /* Currently always set to 3 */ + + void *(*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); +}; + +/* +** CUSTOM AUXILIARY FUNCTIONS +*************************************************************************/ + +/************************************************************************* +** CUSTOM TOKENIZERS +** +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the +** following structure. All structure methods must be defined, setting +** any member of the fts5_tokenizer struct to NULL leads to undefined +** behaviour. The structure methods are expected to function as follows: +** +** xCreate: +** This function is used to allocate and initialize a tokenizer instance. +** A tokenizer instance is required to actually tokenize text. +** +** The first argument passed to this function is a copy of the (void*) +** pointer provided by the application when the fts5_tokenizer object +** was registered with FTS5 (the third argument to xCreateTokenizer()). +** The second and third arguments are an array of nul-terminated strings +** containing the tokenizer arguments, if any, specified following the +** tokenizer name as part of the CREATE VIRTUAL TABLE statement used +** to create the FTS5 table. +** +** The final argument is an output variable. If successful, (*ppOut) +** should be set to point to the new tokenizer handle and SQLITE_OK +** returned. If an error occurs, some value other than SQLITE_OK should +** be returned. In this case, fts5 assumes that the final value of *ppOut +** is undefined. +** +** xDelete: +** This function is invoked to delete a tokenizer handle previously +** allocated using xCreate(). Fts5 guarantees that this function will +** be invoked exactly once for each successful call to xCreate(). +** +** xTokenize: +** This function is expected to tokenize the nText byte string indicated +** by argument pText. pText may or may not be nul-terminated. The first +** argument passed to this function is a pointer to an Fts5Tokenizer object +** returned by an earlier call to xCreate(). +** +** The second argument indicates the reason that FTS5 is requesting +** tokenization of the supplied text. This is always one of the following +** four values: +** +**
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into +** or removed from the FTS table. The tokenizer is being invoked to +** determine the set of tokens to add to (or delete from) the +** FTS index. +** +**
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize +** a bareword or quoted string specified as part of the query. +** +**
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as +** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is +** followed by a "*" character, indicating that the last token +** returned by the tokenizer will be treated as a token prefix. +** +**
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +** satisfy an fts5_api.xTokenize() request made by an auxiliary +** function. Or an fts5_api.xColumnSize() request made by the same +** on a columnsize=0 database. +**
+** +** For each token in the input string, the supplied callback xToken() must +** be invoked. The first argument to it should be a copy of the pointer +** passed as the second argument to xTokenize(). The third and fourth +** arguments are a pointer to a buffer containing the token text, and the +** size of the token in bytes. The 4th and 5th arguments are the byte offsets +** of the first byte of and first byte immediately following the text from +** which the token is derived within the input. +** +** The second argument passed to the xToken() callback ("tflags") should +** normally be set to 0. The exception is if the tokenizer supports +** synonyms. In this case see the discussion below for details. +** +** FTS5 assumes the xToken() callback is invoked for each token in the +** order that they occur within the input text. +** +** If an xToken() callback returns any value other than SQLITE_OK, then +** the tokenization should be abandoned and the xTokenize() method should +** immediately return a copy of the xToken() return value. Or, if the +** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, +** if an error occurs with the xTokenize() implementation itself, it +** may abandon the tokenization and return any error code other than +** SQLITE_OK or SQLITE_DONE. +** +** SYNONYM SUPPORT +** +** Custom tokenizers may also support synonyms. Consider a case in which a +** user wishes to query for a phrase such as "first place". Using the +** built-in tokenizers, the FTS5 query 'first + place' will match instances +** of "first place" within the document set, but not alternative forms +** such as "1st place". In some applications, it would be better to match +** all instances of "first place" or "1st place" regardless of which form +** the user specified in the MATCH query text. +** +** There are several ways to approach this in FTS5: +** +**
  1. By mapping all synonyms to a single token. In this case, the +** In the above example, this means that the tokenizer returns the +** same token for inputs "first" and "1st". Say that token is in +** fact "first", so that when the user inserts the document "I won +** 1st place" entries are added to the index for tokens "i", "won", +** "first" and "place". If the user then queries for '1st + place', +** the tokenizer substitutes "first" for "1st" and the query works +** as expected. +** +**
  2. By adding multiple synonyms for a single term to the FTS index. +** In this case, when tokenizing query text, the tokenizer may +** provide multiple synonyms for a single term within the document. +** FTS5 then queries the index for each synonym individually. For +** example, faced with the query: +** +** +** ... MATCH 'first place' +** +** the tokenizer offers both "1st" and "first" as synonyms for the +** first token in the MATCH query and FTS5 effectively runs a query +** similar to: +** +** +** ... MATCH '(first OR 1st) place' +** +** except that, for the purposes of auxiliary functions, the query +** still appears to contain just two phrases - "(first OR 1st)" +** being treated as a single phrase. +** +**
  3. By adding multiple synonyms for a single term to the FTS index. +** Using this method, when tokenizing document text, the tokenizer +** provides multiple synonyms for each token. So that when a +** document such as "I won first place" is tokenized, entries are +** added to the FTS index for "i", "won", "first", "1st" and +** "place". +** +** This way, even if the tokenizer does not provide synonyms +** when tokenizing query text (it should not - to do would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entires in the +** FTS index corresponding to both forms of the first token. +**
+** +** Whether it is parsing document or query text, any call to xToken that +** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit +** is considered to supply a synonym for the previous token. For example, +** when parsing the document "I won first place", a tokenizer that supports +** synonyms would call xToken() 5 times, as follows: +** +** +** xToken(pCtx, 0, "i", 1, 0, 1); +** xToken(pCtx, 0, "won", 3, 2, 5); +** xToken(pCtx, 0, "first", 5, 6, 11); +** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); +** xToken(pCtx, 0, "place", 5, 12, 17); +** +** +** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time +** xToken() is called. Multiple synonyms may be specified for a single token +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** There is no limit to the number of synonyms that may be provided for a +** single token. +** +** In many cases, method (1) above is the best approach. It does not add +** extra data to the FTS index or require FTS5 to query for multiple terms, +** so it is efficient in terms of disk space and query speed. However, it +** does not support prefix queries very well. If, as suggested above, the +** token "first" is subsituted for "1st" by the tokenizer, then the query: +** +** +** ... MATCH '1s*' +** +** will not match documents that contain the token "1st" (as the tokenizer +** will probably not map "1s" to any prefix of "first"). +** +** For full prefix support, method (3) may be preferred. In this case, +** because the index contains entries for both "first" and "1st", prefix +** queries such as 'fi*' or '1s*' will match correctly. However, because +** extra entries are added to the FTS index, this method uses more space +** within the database. +** +** Method (2) offers a midpoint between (1) and (3). Using this method, +** a query such as '1s*' will match documents that contain the literal +** token "1st", but not "first" (assuming the tokenizer is not able to +** provide synonyms for prefixes). However, a non-prefix query like '1st' +** will match against "1st" and "first". This method does not require +** extra disk space, as no extra entries are added to the FTS index. +** On the other hand, it may require more CPU cycles to run MATCH queries, +** as separate queries of the FTS index are required for each synonym. +** +** When using methods (2) or (3), it is important that the tokenizer only +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is +** inefficient. +*/ +typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer fts5_tokenizer; +struct fts5_tokenizer { + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* Flags that may be passed as the third argument to xTokenize() */ +#define FTS5_TOKENIZE_QUERY 0x0001 +#define FTS5_TOKENIZE_PREFIX 0x0002 +#define FTS5_TOKENIZE_DOCUMENT 0x0004 +#define FTS5_TOKENIZE_AUX 0x0008 + +/* Flags that may be passed by the tokenizer implementation back to FTS5 +** as the third argument to the supplied xToken callback. */ +#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ + +/* +** END OF CUSTOM TOKENIZERS +*************************************************************************/ + +/************************************************************************* +** FTS5 EXTENSION REGISTRATION API +*/ +typedef struct fts5_api fts5_api; +struct fts5_api { + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + /* Create a new auxiliary function */ + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); +}; + +/* +** END OF REGISTRATION API +*************************************************************************/ + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* _FTS5_H */ diff --git a/keywordhash.h b/keywordhash.h new file mode 100644 index 0000000000..997651c69f --- /dev/null +++ b/keywordhash.h @@ -0,0 +1,285 @@ +/***** This file contains automatically generated code ****** +** +** The code in this file has been automatically generated by +** +** sqlite/tool/mkkeywordhash.c +** +** The code in this file implements a function that determines whether +** or not a given identifier is really an SQL keyword. The same thing +** might be implemented more directly using a hand-written hash table. +** But by using this automatically generated code, the size of the code +** is substantially reduced. This is important for embedded applications +** on platforms with limited memory. +*/ +/* Hash score: 182 */ +static int keywordCode(const char *z, int n, int *pType){ + /* zText[] encodes 834 bytes of keywords in 554 bytes */ + /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ + /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ + /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ + /* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ + /* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ + /* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ + /* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ + /* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ + /* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ + /* VACUUMVIEWINITIALLY */ + static const char zText[553] = { + 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', + 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', + 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', + 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', + 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', + 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', + 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', + 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', + 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', + 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', + 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', + 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', + 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E', + 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A', + 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A', + 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A', + 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J', + 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L', + 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E', + 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H', + 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E', + 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E', + 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M', + 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R', + 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A', + 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', + 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', + 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', + 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', + 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', + 'V','I','E','W','I','N','I','T','I','A','L','L','Y', + }; + static const unsigned char aHash[127] = { + 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, + 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, + 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, + 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, + 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, + 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, + 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, + 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, + 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, + 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, + }; + static const unsigned char aNext[124] = { + 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, + 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38, + 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, + 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, + 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, + 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, + 73, 83, 0, 35, 68, 0, 0, + }; + static const unsigned char aLen[124] = { + 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, + 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, + 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, + 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4, + 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, + 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, + 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, + 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, + 3, 5, 5, 6, 4, 9, 3, + }; + static const unsigned short int aOffset[124] = { + 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, + 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, + 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, + 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, + 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246, + 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, + 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, + 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, + 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, + 521, 524, 529, 534, 540, 544, 549, + }; + static const unsigned char aCode[124] = { + TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, + TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, + TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, + TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, + TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, + TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, + TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, + TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, + TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, + TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, + TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, + TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN, + TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, + TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, + TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, + TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, + TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, + TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, + TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, + TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, + TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, + TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, + TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, + TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, + TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, + }; + int i, j; + const char *zKW; + if( n>=2 ){ + i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127; + for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){ + if( aLen[i]!=n ) continue; + j = 0; + zKW = &zText[aOffset[i]]; +#ifdef SQLITE_ASCII + while( jr[P1]"), + /* 39 */ "Le" OpHelp("IF r[P3]<=r[P1]"), + /* 40 */ "Lt" OpHelp("IF r[P3]=r[P1]"), + /* 42 */ "ElseNotEq" OpHelp(""), + /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 53 */ "Last" OpHelp(""), + /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), + /* 55 */ "SorterSort" OpHelp(""), + /* 56 */ "Sort" OpHelp(""), + /* 57 */ "Rewind" OpHelp(""), + /* 58 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 59 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 60 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 61 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 62 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 63 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 64 */ "Program" OpHelp(""), + /* 65 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 66 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 67 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"), + /* 68 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 69 */ "IncrVacuum" OpHelp(""), + /* 70 */ "VNext" OpHelp(""), + /* 71 */ "Init" OpHelp("Start at P2"), + /* 72 */ "Return" OpHelp(""), + /* 73 */ "EndCoroutine" OpHelp(""), + /* 74 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 75 */ "Halt" OpHelp(""), + /* 76 */ "Integer" OpHelp("r[P2]=P1"), + /* 77 */ "Int64" OpHelp("r[P2]=P4"), + /* 78 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 79 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 80 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 81 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 82 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 83 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 84 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 85 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 86 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 87 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 88 */ "CollSeq" OpHelp(""), + /* 89 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 90 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 91 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 92 */ "RealAffinity" OpHelp(""), + /* 93 */ "Cast" OpHelp("affinity(r[P1])"), + /* 94 */ "Permutation" OpHelp(""), + /* 95 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 96 */ "Column" OpHelp("r[P3]=PX"), + /* 97 */ "String8" OpHelp("r[P2]='P4'"), + /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 100 */ "Count" OpHelp("r[P2]=count()"), + /* 101 */ "ReadCookie" OpHelp(""), + /* 102 */ "SetCookie" OpHelp(""), + /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 106 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 107 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 108 */ "SorterOpen" OpHelp(""), + /* 109 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 110 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 111 */ "Close" OpHelp(""), + /* 112 */ "ColumnsUsed" OpHelp(""), + /* 113 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 114 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 115 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 116 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 117 */ "Delete" OpHelp(""), + /* 118 */ "ResetCount" OpHelp(""), + /* 119 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 120 */ "SorterData" OpHelp("r[P2]=data"), + /* 121 */ "RowKey" OpHelp("r[P2]=key"), + /* 122 */ "RowData" OpHelp("r[P2]=data"), + /* 123 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 124 */ "NullRow" OpHelp(""), + /* 125 */ "SorterInsert" OpHelp(""), + /* 126 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 127 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 128 */ "Seek" OpHelp("Move P3 to P1.rowid"), + /* 129 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 130 */ "Destroy" OpHelp(""), + /* 131 */ "Clear" OpHelp(""), + /* 132 */ "Real" OpHelp("r[P2]=P4"), + /* 133 */ "ResetSorter" OpHelp(""), + /* 134 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), + /* 135 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 136 */ "ParseSchema" OpHelp(""), + /* 137 */ "LoadAnalysis" OpHelp(""), + /* 138 */ "DropTable" OpHelp(""), + /* 139 */ "DropIndex" OpHelp(""), + /* 140 */ "DropTrigger" OpHelp(""), + /* 141 */ "IntegrityCk" OpHelp(""), + /* 142 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 143 */ "Param" OpHelp(""), + /* 144 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 145 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 146 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 147 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 148 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 149 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 150 */ "Expire" OpHelp(""), + /* 151 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 152 */ "VBegin" OpHelp(""), + /* 153 */ "VCreate" OpHelp(""), + /* 154 */ "VDestroy" OpHelp(""), + /* 155 */ "VOpen" OpHelp(""), + /* 156 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 157 */ "VRename" OpHelp(""), + /* 158 */ "Pagecount" OpHelp(""), + /* 159 */ "MaxPgcnt" OpHelp(""), + /* 160 */ "CursorHint" OpHelp(""), + /* 161 */ "Noop" OpHelp(""), + /* 162 */ "Explain" OpHelp(""), + }; + return azName[i]; +} +#endif diff --git a/opcodes.h b/opcodes.h new file mode 100644 index 0000000000..9cac2fcc0f --- /dev/null +++ b/opcodes.h @@ -0,0 +1,206 @@ +/* Automatically generated. Do not edit */ +/* See the tool/mkopcodeh.tcl script for details */ +#define OP_Savepoint 0 +#define OP_AutoCommit 1 +#define OP_Transaction 2 +#define OP_SorterNext 3 +#define OP_PrevIfOpen 4 +#define OP_NextIfOpen 5 +#define OP_Prev 6 +#define OP_Next 7 +#define OP_Checkpoint 8 +#define OP_JournalMode 9 +#define OP_Vacuum 10 +#define OP_VFilter 11 /* synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */ +#define OP_Goto 13 +#define OP_Gosub 14 +#define OP_InitCoroutine 15 +#define OP_Yield 16 +#define OP_MustBeInt 17 +#define OP_Jump 18 +#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ +#define OP_Once 20 +#define OP_If 21 +#define OP_IfNot 22 +#define OP_SeekLT 23 /* synopsis: key=r[P3@P4] */ +#define OP_SeekLE 24 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGE 25 /* synopsis: key=r[P3@P4] */ +#define OP_SeekGT 26 /* synopsis: key=r[P3@P4] */ +#define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ +#define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ +#define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */ +#define OP_NotFound 30 /* synopsis: key=r[P3@P4] */ +#define OP_Found 31 /* synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 32 /* synopsis: intkey=r[P3] */ +#define OP_NotExists 33 /* synopsis: intkey=r[P3] */ +#define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ +#define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ +#define OP_Ne 36 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */ +#define OP_Eq 37 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */ +#define OP_Gt 38 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */ +#define OP_Le 39 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */ +#define OP_Lt 40 /* same as TK_LT, synopsis: IF r[P3]=r[P1] */ +#define OP_ElseNotEq 42 /* same as TK_ESCAPE */ +#define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_Last 53 +#define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ +#define OP_SorterSort 55 +#define OP_Sort 56 +#define OP_Rewind 57 +#define OP_IdxLE 58 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGT 59 /* synopsis: key=r[P3@P4] */ +#define OP_IdxLT 60 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGE 61 /* synopsis: key=r[P3@P4] */ +#define OP_RowSetRead 62 /* synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 63 /* synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 64 +#define OP_FkIfZero 65 /* synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 66 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 67 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */ +#define OP_DecrJumpZero 68 /* synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 69 +#define OP_VNext 70 +#define OP_Init 71 /* synopsis: Start at P2 */ +#define OP_Return 72 +#define OP_EndCoroutine 73 +#define OP_HaltIfNull 74 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 75 +#define OP_Integer 76 /* synopsis: r[P2]=P1 */ +#define OP_Int64 77 /* synopsis: r[P2]=P4 */ +#define OP_String 78 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 79 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 80 /* synopsis: r[P1]=NULL */ +#define OP_Blob 81 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 82 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 83 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 84 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 85 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 86 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 87 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 88 +#define OP_Function0 89 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_Function 90 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_AddImm 91 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 92 +#define OP_Cast 93 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 94 +#define OP_Compare 95 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_Column 96 /* synopsis: r[P3]=PX */ +#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 100 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 101 +#define OP_SetCookie 102 +#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenAutoindex 106 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 107 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 108 +#define OP_SequenceTest 109 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 110 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 111 +#define OP_ColumnsUsed 112 +#define OP_Sequence 113 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 114 /* synopsis: r[P2]=rowid */ +#define OP_Insert 115 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 116 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 117 +#define OP_ResetCount 118 +#define OP_SorterCompare 119 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 120 /* synopsis: r[P2]=data */ +#define OP_RowKey 121 /* synopsis: r[P2]=key */ +#define OP_RowData 122 /* synopsis: r[P2]=data */ +#define OP_Rowid 123 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 124 +#define OP_SorterInsert 125 +#define OP_IdxInsert 126 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 127 /* synopsis: key=r[P2@P3] */ +#define OP_Seek 128 /* synopsis: Move P3 to P1.rowid */ +#define OP_IdxRowid 129 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 130 +#define OP_Clear 131 +#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_ResetSorter 133 +#define OP_CreateIndex 134 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_CreateTable 135 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_ParseSchema 136 +#define OP_LoadAnalysis 137 +#define OP_DropTable 138 +#define OP_DropIndex 139 +#define OP_DropTrigger 140 +#define OP_IntegrityCk 141 +#define OP_RowSetAdd 142 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 143 +#define OP_FkCounter 144 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 145 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 146 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 147 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 148 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 149 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 150 +#define OP_TableLock 151 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 152 +#define OP_VCreate 153 +#define OP_VDestroy 154 +#define OP_VOpen 155 +#define OP_VColumn 156 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 157 +#define OP_Pagecount 158 +#define OP_MaxPgcnt 159 +#define OP_CursorHint 160 +#define OP_Noop 161 +#define OP_Explain 162 + +/* Properties such as "out2" or "jump" that are specified in +** comments following the "case" for each opcode in the vdbe.c +** are encoded into bitvectors as follows: +*/ +#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */ +#define OPFLG_IN1 0x02 /* in1: P1 is an input */ +#define OPFLG_IN2 0x04 /* in2: P2 is an input */ +#define OPFLG_IN3 0x08 /* in3: P3 is an input */ +#define OPFLG_OUT2 0x10 /* out2: P2 is an output */ +#define OPFLG_OUT3 0x20 /* out3: P3 is an output */ +#define OPFLG_INITIALIZER {\ +/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\ +/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\ +/* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\ +/* 32 */ 0x09, 0x09, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\ +/* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\ +/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b,\ +/* 64 */ 0x01, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01,\ +/* 72 */ 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10,\ +/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,\ +/* 88 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ +/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00,\ +/* 128 */ 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\ +/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10,\ +/* 144 */ 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\ +/* 160 */ 0x00, 0x00, 0x00,} + +/* The sqlite3P2Values() routine is able to run faster if it knows +** the value of the largest JUMP opcode. The smaller the maximum +** JUMP opcode the better, so the mkopcodeh.tcl script that +** generated this include file strives to group all JUMP opcodes +** together near the beginning of the list. +*/ +#define SQLITE_MX_JUMP_OPCODE 71 /* Maximum JUMP opcode */ diff --git a/parse.c b/parse.c new file mode 100644 index 0000000000..4d773e1733 --- /dev/null +++ b/parse.c @@ -0,0 +1,4215 @@ +/* +** 2000-05-29 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Driver template for the LEMON parser generator. +** +** The "lemon" program processes an LALR(1) input grammar file, then uses +** this template to construct a parser. The "lemon" program inserts text +** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** interstitial "-" characters) contained in this template is changed into +** the value of the %name directive from the grammar. Otherwise, the content +** of this template is copied straight through into the generate parser +** source file. +** +** The following is the concatenation of all %include directives from the +** input grammar file: +*/ +#include +/************ Begin %include sections from the grammar ************************/ +#line 48 "parse.y" + +#include "sqliteInt.h" + +/* +** Disable all error recovery processing in the parser push-down +** automaton. +*/ +#define YYNOERRORRECOVERY 1 + +/* +** Make yytestcase() the same as testcase() +*/ +#define yytestcase(X) testcase(X) + +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENEVERNULL 1 + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 + +/* +** An instance of this structure holds information about the +** LIMIT clause of a SELECT statement. +*/ +struct LimitVal { + Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */ + Expr *pOffset; /* The OFFSET expression. NULL if there is none */ +}; + +/* +** An instance of the following structure describes the event of a +** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, +** TK_DELETE, or TK_INSTEAD. If the event is of the form +** +** UPDATE ON (a,b,c) +** +** Then the "b" IdList records the list "a,b,c". +*/ +struct TrigEvent { int a; IdList * b; }; + +/* +** Disable lookaside memory allocation for objects that might be +** shared across database connections. +*/ +static void disableLookaside(Parse *pParse){ + pParse->disableLookaside++; + pParse->db->lookaside.bDisable++; +} + +#line 402 "parse.y" + + /* + ** For a compound SELECT statement, make sure p->pPrior->pNext==p for + ** all elements in the list. And make sure list length does not exceed + ** SQLITE_LIMIT_COMPOUND_SELECT. + */ + static void parserDoubleLinkSelect(Parse *pParse, Select *p){ + if( p->pPrior ){ + Select *pNext = 0, *pLoop; + int mxSelect, cnt = 0; + for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ + pLoop->pNext = pNext; + pLoop->selFlags |= SF_Compound; + } + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect + ){ + sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); + } + } + } +#line 825 "parse.y" + + /* This is a utility routine used to set the ExprSpan.zStart and + ** ExprSpan.zEnd values of pOut so that the span covers the complete + ** range of text beginning with pStart and going to the end of pEnd. + */ + static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){ + pOut->zStart = pStart->z; + pOut->zEnd = &pEnd->z[pEnd->n]; + } + + /* Construct a new Expr object from a single identifier. Use the + ** new Expr to populate pOut. Set the span of pOut to be the identifier + ** that created the expression. + */ + static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){ + Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = (u8)op; + p->flags = EP_Leaf; + p->iAgg = -1; + p->u.zToken = (char*)&p[1]; + memcpy(p->u.zToken, t.z, t.n); + p->u.zToken[t.n] = 0; + if( sqlite3Isquote(p->u.zToken[0]) ){ + if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted; + sqlite3Dequote(p->u.zToken); + } +#if SQLITE_MAX_EXPR_DEPTH>0 + p->nHeight = 1; +#endif + } + pOut->pExpr = p; + pOut->zStart = t.z; + pOut->zEnd = &t.z[t.n]; + } +#line 941 "parse.y" + + /* This routine constructs a binary expression node out of two ExprSpan + ** objects and uses the result to populate a new ExprSpan object. + */ + static void spanBinaryExpr( + Parse *pParse, /* The parsing context. Errors accumulate here */ + int op, /* The binary operation */ + ExprSpan *pLeft, /* The left operand, and output */ + ExprSpan *pRight /* The right operand */ + ){ + pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0); + pLeft->zEnd = pRight->zEnd; + } + + /* If doNot is true, then add a TK_NOT Expr-node wrapper around the + ** outside of *ppExpr. + */ + static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){ + if( doNot ){ + pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0, 0); + } + } +#line 1015 "parse.y" + + /* Construct an expression node for a unary postfix operator + */ + static void spanUnaryPostfix( + Parse *pParse, /* Parsing context to record errors */ + int op, /* The operator */ + ExprSpan *pOperand, /* The operand, and output */ + Token *pPostOp /* The operand token for setting the span */ + ){ + pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); + pOperand->zEnd = &pPostOp->z[pPostOp->n]; + } +#line 1032 "parse.y" + + /* A routine to convert a binary TK_IS or TK_ISNOT expression into a + ** unary TK_ISNULL or TK_NOTNULL expression. */ + static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ + sqlite3 *db = pParse->db; + if( pA && pY && pY->op==TK_NULL ){ + pA->op = (u8)op; + sqlite3ExprDelete(db, pA->pRight); + pA->pRight = 0; + } + } +#line 1060 "parse.y" + + /* Construct an expression node for a unary prefix operator + */ + static void spanUnaryPrefix( + ExprSpan *pOut, /* Write the new expression node here */ + Parse *pParse, /* Parsing context to record errors */ + int op, /* The operator */ + ExprSpan *pOperand, /* The operand */ + Token *pPreOp /* The operand token for setting the span */ + ){ + pOut->zStart = pPreOp->z; + pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); + pOut->zEnd = pOperand->zEnd; + } +#line 1272 "parse.y" + + /* Add a single new term to an ExprList that is used to store a + ** list of identifiers. Report an error if the ID list contains + ** a COLLATE clause or an ASC or DESC keyword, except ignore the + ** error while parsing a legacy schema. + */ + static ExprList *parserAddExprIdListTerm( + Parse *pParse, + ExprList *pPrior, + Token *pIdToken, + int hasCollate, + int sortOrder + ){ + ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); + if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) + && pParse->db->init.busy==0 + ){ + sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", + pIdToken->n, pIdToken->z); + } + sqlite3ExprListSetName(pParse, p, pIdToken, 1); + return p; + } +#line 231 "parse.c" +/**************** End of %include directives **********************************/ +/* These constants specify the various numeric values for terminal symbols +** in a format understandable to "makeheaders". This section is blank unless +** "lemon" is run with the "-m" command-line option. +***************** Begin makeheaders token definitions *************************/ +/**************** End makeheaders token definitions ***************************/ + +/* The next sections is a series of control #defines. +** various aspects of the generated parser. +** YYCODETYPE is the data type used to store the integer codes +** that represent terminal and non-terminal symbols. +** "unsigned char" is used if there are fewer than +** 256 symbols. Larger types otherwise. +** YYNOCODE is a number of type YYCODETYPE that is not used for +** any terminal or nonterminal symbol. +** YYFALLBACK If defined, this indicates that one or more tokens +** (also known as: "terminal symbols") have fall-back +** values which should be used if the original symbol +** would not parse. This permits keywords to sometimes +** be used as identifiers, for example. +** YYACTIONTYPE is the data type used for "action codes" - numbers +** that indicate what to do in response to the next +** token. +** sqlite3ParserTOKENTYPE is the data type used for minor type for terminal +** symbols. Background: A "minor type" is a semantic +** value associated with a terminal or non-terminal +** symbols. For example, for an "ID" terminal symbol, +** the minor type might be the name of the identifier. +** Each non-terminal can have a different minor type. +** Terminal symbols all have the same minor type, though. +** This macros defines the minor type for terminal +** symbols. +** YYMINORTYPE is the data type used for all minor types. +** This is typically a union of many types, one of +** which is sqlite3ParserTOKENTYPE. The entry in the union +** for terminal symbols is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument +** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser +** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YY_MAX_SHIFT Maximum value for shift actions +** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions +** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions +** YY_MIN_REDUCE Maximum value for reduce actions +** YY_ERROR_ACTION The yy_action[] code for syntax error +** YY_ACCEPT_ACTION The yy_action[] code for accept +** YY_NO_ACTION The yy_action[] code for no-op +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ +#define YYCODETYPE unsigned char +#define YYNOCODE 252 +#define YYACTIONTYPE unsigned short int +#define YYWILDCARD 96 +#define sqlite3ParserTOKENTYPE Token +typedef union { + int yyinit; + sqlite3ParserTOKENTYPE yy0; + Expr* yy72; + TriggerStep* yy145; + ExprList* yy148; + SrcList* yy185; + ExprSpan yy190; + int yy194; + Select* yy243; + IdList* yy254; + With* yy285; + struct TrigEvent yy332; + struct LimitVal yy354; + struct {int value; int mask;} yy497; +} YYMINORTYPE; +#ifndef YYSTACKDEPTH +#define YYSTACKDEPTH 100 +#endif +#define sqlite3ParserARG_SDECL Parse *pParse; +#define sqlite3ParserARG_PDECL ,Parse *pParse +#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse +#define sqlite3ParserARG_STORE yypParser->pParse = pParse +#define YYFALLBACK 1 +#define YYNSTATE 460 +#define YYNRULE 332 +#define YY_MAX_SHIFT 459 +#define YY_MIN_SHIFTREDUCE 672 +#define YY_MAX_SHIFTREDUCE 1003 +#define YY_MIN_REDUCE 1004 +#define YY_MAX_REDUCE 1335 +#define YY_ERROR_ACTION 1336 +#define YY_ACCEPT_ACTION 1337 +#define YY_NO_ACTION 1338 +/************* End control #defines *******************************************/ + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. +** +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE +** and YY_MAX_REDUCE +** +** N == YY_ERROR_ACTION A syntax error has occurred. +** +** N == YY_ACCEPT_ACTION The parser accepts its input. +** +** N == YY_NO_ACTION No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large table named yy_action[]. +** Given state S and lookahead X, the action is computed as either: +** +** (A) N = yy_action[ yy_shift_ofst[S] + X ] +** (B) N = yy_default[S] +** +** The (A) formula is preferred. The B formula is used instead if: +** (1) The yy_shift_ofst[S]+X value is out of range, or +** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or +** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. +** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that +** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) +** +** The formulas above are for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the yy_reduce_ofst[] array is used in place of +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of +** YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** yy_action[] A single table containing all actions. +** yy_lookahead[] A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** yy_shift_ofst[] For each state, the offset into yy_action for +** shifting terminals. +** yy_reduce_ofst[] For each state, the offset into yy_action for +** shifting non-terminals after a reduce. +** yy_default[] Default action for each state. +** +*********** Begin parsing tables **********************************************/ +#define YY_ACTTAB_COUNT (1570) +static const YYACTIONTYPE yy_action[] = { + /* 0 */ 329, 836, 355, 829, 5, 203, 203, 823, 99, 100, + /* 10 */ 90, 846, 846, 858, 861, 850, 850, 97, 97, 98, + /* 20 */ 98, 98, 98, 305, 96, 96, 96, 96, 95, 95, + /* 30 */ 94, 94, 94, 93, 355, 329, 981, 981, 828, 828, + /* 40 */ 830, 951, 358, 99, 100, 90, 846, 846, 858, 861, + /* 50 */ 850, 850, 97, 97, 98, 98, 98, 98, 342, 96, + /* 60 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 355, + /* 70 */ 95, 95, 94, 94, 94, 93, 355, 795, 981, 981, + /* 80 */ 329, 94, 94, 94, 93, 355, 796, 75, 99, 100, + /* 90 */ 90, 846, 846, 858, 861, 850, 850, 97, 97, 98, + /* 100 */ 98, 98, 98, 454, 96, 96, 96, 96, 95, 95, + /* 110 */ 94, 94, 94, 93, 355, 1337, 155, 155, 2, 329, + /* 120 */ 279, 146, 132, 52, 52, 93, 355, 99, 100, 90, + /* 130 */ 846, 846, 858, 861, 850, 850, 97, 97, 98, 98, + /* 140 */ 98, 98, 101, 96, 96, 96, 96, 95, 95, 94, + /* 150 */ 94, 94, 93, 355, 962, 962, 329, 272, 432, 417, + /* 160 */ 415, 61, 756, 756, 99, 100, 90, 846, 846, 858, + /* 170 */ 861, 850, 850, 97, 97, 98, 98, 98, 98, 60, + /* 180 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 190 */ 355, 329, 274, 333, 277, 281, 963, 964, 250, 99, + /* 200 */ 100, 90, 846, 846, 858, 861, 850, 850, 97, 97, + /* 210 */ 98, 98, 98, 98, 305, 96, 96, 96, 96, 95, + /* 220 */ 95, 94, 94, 94, 93, 355, 329, 942, 1330, 702, + /* 230 */ 710, 1330, 242, 416, 99, 100, 90, 846, 846, 858, + /* 240 */ 861, 850, 850, 97, 97, 98, 98, 98, 98, 351, + /* 250 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 260 */ 355, 329, 942, 1331, 388, 703, 1331, 385, 383, 99, + /* 270 */ 100, 90, 846, 846, 858, 861, 850, 850, 97, 97, + /* 280 */ 98, 98, 98, 98, 705, 96, 96, 96, 96, 95, + /* 290 */ 95, 94, 94, 94, 93, 355, 329, 92, 89, 178, + /* 300 */ 837, 940, 377, 704, 99, 100, 90, 846, 846, 858, + /* 310 */ 861, 850, 850, 97, 97, 98, 98, 98, 98, 379, + /* 320 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 330 */ 355, 329, 1280, 951, 358, 822, 940, 743, 743, 99, + /* 340 */ 100, 90, 846, 846, 858, 861, 850, 850, 97, 97, + /* 350 */ 98, 98, 98, 98, 230, 96, 96, 96, 96, 95, + /* 360 */ 95, 94, 94, 94, 93, 355, 329, 973, 227, 92, + /* 370 */ 89, 178, 377, 304, 99, 100, 90, 846, 846, 858, + /* 380 */ 861, 850, 850, 97, 97, 98, 98, 98, 98, 925, + /* 390 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 400 */ 355, 329, 453, 451, 451, 451, 147, 741, 741, 99, + /* 410 */ 100, 90, 846, 846, 858, 861, 850, 850, 97, 97, + /* 420 */ 98, 98, 98, 98, 300, 96, 96, 96, 96, 95, + /* 430 */ 95, 94, 94, 94, 93, 355, 329, 423, 231, 962, + /* 440 */ 962, 158, 25, 426, 99, 100, 90, 846, 846, 858, + /* 450 */ 861, 850, 850, 97, 97, 98, 98, 98, 98, 454, + /* 460 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 470 */ 355, 447, 224, 224, 424, 962, 962, 966, 329, 52, + /* 480 */ 52, 963, 964, 176, 419, 78, 99, 100, 90, 846, + /* 490 */ 846, 858, 861, 850, 850, 97, 97, 98, 98, 98, + /* 500 */ 98, 383, 96, 96, 96, 96, 95, 95, 94, 94, + /* 510 */ 94, 93, 355, 329, 432, 422, 302, 963, 964, 966, + /* 520 */ 81, 99, 88, 90, 846, 846, 858, 861, 850, 850, + /* 530 */ 97, 97, 98, 98, 98, 98, 721, 96, 96, 96, + /* 540 */ 96, 95, 95, 94, 94, 94, 93, 355, 329, 847, + /* 550 */ 847, 859, 862, 1000, 322, 347, 383, 100, 90, 846, + /* 560 */ 846, 858, 861, 850, 850, 97, 97, 98, 98, 98, + /* 570 */ 98, 454, 96, 96, 96, 96, 95, 95, 94, 94, + /* 580 */ 94, 93, 355, 329, 354, 354, 354, 264, 381, 344, + /* 590 */ 933, 52, 52, 90, 846, 846, 858, 861, 850, 850, + /* 600 */ 97, 97, 98, 98, 98, 98, 365, 96, 96, 96, + /* 610 */ 96, 95, 95, 94, 94, 94, 93, 355, 86, 449, + /* 620 */ 851, 3, 1207, 365, 364, 382, 348, 817, 962, 962, + /* 630 */ 1304, 86, 449, 733, 3, 212, 169, 291, 409, 286, + /* 640 */ 408, 199, 232, 454, 304, 764, 83, 84, 284, 245, + /* 650 */ 266, 369, 253, 85, 356, 356, 92, 89, 178, 83, + /* 660 */ 84, 242, 416, 52, 52, 452, 85, 356, 356, 246, + /* 670 */ 963, 964, 194, 459, 674, 406, 403, 402, 452, 243, + /* 680 */ 221, 114, 438, 780, 365, 454, 401, 272, 751, 224, + /* 690 */ 224, 132, 132, 198, 836, 438, 456, 455, 432, 431, + /* 700 */ 823, 419, 738, 717, 132, 52, 52, 836, 272, 456, + /* 710 */ 455, 738, 194, 823, 367, 406, 403, 402, 454, 1275, + /* 720 */ 1275, 23, 962, 962, 86, 449, 401, 3, 228, 433, + /* 730 */ 899, 828, 828, 830, 831, 19, 203, 724, 52, 52, + /* 740 */ 432, 412, 443, 249, 828, 828, 830, 831, 19, 229, + /* 750 */ 407, 153, 83, 84, 765, 177, 241, 454, 725, 85, + /* 760 */ 356, 356, 120, 157, 963, 964, 58, 981, 413, 359, + /* 770 */ 334, 452, 272, 432, 434, 324, 794, 32, 32, 86, + /* 780 */ 449, 780, 3, 345, 98, 98, 98, 98, 438, 96, + /* 790 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 355, + /* 800 */ 836, 120, 456, 455, 817, 891, 823, 83, 84, 981, + /* 810 */ 817, 132, 414, 924, 85, 356, 356, 132, 411, 793, + /* 820 */ 962, 962, 92, 89, 178, 921, 452, 266, 374, 265, + /* 830 */ 82, 918, 80, 266, 374, 265, 780, 828, 828, 830, + /* 840 */ 831, 19, 938, 438, 96, 96, 96, 96, 95, 95, + /* 850 */ 94, 94, 94, 93, 355, 836, 74, 456, 455, 962, + /* 860 */ 962, 823, 963, 964, 120, 92, 89, 178, 949, 2, + /* 870 */ 922, 969, 272, 1, 980, 76, 449, 766, 3, 712, + /* 880 */ 905, 905, 391, 962, 962, 761, 923, 375, 744, 782, + /* 890 */ 760, 261, 828, 828, 830, 831, 19, 421, 745, 454, + /* 900 */ 24, 963, 964, 83, 84, 373, 962, 962, 177, 226, + /* 910 */ 85, 356, 356, 889, 319, 318, 317, 215, 315, 10, + /* 920 */ 10, 687, 452, 353, 352, 963, 964, 913, 781, 157, + /* 930 */ 120, 962, 962, 341, 780, 420, 715, 314, 454, 438, + /* 940 */ 454, 325, 454, 795, 103, 200, 175, 454, 963, 964, + /* 950 */ 912, 836, 796, 456, 455, 9, 9, 823, 10, 10, + /* 960 */ 52, 52, 51, 51, 180, 720, 248, 10, 10, 171, + /* 970 */ 170, 167, 343, 963, 964, 247, 988, 706, 706, 454, + /* 980 */ 719, 233, 690, 986, 893, 987, 182, 918, 828, 828, + /* 990 */ 830, 831, 19, 183, 260, 427, 132, 181, 398, 10, + /* 1000 */ 10, 893, 895, 753, 962, 962, 921, 272, 989, 198, + /* 1010 */ 989, 353, 352, 429, 419, 303, 821, 836, 330, 829, + /* 1020 */ 120, 336, 133, 823, 272, 98, 98, 98, 98, 91, + /* 1030 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 1040 */ 355, 157, 814, 375, 386, 363, 963, 964, 362, 272, + /* 1050 */ 454, 922, 372, 328, 828, 828, 830, 454, 713, 454, + /* 1060 */ 268, 384, 893, 454, 881, 750, 257, 923, 259, 437, + /* 1070 */ 36, 36, 234, 454, 234, 120, 273, 37, 37, 12, + /* 1080 */ 12, 338, 276, 27, 27, 454, 334, 118, 454, 162, + /* 1090 */ 746, 284, 454, 38, 38, 454, 989, 360, 989, 454, + /* 1100 */ 713, 1214, 454, 132, 454, 39, 39, 454, 40, 40, + /* 1110 */ 454, 366, 41, 41, 454, 42, 42, 454, 258, 28, + /* 1120 */ 28, 454, 29, 29, 31, 31, 454, 43, 43, 454, + /* 1130 */ 44, 44, 454, 718, 45, 45, 454, 11, 11, 771, + /* 1140 */ 454, 46, 46, 454, 272, 454, 105, 105, 454, 47, + /* 1150 */ 47, 454, 48, 48, 454, 237, 33, 33, 454, 172, + /* 1160 */ 49, 49, 454, 50, 50, 34, 34, 278, 122, 122, + /* 1170 */ 454, 123, 123, 454, 124, 124, 454, 902, 56, 56, + /* 1180 */ 454, 901, 35, 35, 454, 271, 454, 821, 454, 821, + /* 1190 */ 106, 106, 454, 53, 53, 389, 107, 107, 454, 821, + /* 1200 */ 108, 108, 821, 454, 104, 104, 121, 121, 119, 119, + /* 1210 */ 454, 117, 112, 112, 454, 280, 454, 225, 111, 111, + /* 1220 */ 454, 734, 454, 109, 109, 454, 677, 678, 679, 916, + /* 1230 */ 110, 110, 321, 1002, 55, 55, 57, 57, 696, 335, + /* 1240 */ 54, 54, 26, 26, 700, 30, 30, 321, 941, 197, + /* 1250 */ 196, 195, 339, 285, 340, 450, 335, 749, 693, 440, + /* 1260 */ 444, 448, 120, 72, 390, 223, 175, 349, 761, 937, + /* 1270 */ 20, 290, 323, 760, 819, 376, 378, 202, 202, 202, + /* 1280 */ 267, 399, 289, 74, 208, 21, 700, 723, 722, 888, + /* 1290 */ 120, 120, 120, 120, 120, 758, 282, 832, 77, 74, + /* 1300 */ 730, 731, 789, 787, 884, 202, 1003, 208, 898, 897, + /* 1310 */ 898, 897, 698, 820, 767, 116, 778, 1294, 435, 436, + /* 1320 */ 306, 1003, 394, 307, 827, 701, 695, 684, 159, 293, + /* 1330 */ 683, 888, 685, 956, 295, 218, 297, 7, 320, 832, + /* 1340 */ 173, 252, 263, 368, 256, 915, 380, 717, 299, 439, + /* 1350 */ 312, 168, 959, 997, 135, 404, 994, 288, 886, 885, + /* 1360 */ 205, 932, 930, 59, 337, 62, 144, 156, 102, 430, + /* 1370 */ 809, 72, 130, 251, 137, 370, 371, 397, 185, 160, + /* 1380 */ 387, 189, 67, 393, 139, 140, 141, 779, 142, 148, + /* 1390 */ 816, 806, 255, 900, 254, 270, 219, 154, 190, 917, + /* 1400 */ 880, 395, 410, 275, 326, 191, 737, 736, 686, 735, + /* 1410 */ 346, 728, 192, 327, 715, 425, 6, 71, 350, 79, + /* 1420 */ 775, 292, 204, 776, 709, 774, 294, 296, 301, 773, + /* 1430 */ 287, 708, 866, 298, 707, 971, 757, 213, 428, 442, + /* 1440 */ 238, 727, 446, 73, 239, 240, 692, 22, 957, 457, + /* 1450 */ 214, 216, 217, 458, 681, 680, 675, 125, 115, 126, + /* 1460 */ 673, 235, 357, 166, 127, 244, 179, 361, 308, 309, + /* 1470 */ 310, 311, 896, 113, 815, 331, 894, 136, 128, 332, + /* 1480 */ 747, 138, 262, 911, 143, 184, 145, 63, 129, 64, + /* 1490 */ 914, 65, 66, 186, 187, 910, 8, 13, 188, 903, + /* 1500 */ 202, 991, 269, 149, 392, 150, 689, 161, 396, 289, + /* 1510 */ 193, 283, 151, 134, 68, 400, 405, 14, 15, 726, + /* 1520 */ 69, 236, 835, 834, 864, 755, 131, 16, 70, 759, + /* 1530 */ 4, 201, 174, 418, 220, 222, 788, 152, 868, 783, + /* 1540 */ 77, 17, 74, 18, 879, 865, 863, 920, 210, 919, + /* 1550 */ 207, 206, 946, 163, 441, 211, 947, 164, 209, 165, + /* 1560 */ 445, 867, 833, 699, 87, 1296, 1295, 313, 316, 952, +}; +static const YYCODETYPE yy_lookahead[] = { + /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28, + /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48, + /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133, + /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33, + /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 187, 43, + /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97, + /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28, + /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48, + /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19, + /* 120 */ 16, 22, 92, 172, 173, 52, 53, 27, 28, 29, + /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49, + /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208, + /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32, + /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79, + /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 190 */ 53, 19, 88, 157, 90, 23, 97, 98, 193, 27, + /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, + /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172, + /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32, + /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187, + /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 260 */ 53, 19, 22, 23, 228, 23, 26, 231, 152, 27, + /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + /* 280 */ 38, 39, 40, 41, 172, 43, 44, 45, 46, 47, + /* 290 */ 48, 49, 50, 51, 52, 53, 19, 221, 222, 223, + /* 300 */ 23, 96, 152, 172, 27, 28, 29, 30, 31, 32, + /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152, + /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 330 */ 53, 19, 0, 1, 2, 23, 96, 190, 191, 27, + /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + /* 350 */ 38, 39, 40, 41, 238, 43, 44, 45, 46, 47, + /* 360 */ 48, 49, 50, 51, 52, 53, 19, 185, 218, 221, + /* 370 */ 222, 223, 152, 152, 27, 28, 29, 30, 31, 32, + /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 241, + /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 400 */ 53, 19, 152, 168, 169, 170, 22, 190, 191, 27, + /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, + /* 430 */ 48, 49, 50, 51, 52, 53, 19, 19, 218, 55, + /* 440 */ 56, 24, 22, 152, 27, 28, 29, 30, 31, 32, + /* 450 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152, + /* 460 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 470 */ 53, 250, 194, 195, 56, 55, 56, 55, 19, 172, + /* 480 */ 173, 97, 98, 152, 206, 138, 27, 28, 29, 30, + /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + /* 500 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50, + /* 510 */ 51, 52, 53, 19, 207, 208, 152, 97, 98, 97, + /* 520 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35, + /* 530 */ 36, 37, 38, 39, 40, 41, 181, 43, 44, 45, + /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 30, + /* 550 */ 31, 32, 33, 247, 248, 19, 152, 28, 29, 30, + /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50, + /* 580 */ 51, 52, 53, 19, 168, 169, 170, 238, 19, 53, + /* 590 */ 152, 172, 173, 29, 30, 31, 32, 33, 34, 35, + /* 600 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45, + /* 610 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 20, + /* 620 */ 101, 22, 23, 169, 170, 56, 207, 85, 55, 56, + /* 630 */ 23, 19, 20, 26, 22, 99, 100, 101, 102, 103, + /* 640 */ 104, 105, 238, 152, 152, 210, 47, 48, 112, 152, + /* 650 */ 108, 109, 110, 54, 55, 56, 221, 222, 223, 47, + /* 660 */ 48, 119, 120, 172, 173, 66, 54, 55, 56, 152, + /* 670 */ 97, 98, 99, 148, 149, 102, 103, 104, 66, 154, + /* 680 */ 23, 156, 83, 26, 230, 152, 113, 152, 163, 194, + /* 690 */ 195, 92, 92, 30, 95, 83, 97, 98, 207, 208, + /* 700 */ 101, 206, 179, 180, 92, 172, 173, 95, 152, 97, + /* 710 */ 98, 188, 99, 101, 219, 102, 103, 104, 152, 119, + /* 720 */ 120, 196, 55, 56, 19, 20, 113, 22, 193, 163, + /* 730 */ 11, 132, 133, 134, 135, 136, 24, 65, 172, 173, + /* 740 */ 207, 208, 250, 152, 132, 133, 134, 135, 136, 193, + /* 750 */ 78, 84, 47, 48, 49, 98, 199, 152, 86, 54, + /* 760 */ 55, 56, 196, 152, 97, 98, 209, 55, 163, 244, + /* 770 */ 107, 66, 152, 207, 208, 164, 175, 172, 173, 19, + /* 780 */ 20, 124, 22, 111, 38, 39, 40, 41, 83, 43, + /* 790 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 800 */ 95, 196, 97, 98, 85, 152, 101, 47, 48, 97, + /* 810 */ 85, 92, 207, 193, 54, 55, 56, 92, 49, 175, + /* 820 */ 55, 56, 221, 222, 223, 12, 66, 108, 109, 110, + /* 830 */ 137, 163, 139, 108, 109, 110, 26, 132, 133, 134, + /* 840 */ 135, 136, 152, 83, 43, 44, 45, 46, 47, 48, + /* 850 */ 49, 50, 51, 52, 53, 95, 26, 97, 98, 55, + /* 860 */ 56, 101, 97, 98, 196, 221, 222, 223, 146, 147, + /* 870 */ 57, 171, 152, 22, 26, 19, 20, 49, 22, 179, + /* 880 */ 108, 109, 110, 55, 56, 116, 73, 219, 75, 124, + /* 890 */ 121, 152, 132, 133, 134, 135, 136, 163, 85, 152, + /* 900 */ 232, 97, 98, 47, 48, 237, 55, 56, 98, 5, + /* 910 */ 54, 55, 56, 193, 10, 11, 12, 13, 14, 172, + /* 920 */ 173, 17, 66, 47, 48, 97, 98, 152, 124, 152, + /* 930 */ 196, 55, 56, 186, 124, 152, 106, 160, 152, 83, + /* 940 */ 152, 164, 152, 61, 22, 211, 212, 152, 97, 98, + /* 950 */ 152, 95, 70, 97, 98, 172, 173, 101, 172, 173, + /* 960 */ 172, 173, 172, 173, 60, 181, 62, 172, 173, 47, + /* 970 */ 48, 123, 186, 97, 98, 71, 100, 55, 56, 152, + /* 980 */ 181, 186, 21, 107, 152, 109, 82, 163, 132, 133, + /* 990 */ 134, 135, 136, 89, 16, 207, 92, 93, 19, 172, + /* 1000 */ 173, 169, 170, 195, 55, 56, 12, 152, 132, 30, + /* 1010 */ 134, 47, 48, 186, 206, 225, 152, 95, 114, 97, + /* 1020 */ 196, 245, 246, 101, 152, 38, 39, 40, 41, 42, + /* 1030 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 1040 */ 53, 152, 163, 219, 152, 141, 97, 98, 193, 152, + /* 1050 */ 152, 57, 91, 164, 132, 133, 134, 152, 55, 152, + /* 1060 */ 152, 237, 230, 152, 103, 193, 88, 73, 90, 75, + /* 1070 */ 172, 173, 183, 152, 185, 196, 152, 172, 173, 172, + /* 1080 */ 173, 217, 152, 172, 173, 152, 107, 22, 152, 24, + /* 1090 */ 193, 112, 152, 172, 173, 152, 132, 242, 134, 152, + /* 1100 */ 97, 140, 152, 92, 152, 172, 173, 152, 172, 173, + /* 1110 */ 152, 100, 172, 173, 152, 172, 173, 152, 140, 172, + /* 1120 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152, + /* 1130 */ 172, 173, 152, 152, 172, 173, 152, 172, 173, 213, + /* 1140 */ 152, 172, 173, 152, 152, 152, 172, 173, 152, 172, + /* 1150 */ 173, 152, 172, 173, 152, 210, 172, 173, 152, 26, + /* 1160 */ 172, 173, 152, 172, 173, 172, 173, 152, 172, 173, + /* 1170 */ 152, 172, 173, 152, 172, 173, 152, 59, 172, 173, + /* 1180 */ 152, 63, 172, 173, 152, 193, 152, 152, 152, 152, + /* 1190 */ 172, 173, 152, 172, 173, 77, 172, 173, 152, 152, + /* 1200 */ 172, 173, 152, 152, 172, 173, 172, 173, 172, 173, + /* 1210 */ 152, 22, 172, 173, 152, 152, 152, 22, 172, 173, + /* 1220 */ 152, 152, 152, 172, 173, 152, 7, 8, 9, 163, + /* 1230 */ 172, 173, 22, 23, 172, 173, 172, 173, 166, 167, + /* 1240 */ 172, 173, 172, 173, 55, 172, 173, 22, 23, 108, + /* 1250 */ 109, 110, 217, 152, 217, 166, 167, 163, 163, 163, + /* 1260 */ 163, 163, 196, 130, 217, 211, 212, 217, 116, 23, + /* 1270 */ 22, 101, 26, 121, 23, 23, 23, 26, 26, 26, + /* 1280 */ 23, 23, 112, 26, 26, 37, 97, 100, 101, 55, + /* 1290 */ 196, 196, 196, 196, 196, 23, 23, 55, 26, 26, + /* 1300 */ 7, 8, 23, 152, 23, 26, 96, 26, 132, 132, + /* 1310 */ 134, 134, 23, 152, 152, 26, 152, 122, 152, 191, + /* 1320 */ 152, 96, 234, 152, 152, 152, 152, 152, 197, 210, + /* 1330 */ 152, 97, 152, 152, 210, 233, 210, 198, 150, 97, + /* 1340 */ 184, 201, 239, 214, 214, 201, 239, 180, 214, 227, + /* 1350 */ 200, 198, 155, 67, 243, 176, 69, 175, 175, 175, + /* 1360 */ 122, 159, 159, 240, 159, 240, 22, 220, 129, 126, + /* 1370 */ 205, 130, 27, 204, 189, 18, 159, 18, 158, 220, + /* 1380 */ 159, 158, 137, 74, 192, 192, 192, 159, 192, 189, + /* 1390 */ 189, 205, 201, 236, 204, 235, 159, 22, 158, 201, + /* 1400 */ 201, 177, 107, 159, 177, 158, 174, 174, 159, 174, + /* 1410 */ 76, 182, 158, 177, 106, 125, 22, 107, 53, 137, + /* 1420 */ 216, 215, 159, 216, 174, 216, 215, 215, 159, 216, + /* 1430 */ 174, 176, 224, 215, 174, 174, 205, 25, 127, 177, + /* 1440 */ 226, 182, 177, 128, 229, 229, 162, 26, 13, 161, + /* 1450 */ 153, 153, 6, 151, 151, 151, 151, 165, 178, 165, + /* 1460 */ 4, 178, 3, 22, 165, 142, 15, 94, 204, 203, + /* 1470 */ 202, 201, 23, 16, 120, 249, 23, 131, 111, 249, + /* 1480 */ 20, 123, 16, 1, 123, 125, 131, 37, 111, 37, + /* 1490 */ 56, 37, 37, 64, 122, 1, 5, 22, 107, 80, + /* 1500 */ 26, 87, 140, 80, 72, 107, 20, 24, 19, 112, + /* 1510 */ 105, 23, 22, 246, 22, 79, 79, 22, 22, 58, + /* 1520 */ 22, 79, 23, 23, 23, 116, 68, 22, 26, 23, + /* 1530 */ 22, 64, 122, 26, 23, 23, 56, 22, 11, 124, + /* 1540 */ 26, 64, 26, 64, 23, 23, 23, 23, 122, 23, + /* 1550 */ 22, 26, 23, 22, 24, 122, 23, 22, 26, 22, + /* 1560 */ 24, 23, 23, 23, 22, 122, 122, 23, 15, 1, +}; +#define YY_SHIFT_USE_DFLT (1570) +#define YY_SHIFT_COUNT (459) +#define YY_SHIFT_MIN (-94) +#define YY_SHIFT_MAX (1568) +static const short yy_shift_ofst[] = { + /* 0 */ 40, 599, 904, 612, 760, 760, 760, 760, 725, -19, + /* 10 */ 16, 16, 100, 760, 760, 760, 760, 760, 760, 760, + /* 20 */ 876, 876, 573, 542, 719, 600, 61, 137, 172, 207, + /* 30 */ 242, 277, 312, 347, 382, 417, 459, 459, 459, 459, + /* 40 */ 459, 459, 459, 459, 459, 459, 459, 459, 459, 459, + /* 50 */ 459, 459, 459, 494, 459, 529, 564, 564, 705, 760, + /* 60 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, + /* 70 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, + /* 80 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, + /* 90 */ 856, 760, 760, 760, 760, 760, 760, 760, 760, 760, + /* 100 */ 760, 760, 760, 760, 987, 746, 746, 746, 746, 746, + /* 110 */ 801, 23, 32, 949, 961, 979, 964, 964, 949, 73, + /* 120 */ 113, -51, 1570, 1570, 1570, 536, 536, 536, 99, 99, + /* 130 */ 813, 813, 667, 205, 240, 949, 949, 949, 949, 949, + /* 140 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, + /* 150 */ 949, 949, 949, 949, 949, 332, 1011, 422, 422, 113, + /* 160 */ 30, 30, 30, 30, 30, 30, 1570, 1570, 1570, 922, + /* 170 */ -94, -94, 384, 613, 828, 420, 765, 804, 851, 949, + /* 180 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, + /* 190 */ 949, 949, 949, 949, 949, 672, 672, 672, 949, 949, + /* 200 */ 657, 949, 949, 949, -18, 949, 949, 994, 949, 949, + /* 210 */ 949, 949, 949, 949, 949, 949, 949, 949, 772, 1118, + /* 220 */ 712, 712, 712, 810, 45, 769, 1219, 1133, 418, 418, + /* 230 */ 569, 1133, 569, 830, 607, 663, 882, 418, 693, 882, + /* 240 */ 882, 848, 1152, 1065, 1286, 1238, 1238, 1287, 1287, 1238, + /* 250 */ 1344, 1239, 1243, 1345, 1239, 1243, 1241, 1357, 1357, 1357, + /* 260 */ 1357, 1238, 1359, 1241, 1344, 1345, 1345, 1241, 1238, 1359, + /* 270 */ 1245, 1309, 1238, 1238, 1359, 1375, 1238, 1359, 1238, 1359, + /* 280 */ 1375, 1295, 1295, 1295, 1334, 1375, 1295, 1308, 1295, 1334, + /* 290 */ 1295, 1295, 1290, 1310, 1290, 1310, 1290, 1310, 1290, 1310, + /* 300 */ 1238, 1394, 1238, 1282, 1375, 1365, 1365, 1375, 1239, 1243, + /* 310 */ 1315, 1311, 1241, 1412, 1421, 1435, 1435, 1446, 1446, 1446, + /* 320 */ 1446, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 519, + /* 330 */ 978, 1210, 1225, 104, 1141, 1189, 1246, 1248, 1251, 1252, + /* 340 */ 1253, 1257, 1258, 1273, 1003, 1187, 1293, 1170, 1272, 1279, + /* 350 */ 1234, 1281, 1176, 1177, 1289, 1242, 1195, 1456, 1459, 1441, + /* 360 */ 1323, 1451, 1373, 1457, 1449, 1453, 1354, 1346, 1367, 1358, + /* 370 */ 1460, 1360, 1466, 1482, 1361, 1355, 1450, 1452, 1454, 1455, + /* 380 */ 1377, 1434, 1429, 1372, 1494, 1491, 1475, 1391, 1362, 1419, + /* 390 */ 1474, 1423, 1414, 1432, 1398, 1483, 1486, 1489, 1397, 1405, + /* 400 */ 1490, 1436, 1492, 1495, 1488, 1496, 1437, 1461, 1498, 1442, + /* 410 */ 1458, 1499, 1500, 1501, 1502, 1409, 1505, 1506, 1508, 1507, + /* 420 */ 1410, 1511, 1512, 1480, 1467, 1515, 1415, 1514, 1477, 1516, + /* 430 */ 1479, 1521, 1514, 1522, 1523, 1524, 1525, 1526, 1528, 1527, + /* 440 */ 1529, 1531, 1530, 1532, 1533, 1535, 1536, 1532, 1538, 1537, + /* 450 */ 1539, 1540, 1542, 1426, 1433, 1443, 1444, 1544, 1553, 1568, +}; +#define YY_REDUCE_USE_DFLT (-130) +#define YY_REDUCE_COUNT (328) +#define YY_REDUCE_MIN (-129) +#define YY_REDUCE_MAX (1305) +static const short yy_reduce_ofst[] = { + /* 0 */ -29, 566, 525, 605, -49, 307, 491, 533, 668, 435, + /* 10 */ 601, 644, 148, 747, 786, 795, 419, 788, 827, 790, + /* 20 */ 454, 832, 889, 495, 824, 734, 76, 76, 76, 76, + /* 30 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + /* 40 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + /* 50 */ 76, 76, 76, 76, 76, 76, 76, 76, 783, 898, + /* 60 */ 905, 907, 911, 921, 933, 936, 940, 943, 947, 950, + /* 70 */ 952, 955, 958, 962, 965, 969, 974, 977, 980, 984, + /* 80 */ 988, 991, 993, 996, 999, 1002, 1006, 1010, 1018, 1021, + /* 90 */ 1024, 1028, 1032, 1034, 1036, 1040, 1046, 1051, 1058, 1062, + /* 100 */ 1064, 1068, 1070, 1073, 76, 76, 76, 76, 76, 76, + /* 110 */ 76, 76, 76, 855, 36, 523, 235, 416, 777, 76, + /* 120 */ 278, 76, 76, 76, 76, 700, 700, 700, 150, 220, + /* 130 */ 147, 217, 221, 306, 306, 611, 5, 535, 556, 620, + /* 140 */ 720, 872, 897, 116, 864, 349, 1035, 1037, 404, 1047, + /* 150 */ 992, -129, 1050, 492, 62, 722, 879, 1072, 1089, 808, + /* 160 */ 1066, 1094, 1095, 1096, 1097, 1098, 776, 1054, 557, 57, + /* 170 */ 112, 131, 167, 182, 250, 272, 291, 331, 364, 438, + /* 180 */ 497, 517, 591, 653, 690, 739, 775, 798, 892, 908, + /* 190 */ 924, 930, 1015, 1063, 1069, 355, 784, 799, 981, 1101, + /* 200 */ 926, 1151, 1161, 1162, 945, 1164, 1166, 1128, 1168, 1171, + /* 210 */ 1172, 250, 1173, 1174, 1175, 1178, 1180, 1181, 1088, 1102, + /* 220 */ 1119, 1124, 1126, 926, 1131, 1139, 1188, 1140, 1129, 1130, + /* 230 */ 1103, 1144, 1107, 1179, 1156, 1167, 1182, 1134, 1122, 1183, + /* 240 */ 1184, 1150, 1153, 1197, 1111, 1202, 1203, 1123, 1125, 1205, + /* 250 */ 1147, 1165, 1169, 1185, 1186, 1190, 1191, 1192, 1193, 1194, + /* 260 */ 1196, 1217, 1220, 1198, 1159, 1200, 1201, 1199, 1221, 1223, + /* 270 */ 1157, 1160, 1228, 1237, 1240, 1224, 1244, 1247, 1249, 1254, + /* 280 */ 1227, 1232, 1233, 1235, 1229, 1236, 1250, 1255, 1256, 1259, + /* 290 */ 1260, 1261, 1204, 1206, 1207, 1211, 1209, 1212, 1213, 1218, + /* 300 */ 1263, 1208, 1269, 1214, 1262, 1215, 1216, 1265, 1231, 1264, + /* 310 */ 1266, 1268, 1270, 1284, 1288, 1297, 1298, 1302, 1303, 1304, + /* 320 */ 1305, 1226, 1230, 1267, 1292, 1294, 1280, 1283, 1299, +}; +static const YYACTIONTYPE yy_default[] = { + /* 0 */ 1285, 1275, 1275, 1275, 1207, 1207, 1207, 1207, 1275, 1100, + /* 10 */ 1129, 1129, 1259, 1336, 1336, 1336, 1336, 1336, 1336, 1206, + /* 20 */ 1336, 1336, 1336, 1336, 1275, 1104, 1135, 1336, 1336, 1336, + /* 30 */ 1336, 1208, 1209, 1336, 1336, 1336, 1258, 1260, 1145, 1144, + /* 40 */ 1143, 1142, 1241, 1116, 1140, 1133, 1137, 1208, 1202, 1203, + /* 50 */ 1201, 1205, 1209, 1336, 1136, 1171, 1186, 1170, 1336, 1336, + /* 60 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 70 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 80 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 90 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 100 */ 1336, 1336, 1336, 1336, 1180, 1185, 1192, 1184, 1181, 1173, + /* 110 */ 1172, 1174, 1175, 1336, 1023, 1071, 1336, 1336, 1336, 1176, + /* 120 */ 1336, 1177, 1189, 1188, 1187, 1266, 1293, 1292, 1336, 1336, + /* 130 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 140 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 150 */ 1336, 1336, 1336, 1336, 1336, 1285, 1275, 1029, 1029, 1336, + /* 160 */ 1275, 1275, 1275, 1275, 1275, 1275, 1271, 1104, 1095, 1336, + /* 170 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 180 */ 1263, 1261, 1336, 1222, 1336, 1336, 1336, 1336, 1336, 1336, + /* 190 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 200 */ 1336, 1336, 1336, 1336, 1100, 1336, 1336, 1336, 1336, 1336, + /* 210 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1287, 1336, 1236, + /* 220 */ 1100, 1100, 1100, 1102, 1084, 1094, 1008, 1139, 1118, 1118, + /* 230 */ 1325, 1139, 1325, 1046, 1307, 1043, 1129, 1118, 1204, 1129, + /* 240 */ 1129, 1101, 1094, 1336, 1328, 1109, 1109, 1327, 1327, 1109, + /* 250 */ 1150, 1134, 1123, 1074, 1134, 1123, 1139, 1080, 1080, 1080, + /* 260 */ 1080, 1109, 1020, 1139, 1150, 1074, 1074, 1139, 1109, 1020, + /* 270 */ 1240, 1322, 1109, 1109, 1020, 1215, 1109, 1020, 1109, 1020, + /* 280 */ 1215, 1072, 1072, 1072, 1061, 1215, 1072, 1046, 1072, 1061, + /* 290 */ 1072, 1072, 1122, 1117, 1122, 1117, 1122, 1117, 1122, 1117, + /* 300 */ 1109, 1210, 1109, 1336, 1215, 1219, 1219, 1215, 1134, 1123, + /* 310 */ 1132, 1130, 1139, 1026, 1064, 1290, 1290, 1286, 1286, 1286, + /* 320 */ 1286, 1333, 1333, 1271, 1302, 1302, 1048, 1048, 1302, 1336, + /* 330 */ 1336, 1336, 1336, 1336, 1336, 1297, 1336, 1224, 1336, 1336, + /* 340 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 350 */ 1336, 1336, 1336, 1336, 1336, 1336, 1156, 1336, 1004, 1268, + /* 360 */ 1336, 1336, 1267, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 370 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 380 */ 1336, 1336, 1336, 1324, 1336, 1336, 1336, 1336, 1336, 1336, + /* 390 */ 1239, 1238, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 400 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 410 */ 1336, 1336, 1336, 1336, 1336, 1086, 1336, 1336, 1336, 1311, + /* 420 */ 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1131, 1336, 1124, + /* 430 */ 1336, 1336, 1315, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + /* 440 */ 1336, 1336, 1336, 1277, 1336, 1336, 1336, 1276, 1336, 1336, + /* 450 */ 1336, 1336, 1336, 1158, 1336, 1157, 1161, 1336, 1014, 1336, +}; +/********** End of lemon-generated parsing tables *****************************/ + +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +** +** This feature can be used, for example, to cause some keywords in a language +** to revert to identifiers if they keyword does not apply in the context where +** it appears. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { + 0, /* $ => nothing */ + 0, /* SEMI => nothing */ + 55, /* EXPLAIN => ID */ + 55, /* QUERY => ID */ + 55, /* PLAN => ID */ + 55, /* BEGIN => ID */ + 0, /* TRANSACTION => nothing */ + 55, /* DEFERRED => ID */ + 55, /* IMMEDIATE => ID */ + 55, /* EXCLUSIVE => ID */ + 0, /* COMMIT => nothing */ + 55, /* END => ID */ + 55, /* ROLLBACK => ID */ + 55, /* SAVEPOINT => ID */ + 55, /* RELEASE => ID */ + 0, /* TO => nothing */ + 0, /* TABLE => nothing */ + 0, /* CREATE => nothing */ + 55, /* IF => ID */ + 0, /* NOT => nothing */ + 0, /* EXISTS => nothing */ + 55, /* TEMP => ID */ + 0, /* LP => nothing */ + 0, /* RP => nothing */ + 0, /* AS => nothing */ + 55, /* WITHOUT => ID */ + 0, /* COMMA => nothing */ + 0, /* OR => nothing */ + 0, /* AND => nothing */ + 0, /* IS => nothing */ + 55, /* MATCH => ID */ + 55, /* LIKE_KW => ID */ + 0, /* BETWEEN => nothing */ + 0, /* IN => nothing */ + 0, /* ISNULL => nothing */ + 0, /* NOTNULL => nothing */ + 0, /* NE => nothing */ + 0, /* EQ => nothing */ + 0, /* GT => nothing */ + 0, /* LE => nothing */ + 0, /* LT => nothing */ + 0, /* GE => nothing */ + 0, /* ESCAPE => nothing */ + 0, /* BITAND => nothing */ + 0, /* BITOR => nothing */ + 0, /* LSHIFT => nothing */ + 0, /* RSHIFT => nothing */ + 0, /* PLUS => nothing */ + 0, /* MINUS => nothing */ + 0, /* STAR => nothing */ + 0, /* SLASH => nothing */ + 0, /* REM => nothing */ + 0, /* CONCAT => nothing */ + 0, /* COLLATE => nothing */ + 0, /* BITNOT => nothing */ + 0, /* ID => nothing */ + 0, /* INDEXED => nothing */ + 55, /* ABORT => ID */ + 55, /* ACTION => ID */ + 55, /* AFTER => ID */ + 55, /* ANALYZE => ID */ + 55, /* ASC => ID */ + 55, /* ATTACH => ID */ + 55, /* BEFORE => ID */ + 55, /* BY => ID */ + 55, /* CASCADE => ID */ + 55, /* CAST => ID */ + 55, /* COLUMNKW => ID */ + 55, /* CONFLICT => ID */ + 55, /* DATABASE => ID */ + 55, /* DESC => ID */ + 55, /* DETACH => ID */ + 55, /* EACH => ID */ + 55, /* FAIL => ID */ + 55, /* FOR => ID */ + 55, /* IGNORE => ID */ + 55, /* INITIALLY => ID */ + 55, /* INSTEAD => ID */ + 55, /* NO => ID */ + 55, /* KEY => ID */ + 55, /* OF => ID */ + 55, /* OFFSET => ID */ + 55, /* PRAGMA => ID */ + 55, /* RAISE => ID */ + 55, /* RECURSIVE => ID */ + 55, /* REPLACE => ID */ + 55, /* RESTRICT => ID */ + 55, /* ROW => ID */ + 55, /* TRIGGER => ID */ + 55, /* VACUUM => ID */ + 55, /* VIEW => ID */ + 55, /* VIRTUAL => ID */ + 55, /* WITH => ID */ + 55, /* REINDEX => ID */ + 55, /* RENAME => ID */ + 55, /* CTIME_KW => ID */ +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +** +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. +*/ +struct yyStackEntry { + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + yyStackEntry *yytos; /* Pointer to top element of the stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyhwm; /* High-water mark of the stack */ +#endif +#ifndef YYNOERRORRECOVERY + int yyerrcnt; /* Shifts left before out of the error */ +#endif + sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ +#endif +}; +typedef struct yyParser yyParser; + +#ifndef NDEBUG +#include +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** Outputs: +** None. +*/ +void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const yyTokenName[] = { + "$", "SEMI", "EXPLAIN", "QUERY", + "PLAN", "BEGIN", "TRANSACTION", "DEFERRED", + "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END", + "ROLLBACK", "SAVEPOINT", "RELEASE", "TO", + "TABLE", "CREATE", "IF", "NOT", + "EXISTS", "TEMP", "LP", "RP", + "AS", "WITHOUT", "COMMA", "OR", + "AND", "IS", "MATCH", "LIKE_KW", + "BETWEEN", "IN", "ISNULL", "NOTNULL", + "NE", "EQ", "GT", "LE", + "LT", "GE", "ESCAPE", "BITAND", + "BITOR", "LSHIFT", "RSHIFT", "PLUS", + "MINUS", "STAR", "SLASH", "REM", + "CONCAT", "COLLATE", "BITNOT", "ID", + "INDEXED", "ABORT", "ACTION", "AFTER", + "ANALYZE", "ASC", "ATTACH", "BEFORE", + "BY", "CASCADE", "CAST", "COLUMNKW", + "CONFLICT", "DATABASE", "DESC", "DETACH", + "EACH", "FAIL", "FOR", "IGNORE", + "INITIALLY", "INSTEAD", "NO", "KEY", + "OF", "OFFSET", "PRAGMA", "RAISE", + "RECURSIVE", "REPLACE", "RESTRICT", "ROW", + "TRIGGER", "VACUUM", "VIEW", "VIRTUAL", + "WITH", "REINDEX", "RENAME", "CTIME_KW", + "ANY", "STRING", "JOIN_KW", "CONSTRAINT", + "DEFAULT", "NULL", "PRIMARY", "UNIQUE", + "CHECK", "REFERENCES", "AUTOINCR", "ON", + "INSERT", "DELETE", "UPDATE", "SET", + "DEFERRABLE", "FOREIGN", "DROP", "UNION", + "ALL", "EXCEPT", "INTERSECT", "SELECT", + "VALUES", "DISTINCT", "DOT", "FROM", + "JOIN", "USING", "ORDER", "GROUP", + "HAVING", "LIMIT", "WHERE", "INTO", + "FLOAT", "BLOB", "INTEGER", "VARIABLE", + "CASE", "WHEN", "THEN", "ELSE", + "INDEX", "ALTER", "ADD", "error", + "input", "cmdlist", "ecmd", "explain", + "cmdx", "cmd", "transtype", "trans_opt", + "nm", "savepoint_opt", "create_table", "create_table_args", + "createkw", "temp", "ifnotexists", "dbnm", + "columnlist", "conslist_opt", "table_options", "select", + "columnname", "carglist", "typetoken", "typename", + "signed", "plus_num", "minus_num", "ccons", + "term", "expr", "onconf", "sortorder", + "autoinc", "eidlist_opt", "refargs", "defer_subclause", + "refarg", "refact", "init_deferred_pred_opt", "conslist", + "tconscomma", "tcons", "sortlist", "eidlist", + "defer_subclause_opt", "orconf", "resolvetype", "raisetype", + "ifexists", "fullname", "selectnowith", "oneselect", + "with", "multiselect_op", "distinct", "selcollist", + "from", "where_opt", "groupby_opt", "having_opt", + "orderby_opt", "limit_opt", "values", "nexprlist", + "exprlist", "sclp", "as", "seltablist", + "stl_prefix", "joinop", "indexed_opt", "on_opt", + "using_opt", "idlist", "setlist", "insert_cmd", + "idlist_opt", "likeop", "between_op", "in_op", + "paren_exprlist", "case_operand", "case_exprlist", "case_else", + "uniqueflag", "collate", "nmnum", "trigger_decl", + "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause", + "when_clause", "trigger_cmd", "trnm", "tridxby", + "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt", + "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken", + "lp", "anylist", "wqlist", +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const yyRuleName[] = { + /* 0 */ "explain ::= EXPLAIN", + /* 1 */ "explain ::= EXPLAIN QUERY PLAN", + /* 2 */ "cmdx ::= cmd", + /* 3 */ "cmd ::= BEGIN transtype trans_opt", + /* 4 */ "transtype ::=", + /* 5 */ "transtype ::= DEFERRED", + /* 6 */ "transtype ::= IMMEDIATE", + /* 7 */ "transtype ::= EXCLUSIVE", + /* 8 */ "cmd ::= COMMIT trans_opt", + /* 9 */ "cmd ::= END trans_opt", + /* 10 */ "cmd ::= ROLLBACK trans_opt", + /* 11 */ "cmd ::= SAVEPOINT nm", + /* 12 */ "cmd ::= RELEASE savepoint_opt nm", + /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 15 */ "createkw ::= CREATE", + /* 16 */ "ifnotexists ::=", + /* 17 */ "ifnotexists ::= IF NOT EXISTS", + /* 18 */ "temp ::= TEMP", + /* 19 */ "temp ::=", + /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", + /* 21 */ "create_table_args ::= AS select", + /* 22 */ "table_options ::=", + /* 23 */ "table_options ::= WITHOUT nm", + /* 24 */ "columnname ::= nm typetoken", + /* 25 */ "typetoken ::=", + /* 26 */ "typetoken ::= typename LP signed RP", + /* 27 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 28 */ "typename ::= typename ID|STRING", + /* 29 */ "ccons ::= CONSTRAINT nm", + /* 30 */ "ccons ::= DEFAULT term", + /* 31 */ "ccons ::= DEFAULT LP expr RP", + /* 32 */ "ccons ::= DEFAULT PLUS term", + /* 33 */ "ccons ::= DEFAULT MINUS term", + /* 34 */ "ccons ::= DEFAULT ID|INDEXED", + /* 35 */ "ccons ::= NOT NULL onconf", + /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 37 */ "ccons ::= UNIQUE onconf", + /* 38 */ "ccons ::= CHECK LP expr RP", + /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 40 */ "ccons ::= defer_subclause", + /* 41 */ "ccons ::= COLLATE ID|STRING", + /* 42 */ "autoinc ::=", + /* 43 */ "autoinc ::= AUTOINCR", + /* 44 */ "refargs ::=", + /* 45 */ "refargs ::= refargs refarg", + /* 46 */ "refarg ::= MATCH nm", + /* 47 */ "refarg ::= ON INSERT refact", + /* 48 */ "refarg ::= ON DELETE refact", + /* 49 */ "refarg ::= ON UPDATE refact", + /* 50 */ "refact ::= SET NULL", + /* 51 */ "refact ::= SET DEFAULT", + /* 52 */ "refact ::= CASCADE", + /* 53 */ "refact ::= RESTRICT", + /* 54 */ "refact ::= NO ACTION", + /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 57 */ "init_deferred_pred_opt ::=", + /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 60 */ "conslist_opt ::=", + /* 61 */ "tconscomma ::= COMMA", + /* 62 */ "tcons ::= CONSTRAINT nm", + /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 65 */ "tcons ::= CHECK LP expr RP onconf", + /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 67 */ "defer_subclause_opt ::=", + /* 68 */ "onconf ::=", + /* 69 */ "onconf ::= ON CONFLICT resolvetype", + /* 70 */ "orconf ::=", + /* 71 */ "orconf ::= OR resolvetype", + /* 72 */ "resolvetype ::= IGNORE", + /* 73 */ "resolvetype ::= REPLACE", + /* 74 */ "cmd ::= DROP TABLE ifexists fullname", + /* 75 */ "ifexists ::= IF EXISTS", + /* 76 */ "ifexists ::=", + /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 78 */ "cmd ::= DROP VIEW ifexists fullname", + /* 79 */ "cmd ::= select", + /* 80 */ "select ::= with selectnowith", + /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 82 */ "multiselect_op ::= UNION", + /* 83 */ "multiselect_op ::= UNION ALL", + /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 86 */ "values ::= VALUES LP nexprlist RP", + /* 87 */ "values ::= values COMMA LP exprlist RP", + /* 88 */ "distinct ::= DISTINCT", + /* 89 */ "distinct ::= ALL", + /* 90 */ "distinct ::=", + /* 91 */ "sclp ::=", + /* 92 */ "selcollist ::= sclp expr as", + /* 93 */ "selcollist ::= sclp STAR", + /* 94 */ "selcollist ::= sclp nm DOT STAR", + /* 95 */ "as ::= AS nm", + /* 96 */ "as ::=", + /* 97 */ "from ::=", + /* 98 */ "from ::= FROM seltablist", + /* 99 */ "stl_prefix ::= seltablist joinop", + /* 100 */ "stl_prefix ::=", + /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 105 */ "dbnm ::=", + /* 106 */ "dbnm ::= DOT nm", + /* 107 */ "fullname ::= nm dbnm", + /* 108 */ "joinop ::= COMMA|JOIN", + /* 109 */ "joinop ::= JOIN_KW JOIN", + /* 110 */ "joinop ::= JOIN_KW nm JOIN", + /* 111 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 112 */ "on_opt ::= ON expr", + /* 113 */ "on_opt ::=", + /* 114 */ "indexed_opt ::=", + /* 115 */ "indexed_opt ::= INDEXED BY nm", + /* 116 */ "indexed_opt ::= NOT INDEXED", + /* 117 */ "using_opt ::= USING LP idlist RP", + /* 118 */ "using_opt ::=", + /* 119 */ "orderby_opt ::=", + /* 120 */ "orderby_opt ::= ORDER BY sortlist", + /* 121 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 122 */ "sortlist ::= expr sortorder", + /* 123 */ "sortorder ::= ASC", + /* 124 */ "sortorder ::= DESC", + /* 125 */ "sortorder ::=", + /* 126 */ "groupby_opt ::=", + /* 127 */ "groupby_opt ::= GROUP BY nexprlist", + /* 128 */ "having_opt ::=", + /* 129 */ "having_opt ::= HAVING expr", + /* 130 */ "limit_opt ::=", + /* 131 */ "limit_opt ::= LIMIT expr", + /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 133 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt orderby_opt limit_opt", + /* 135 */ "where_opt ::=", + /* 136 */ "where_opt ::= WHERE expr", + /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt orderby_opt limit_opt", + /* 138 */ "setlist ::= setlist COMMA nm EQ expr", + /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 140 */ "setlist ::= nm EQ expr", + /* 141 */ "setlist ::= LP idlist RP EQ expr", + /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", + /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", + /* 144 */ "insert_cmd ::= INSERT orconf", + /* 145 */ "insert_cmd ::= REPLACE", + /* 146 */ "idlist_opt ::=", + /* 147 */ "idlist_opt ::= LP idlist RP", + /* 148 */ "idlist ::= idlist COMMA nm", + /* 149 */ "idlist ::= nm", + /* 150 */ "expr ::= LP expr RP", + /* 151 */ "term ::= NULL", + /* 152 */ "expr ::= ID|INDEXED", + /* 153 */ "expr ::= JOIN_KW", + /* 154 */ "expr ::= nm DOT nm", + /* 155 */ "expr ::= nm DOT nm DOT nm", + /* 156 */ "term ::= FLOAT|BLOB", + /* 157 */ "term ::= STRING", + /* 158 */ "term ::= INTEGER", + /* 159 */ "expr ::= VARIABLE", + /* 160 */ "expr ::= expr COLLATE ID|STRING", + /* 161 */ "expr ::= CAST LP expr AS typetoken RP", + /* 162 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 163 */ "expr ::= ID|INDEXED LP STAR RP", + /* 164 */ "term ::= CTIME_KW", + /* 165 */ "expr ::= LP nexprlist COMMA expr RP", + /* 166 */ "expr ::= expr AND expr", + /* 167 */ "expr ::= expr OR expr", + /* 168 */ "expr ::= expr LT|GT|GE|LE expr", + /* 169 */ "expr ::= expr EQ|NE expr", + /* 170 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 171 */ "expr ::= expr PLUS|MINUS expr", + /* 172 */ "expr ::= expr STAR|SLASH|REM expr", + /* 173 */ "expr ::= expr CONCAT expr", + /* 174 */ "likeop ::= LIKE_KW|MATCH", + /* 175 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 176 */ "expr ::= expr likeop expr", + /* 177 */ "expr ::= expr likeop expr ESCAPE expr", + /* 178 */ "expr ::= expr ISNULL|NOTNULL", + /* 179 */ "expr ::= expr NOT NULL", + /* 180 */ "expr ::= expr IS expr", + /* 181 */ "expr ::= expr IS NOT expr", + /* 182 */ "expr ::= NOT expr", + /* 183 */ "expr ::= BITNOT expr", + /* 184 */ "expr ::= MINUS expr", + /* 185 */ "expr ::= PLUS expr", + /* 186 */ "between_op ::= BETWEEN", + /* 187 */ "between_op ::= NOT BETWEEN", + /* 188 */ "expr ::= expr between_op expr AND expr", + /* 189 */ "in_op ::= IN", + /* 190 */ "in_op ::= NOT IN", + /* 191 */ "expr ::= expr in_op LP exprlist RP", + /* 192 */ "expr ::= LP select RP", + /* 193 */ "expr ::= expr in_op LP select RP", + /* 194 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 195 */ "expr ::= EXISTS LP select RP", + /* 196 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 197 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 198 */ "case_exprlist ::= WHEN expr THEN expr", + /* 199 */ "case_else ::= ELSE expr", + /* 200 */ "case_else ::=", + /* 201 */ "case_operand ::= expr", + /* 202 */ "case_operand ::=", + /* 203 */ "exprlist ::=", + /* 204 */ "nexprlist ::= nexprlist COMMA expr", + /* 205 */ "nexprlist ::= expr", + /* 206 */ "paren_exprlist ::=", + /* 207 */ "paren_exprlist ::= LP exprlist RP", + /* 208 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 209 */ "uniqueflag ::= UNIQUE", + /* 210 */ "uniqueflag ::=", + /* 211 */ "eidlist_opt ::=", + /* 212 */ "eidlist_opt ::= LP eidlist RP", + /* 213 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 214 */ "eidlist ::= nm collate sortorder", + /* 215 */ "collate ::=", + /* 216 */ "collate ::= COLLATE ID|STRING", + /* 217 */ "cmd ::= DROP INDEX ifexists fullname", + /* 218 */ "cmd ::= VACUUM", + /* 219 */ "cmd ::= VACUUM nm", + /* 220 */ "cmd ::= PRAGMA nm dbnm", + /* 221 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 222 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 223 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 224 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 225 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 226 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 227 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 228 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 229 */ "trigger_time ::= BEFORE", + /* 230 */ "trigger_time ::= AFTER", + /* 231 */ "trigger_time ::= INSTEAD OF", + /* 232 */ "trigger_time ::=", + /* 233 */ "trigger_event ::= DELETE|INSERT", + /* 234 */ "trigger_event ::= UPDATE", + /* 235 */ "trigger_event ::= UPDATE OF idlist", + /* 236 */ "when_clause ::=", + /* 237 */ "when_clause ::= WHEN expr", + /* 238 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 239 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 240 */ "trnm ::= nm DOT nm", + /* 241 */ "tridxby ::= INDEXED BY nm", + /* 242 */ "tridxby ::= NOT INDEXED", + /* 243 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", + /* 244 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", + /* 245 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", + /* 246 */ "trigger_cmd ::= select", + /* 247 */ "expr ::= RAISE LP IGNORE RP", + /* 248 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 249 */ "raisetype ::= ROLLBACK", + /* 250 */ "raisetype ::= ABORT", + /* 251 */ "raisetype ::= FAIL", + /* 252 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 253 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 254 */ "cmd ::= DETACH database_kw_opt expr", + /* 255 */ "key_opt ::=", + /* 256 */ "key_opt ::= KEY expr", + /* 257 */ "cmd ::= REINDEX", + /* 258 */ "cmd ::= REINDEX nm dbnm", + /* 259 */ "cmd ::= ANALYZE", + /* 260 */ "cmd ::= ANALYZE nm dbnm", + /* 261 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 262 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 263 */ "add_column_fullname ::= fullname", + /* 264 */ "cmd ::= create_vtab", + /* 265 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 266 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 267 */ "vtabarg ::=", + /* 268 */ "vtabargtoken ::= ANY", + /* 269 */ "vtabargtoken ::= lp anylist RP", + /* 270 */ "lp ::= LP", + /* 271 */ "with ::=", + /* 272 */ "with ::= WITH wqlist", + /* 273 */ "with ::= WITH RECURSIVE wqlist", + /* 274 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 275 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 276 */ "input ::= cmdlist", + /* 277 */ "cmdlist ::= cmdlist ecmd", + /* 278 */ "cmdlist ::= ecmd", + /* 279 */ "ecmd ::= SEMI", + /* 280 */ "ecmd ::= explain cmdx SEMI", + /* 281 */ "explain ::=", + /* 282 */ "trans_opt ::=", + /* 283 */ "trans_opt ::= TRANSACTION", + /* 284 */ "trans_opt ::= TRANSACTION nm", + /* 285 */ "savepoint_opt ::= SAVEPOINT", + /* 286 */ "savepoint_opt ::=", + /* 287 */ "cmd ::= create_table create_table_args", + /* 288 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 289 */ "columnlist ::= columnname carglist", + /* 290 */ "nm ::= ID|INDEXED", + /* 291 */ "nm ::= STRING", + /* 292 */ "nm ::= JOIN_KW", + /* 293 */ "typetoken ::= typename", + /* 294 */ "typename ::= ID|STRING", + /* 295 */ "signed ::= plus_num", + /* 296 */ "signed ::= minus_num", + /* 297 */ "carglist ::= carglist ccons", + /* 298 */ "carglist ::=", + /* 299 */ "ccons ::= NULL onconf", + /* 300 */ "conslist_opt ::= COMMA conslist", + /* 301 */ "conslist ::= conslist tconscomma tcons", + /* 302 */ "conslist ::= tcons", + /* 303 */ "tconscomma ::=", + /* 304 */ "defer_subclause_opt ::= defer_subclause", + /* 305 */ "resolvetype ::= raisetype", + /* 306 */ "selectnowith ::= oneselect", + /* 307 */ "oneselect ::= values", + /* 308 */ "sclp ::= selcollist COMMA", + /* 309 */ "as ::= ID|STRING", + /* 310 */ "expr ::= term", + /* 311 */ "exprlist ::= nexprlist", + /* 312 */ "nmnum ::= plus_num", + /* 313 */ "nmnum ::= nm", + /* 314 */ "nmnum ::= ON", + /* 315 */ "nmnum ::= DELETE", + /* 316 */ "nmnum ::= DEFAULT", + /* 317 */ "plus_num ::= INTEGER|FLOAT", + /* 318 */ "foreach_clause ::=", + /* 319 */ "foreach_clause ::= FOR EACH ROW", + /* 320 */ "trnm ::= nm", + /* 321 */ "tridxby ::=", + /* 322 */ "database_kw_opt ::= DATABASE", + /* 323 */ "database_kw_opt ::=", + /* 324 */ "kwcolumn_opt ::=", + /* 325 */ "kwcolumn_opt ::= COLUMNKW", + /* 326 */ "vtabarglist ::= vtabarg", + /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 328 */ "vtabarg ::= vtabarg vtabargtoken", + /* 329 */ "anylist ::=", + /* 330 */ "anylist ::= anylist LP anylist RP", + /* 331 */ "anylist ::= anylist ANY", +}; +#endif /* NDEBUG */ + + +#if YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. +*/ +static int yyGrowStack(yyParser *p){ + int newSize; + int idx; + yyStackEntry *pNew; + + newSize = p->yystksz*2 + 100; + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; + }else{ + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + } + if( pNew ){ + p->yystack = pNew; + p->yytos = &p->yystack[idx]; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + } +#endif + p->yystksz = newSize; + } + return pNew==0; +} +#endif + +/* Datatype of the argument to the memory allocated passed as the +** second argument to sqlite3ParserAlloc() below. This can be changed by +** putting an appropriate #define in the %include section of the input +** grammar. +*/ +#ifndef YYMALLOCARGTYPE +# define YYMALLOCARGTYPE size_t +#endif + +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to sqlite3Parser and sqlite3ParserFree. +*/ +void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ + yyParser *pParser; + pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); + if( pParser ){ +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyhwm = 0; +#endif +#if YYSTACKDEPTH<=0 + pParser->yytos = NULL; + pParser->yystack = NULL; + pParser->yystksz = 0; + if( yyGrowStack(pParser) ){ + pParser->yystack = &pParser->yystk0; + pParser->yystksz = 1; + } +#endif +#ifndef YYNOERRORRECOVERY + pParser->yyerrcnt = -1; +#endif + pParser->yytos = pParser->yystack; + pParser->yystack[0].stateno = 0; + pParser->yystack[0].major = 0; + } + return pParser; +} + +/* The following function deletes the "minor type" or semantic value +** associated with a symbol. The symbol can be either a terminal +** or nonterminal. "yymajor" is the symbol code, and "yypminor" is +** a pointer to the value to be deleted. The code used to do the +** deletions is derived from the %destructor and/or %token_destructor +** directives of the input grammar. +*/ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + sqlite3ParserARG_FETCH; + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are *not* used + ** inside the C code. + */ +/********* Begin destructor definitions ***************************************/ + case 163: /* select */ + case 194: /* selectnowith */ + case 195: /* oneselect */ + case 206: /* values */ +{ +#line 396 "parse.y" +sqlite3SelectDelete(pParse->db, (yypminor->yy243)); +#line 1575 "parse.c" +} + break; + case 172: /* term */ + case 173: /* expr */ +{ +#line 823 "parse.y" +sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr); +#line 1583 "parse.c" +} + break; + case 177: /* eidlist_opt */ + case 186: /* sortlist */ + case 187: /* eidlist */ + case 199: /* selcollist */ + case 202: /* groupby_opt */ + case 204: /* orderby_opt */ + case 207: /* nexprlist */ + case 208: /* exprlist */ + case 209: /* sclp */ + case 218: /* setlist */ + case 224: /* paren_exprlist */ + case 226: /* case_exprlist */ +{ +#line 1270 "parse.y" +sqlite3ExprListDelete(pParse->db, (yypminor->yy148)); +#line 1601 "parse.c" +} + break; + case 193: /* fullname */ + case 200: /* from */ + case 211: /* seltablist */ + case 212: /* stl_prefix */ +{ +#line 628 "parse.y" +sqlite3SrcListDelete(pParse->db, (yypminor->yy185)); +#line 1611 "parse.c" +} + break; + case 196: /* with */ + case 250: /* wqlist */ +{ +#line 1547 "parse.y" +sqlite3WithDelete(pParse->db, (yypminor->yy285)); +#line 1619 "parse.c" +} + break; + case 201: /* where_opt */ + case 203: /* having_opt */ + case 215: /* on_opt */ + case 225: /* case_operand */ + case 227: /* case_else */ + case 236: /* when_clause */ + case 241: /* key_opt */ +{ +#line 744 "parse.y" +sqlite3ExprDelete(pParse->db, (yypminor->yy72)); +#line 1632 "parse.c" +} + break; + case 216: /* using_opt */ + case 217: /* idlist */ + case 220: /* idlist_opt */ +{ +#line 662 "parse.y" +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); +#line 1641 "parse.c" +} + break; + case 232: /* trigger_cmd_list */ + case 237: /* trigger_cmd */ +{ +#line 1384 "parse.y" +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145)); +#line 1649 "parse.c" +} + break; + case 234: /* trigger_event */ +{ +#line 1370 "parse.y" +sqlite3IdListDelete(pParse->db, (yypminor->yy332).b); +#line 1656 "parse.c" +} + break; +/********* End destructor definitions *****************************************/ + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +*/ +static void yy_pop_parser_stack(yyParser *pParser){ + yyStackEntry *yytos; + assert( pParser->yytos!=0 ); + assert( pParser->yytos > pParser->yystack ); + yytos = pParser->yytos--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[yytos->major]); + } +#endif + yy_destructor(pParser, yytos->major, &yytos->minor); +} + +/* +** Deallocate and destroy a parser. Destructors are called for +** all stack elements before shutting the parser down. +** +** If the YYPARSEFREENEVERNULL macro exists (for example because it +** is defined in a %include section of the input grammar) then it is +** assumed that the input pointer is never NULL. +*/ +void sqlite3ParserFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ + yyParser *pParser = (yyParser*)p; +#ifndef YYPARSEFREENEVERNULL + if( pParser==0 ) return; +#endif + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); +#endif + (*freeProc)((void*)pParser); +} + +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +int sqlite3ParserStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyhwm; +} +#endif + +/* +** Find the appropriate action for a parser given the terminal +** look-ahead token iLookAhead. +*/ +static unsigned int yy_find_shift_action( + yyParser *pParser, /* The parser */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; + int stateno = pParser->yytos->stateno; + + if( stateno>=YY_MIN_REDUCE ) return stateno; + assert( stateno <= YY_SHIFT_COUNT ); + do{ + i = yy_shift_ofst[stateno]; + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ +#ifdef YYFALLBACK + YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( +#if YY_SHIFT_MIN+YYWILDCARD<0 + j>=0 && +#endif +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT + j0 + ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; + } + } +#endif /* YYWILDCARD */ + return yy_default[stateno]; + }else{ + return yy_action[i]; + } + }while(1); +} + +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +*/ +static int yy_find_reduce_action( + int stateno, /* Current state number */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_COUNT ){ + return yy_default[stateno]; + } +#else + assert( stateno<=YY_REDUCE_COUNT ); +#endif + i = yy_reduce_ofst[stateno]; + assert( i!=YY_REDUCE_USE_DFLT ); + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; +#ifdef YYERRORSYMBOL + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + return yy_default[stateno]; + } +#else + assert( i>=0 && iyytos--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); + } +#endif + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +/******** Begin %stack_overflow code ******************************************/ +#line 37 "parse.y" + + sqlite3ErrorMsg(pParse, "parser stack overflow"); +#line 1830 "parse.c" +/******** End %stack_overflow code ********************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ +} + +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void yyTraceShift(yyParser *yypParser, int yyNewState){ + if( yyTraceFILE ){ + if( yyNewStateyytos->major], + yyNewState); + }else{ + fprintf(yyTraceFILE,"%sShift '%s'\n", + yyTracePrompt,yyTokenName[yypParser->yytos->major]); + } + } +} +#else +# define yyTraceShift(X,Y) +#endif + +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + int yyNewState, /* The new state to shift in */ + int yyMajor, /* The major token to shift in */ + sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ +){ + yyStackEntry *yytos; + yypParser->yytos++; +#ifdef YYTRACKMAXSTACKDEPTH + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ + if( yyGrowStack(yypParser) ){ + yyStackOverflow(yypParser); + return; + } + } +#endif + if( yyNewState > YY_MAX_SHIFT ){ + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yytos = yypParser->yytos; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; + yytos->minor.yy0 = yyMinor; + yyTraceShift(yypParser, yyNewState); +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static const struct { + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} yyRuleInfo[] = { + { 147, 1 }, + { 147, 3 }, + { 148, 1 }, + { 149, 3 }, + { 150, 0 }, + { 150, 1 }, + { 150, 1 }, + { 150, 1 }, + { 149, 2 }, + { 149, 2 }, + { 149, 2 }, + { 149, 2 }, + { 149, 3 }, + { 149, 5 }, + { 154, 6 }, + { 156, 1 }, + { 158, 0 }, + { 158, 3 }, + { 157, 1 }, + { 157, 0 }, + { 155, 5 }, + { 155, 2 }, + { 162, 0 }, + { 162, 2 }, + { 164, 2 }, + { 166, 0 }, + { 166, 4 }, + { 166, 6 }, + { 167, 2 }, + { 171, 2 }, + { 171, 2 }, + { 171, 4 }, + { 171, 3 }, + { 171, 3 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 2 }, + { 171, 4 }, + { 171, 4 }, + { 171, 1 }, + { 171, 2 }, + { 176, 0 }, + { 176, 1 }, + { 178, 0 }, + { 178, 2 }, + { 180, 2 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 181, 2 }, + { 181, 2 }, + { 181, 1 }, + { 181, 1 }, + { 181, 2 }, + { 179, 3 }, + { 179, 2 }, + { 182, 0 }, + { 182, 2 }, + { 182, 2 }, + { 161, 0 }, + { 184, 1 }, + { 185, 2 }, + { 185, 7 }, + { 185, 5 }, + { 185, 5 }, + { 185, 10 }, + { 188, 0 }, + { 174, 0 }, + { 174, 3 }, + { 189, 0 }, + { 189, 2 }, + { 190, 1 }, + { 190, 1 }, + { 149, 4 }, + { 192, 2 }, + { 192, 0 }, + { 149, 9 }, + { 149, 4 }, + { 149, 1 }, + { 163, 2 }, + { 194, 3 }, + { 197, 1 }, + { 197, 2 }, + { 197, 1 }, + { 195, 9 }, + { 206, 4 }, + { 206, 5 }, + { 198, 1 }, + { 198, 1 }, + { 198, 0 }, + { 209, 0 }, + { 199, 3 }, + { 199, 2 }, + { 199, 4 }, + { 210, 2 }, + { 210, 0 }, + { 200, 0 }, + { 200, 2 }, + { 212, 2 }, + { 212, 0 }, + { 211, 7 }, + { 211, 9 }, + { 211, 7 }, + { 211, 7 }, + { 159, 0 }, + { 159, 2 }, + { 193, 2 }, + { 213, 1 }, + { 213, 2 }, + { 213, 3 }, + { 213, 4 }, + { 215, 2 }, + { 215, 0 }, + { 214, 0 }, + { 214, 3 }, + { 214, 2 }, + { 216, 4 }, + { 216, 0 }, + { 204, 0 }, + { 204, 3 }, + { 186, 4 }, + { 186, 2 }, + { 175, 1 }, + { 175, 1 }, + { 175, 0 }, + { 202, 0 }, + { 202, 3 }, + { 203, 0 }, + { 203, 2 }, + { 205, 0 }, + { 205, 2 }, + { 205, 4 }, + { 205, 4 }, + { 149, 8 }, + { 201, 0 }, + { 201, 2 }, + { 149, 10 }, + { 218, 5 }, + { 218, 7 }, + { 218, 3 }, + { 218, 5 }, + { 149, 6 }, + { 149, 7 }, + { 219, 2 }, + { 219, 1 }, + { 220, 0 }, + { 220, 3 }, + { 217, 3 }, + { 217, 1 }, + { 173, 3 }, + { 172, 1 }, + { 173, 1 }, + { 173, 1 }, + { 173, 3 }, + { 173, 5 }, + { 172, 1 }, + { 172, 1 }, + { 172, 1 }, + { 173, 1 }, + { 173, 3 }, + { 173, 6 }, + { 173, 5 }, + { 173, 4 }, + { 172, 1 }, + { 173, 5 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 221, 1 }, + { 221, 2 }, + { 173, 3 }, + { 173, 5 }, + { 173, 2 }, + { 173, 3 }, + { 173, 3 }, + { 173, 4 }, + { 173, 2 }, + { 173, 2 }, + { 173, 2 }, + { 173, 2 }, + { 222, 1 }, + { 222, 2 }, + { 173, 5 }, + { 223, 1 }, + { 223, 2 }, + { 173, 5 }, + { 173, 3 }, + { 173, 5 }, + { 173, 5 }, + { 173, 4 }, + { 173, 5 }, + { 226, 5 }, + { 226, 4 }, + { 227, 2 }, + { 227, 0 }, + { 225, 1 }, + { 225, 0 }, + { 208, 0 }, + { 207, 3 }, + { 207, 1 }, + { 224, 0 }, + { 224, 3 }, + { 149, 12 }, + { 228, 1 }, + { 228, 0 }, + { 177, 0 }, + { 177, 3 }, + { 187, 5 }, + { 187, 3 }, + { 229, 0 }, + { 229, 2 }, + { 149, 4 }, + { 149, 1 }, + { 149, 2 }, + { 149, 3 }, + { 149, 5 }, + { 149, 6 }, + { 149, 5 }, + { 149, 6 }, + { 169, 2 }, + { 170, 2 }, + { 149, 5 }, + { 231, 11 }, + { 233, 1 }, + { 233, 1 }, + { 233, 2 }, + { 233, 0 }, + { 234, 1 }, + { 234, 1 }, + { 234, 3 }, + { 236, 0 }, + { 236, 2 }, + { 232, 3 }, + { 232, 2 }, + { 238, 3 }, + { 239, 3 }, + { 239, 2 }, + { 237, 7 }, + { 237, 5 }, + { 237, 5 }, + { 237, 1 }, + { 173, 4 }, + { 173, 6 }, + { 191, 1 }, + { 191, 1 }, + { 191, 1 }, + { 149, 4 }, + { 149, 6 }, + { 149, 3 }, + { 241, 0 }, + { 241, 2 }, + { 149, 1 }, + { 149, 3 }, + { 149, 1 }, + { 149, 3 }, + { 149, 6 }, + { 149, 7 }, + { 242, 1 }, + { 149, 1 }, + { 149, 4 }, + { 244, 8 }, + { 246, 0 }, + { 247, 1 }, + { 247, 3 }, + { 248, 1 }, + { 196, 0 }, + { 196, 2 }, + { 196, 3 }, + { 250, 6 }, + { 250, 8 }, + { 144, 1 }, + { 145, 2 }, + { 145, 1 }, + { 146, 1 }, + { 146, 3 }, + { 147, 0 }, + { 151, 0 }, + { 151, 1 }, + { 151, 2 }, + { 153, 1 }, + { 153, 0 }, + { 149, 2 }, + { 160, 4 }, + { 160, 2 }, + { 152, 1 }, + { 152, 1 }, + { 152, 1 }, + { 166, 1 }, + { 167, 1 }, + { 168, 1 }, + { 168, 1 }, + { 165, 2 }, + { 165, 0 }, + { 171, 2 }, + { 161, 2 }, + { 183, 3 }, + { 183, 1 }, + { 184, 0 }, + { 188, 1 }, + { 190, 1 }, + { 194, 1 }, + { 195, 1 }, + { 209, 2 }, + { 210, 1 }, + { 173, 1 }, + { 208, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 169, 1 }, + { 235, 0 }, + { 235, 3 }, + { 238, 1 }, + { 239, 0 }, + { 240, 1 }, + { 240, 0 }, + { 243, 0 }, + { 243, 1 }, + { 245, 1 }, + { 245, 3 }, + { 246, 2 }, + { 249, 0 }, + { 249, 4 }, + { 249, 2 }, +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void yy_reduce( + yyParser *yypParser, /* The parser */ + unsigned int yyruleno /* Number of the rule by which to reduce */ +){ + int yygoto; /* The next state */ + int yyact; /* The next action */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + sqlite3ParserARG_FETCH; + yymsp = yypParser->yytos; +#ifndef NDEBUG + if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + yysize = yyRuleInfo[yyruleno].nrhs; + fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, + yyRuleName[yyruleno], yymsp[-yysize].stateno); + } +#endif /* NDEBUG */ + + /* Check that the stack is large enough to grow by a single entry + ** if the RHS of the rule is empty. This ensures that there is room + ** enough on the stack to push the LHS value */ + if( yyRuleInfo[yyruleno].nrhs==0 ){ +#ifdef YYTRACKMAXSTACKDEPTH + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ + if( yyGrowStack(yypParser) ){ + yyStackOverflow(yypParser); + return; + } + yymsp = yypParser->yytos; + } +#endif + } + + switch( yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ +/********** Begin reduce actions **********************************************/ + YYMINORTYPE yylhsminor; + case 0: /* explain ::= EXPLAIN */ +#line 113 "parse.y" +{ pParse->explain = 1; } +#line 2300 "parse.c" + break; + case 1: /* explain ::= EXPLAIN QUERY PLAN */ +#line 114 "parse.y" +{ pParse->explain = 2; } +#line 2305 "parse.c" + break; + case 2: /* cmdx ::= cmd */ +#line 116 "parse.y" +{ sqlite3FinishCoding(pParse); } +#line 2310 "parse.c" + break; + case 3: /* cmd ::= BEGIN transtype trans_opt */ +#line 121 "parse.y" +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);} +#line 2315 "parse.c" + break; + case 4: /* transtype ::= */ +#line 126 "parse.y" +{yymsp[1].minor.yy194 = TK_DEFERRED;} +#line 2320 "parse.c" + break; + case 5: /* transtype ::= DEFERRED */ + case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); + case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); +#line 127 "parse.y" +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/} +#line 2327 "parse.c" + break; + case 8: /* cmd ::= COMMIT trans_opt */ + case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9); +#line 130 "parse.y" +{sqlite3CommitTransaction(pParse);} +#line 2333 "parse.c" + break; + case 10: /* cmd ::= ROLLBACK trans_opt */ +#line 132 "parse.y" +{sqlite3RollbackTransaction(pParse);} +#line 2338 "parse.c" + break; + case 11: /* cmd ::= SAVEPOINT nm */ +#line 136 "parse.y" +{ + sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); +} +#line 2345 "parse.c" + break; + case 12: /* cmd ::= RELEASE savepoint_opt nm */ +#line 139 "parse.y" +{ + sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); +} +#line 2352 "parse.c" + break; + case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ +#line 142 "parse.y" +{ + sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); +} +#line 2359 "parse.c" + break; + case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ +#line 149 "parse.y" +{ + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194); +} +#line 2366 "parse.c" + break; + case 15: /* createkw ::= CREATE */ +#line 152 "parse.y" +{disableLookaside(pParse);} +#line 2371 "parse.c" + break; + case 16: /* ifnotexists ::= */ + case 19: /* temp ::= */ yytestcase(yyruleno==19); + case 22: /* table_options ::= */ yytestcase(yyruleno==22); + case 42: /* autoinc ::= */ yytestcase(yyruleno==42); + case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); + case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); + case 76: /* ifexists ::= */ yytestcase(yyruleno==76); + case 90: /* distinct ::= */ yytestcase(yyruleno==90); + case 215: /* collate ::= */ yytestcase(yyruleno==215); +#line 155 "parse.y" +{yymsp[1].minor.yy194 = 0;} +#line 2384 "parse.c" + break; + case 17: /* ifnotexists ::= IF NOT EXISTS */ +#line 156 "parse.y" +{yymsp[-2].minor.yy194 = 1;} +#line 2389 "parse.c" + break; + case 18: /* temp ::= TEMP */ + case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); +#line 159 "parse.y" +{yymsp[0].minor.yy194 = 1;} +#line 2395 "parse.c" + break; + case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ +#line 162 "parse.y" +{ + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0); +} +#line 2402 "parse.c" + break; + case 21: /* create_table_args ::= AS select */ +#line 165 "parse.y" +{ + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); +} +#line 2410 "parse.c" + break; + case 23: /* table_options ::= WITHOUT nm */ +#line 171 "parse.y" +{ + if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ + yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid; + }else{ + yymsp[-1].minor.yy194 = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); + } +} +#line 2422 "parse.c" + break; + case 24: /* columnname ::= nm typetoken */ +#line 181 "parse.y" +{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} +#line 2427 "parse.c" + break; + case 25: /* typetoken ::= */ + case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); + case 96: /* as ::= */ yytestcase(yyruleno==96); +#line 246 "parse.y" +{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} +#line 2434 "parse.c" + break; + case 26: /* typetoken ::= typename LP signed RP */ +#line 248 "parse.y" +{ + yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); +} +#line 2441 "parse.c" + break; + case 27: /* typetoken ::= typename LP signed COMMA signed RP */ +#line 251 "parse.y" +{ + yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); +} +#line 2448 "parse.c" + break; + case 28: /* typename ::= typename ID|STRING */ +#line 256 "parse.y" +{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} +#line 2453 "parse.c" + break; + case 29: /* ccons ::= CONSTRAINT nm */ + case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); +#line 265 "parse.y" +{pParse->constraintName = yymsp[0].minor.yy0;} +#line 2459 "parse.c" + break; + case 30: /* ccons ::= DEFAULT term */ + case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32); +#line 266 "parse.y" +{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);} +#line 2465 "parse.c" + break; + case 31: /* ccons ::= DEFAULT LP expr RP */ +#line 267 "parse.y" +{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);} +#line 2470 "parse.c" + break; + case 33: /* ccons ::= DEFAULT MINUS term */ +#line 269 "parse.y" +{ + ExprSpan v; + v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0, 0); + v.zStart = yymsp[-1].minor.yy0.z; + v.zEnd = yymsp[0].minor.yy190.zEnd; + sqlite3AddDefaultValue(pParse,&v); +} +#line 2481 "parse.c" + break; + case 34: /* ccons ::= DEFAULT ID|INDEXED */ +#line 276 "parse.y" +{ + ExprSpan v; + spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0); + sqlite3AddDefaultValue(pParse,&v); +} +#line 2490 "parse.c" + break; + case 35: /* ccons ::= NOT NULL onconf */ +#line 286 "parse.y" +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);} +#line 2495 "parse.c" + break; + case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ +#line 288 "parse.y" +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);} +#line 2500 "parse.c" + break; + case 37: /* ccons ::= UNIQUE onconf */ +#line 289 "parse.y" +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} +#line 2506 "parse.c" + break; + case 38: /* ccons ::= CHECK LP expr RP */ +#line 291 "parse.y" +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);} +#line 2511 "parse.c" + break; + case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ +#line 293 "parse.y" +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);} +#line 2516 "parse.c" + break; + case 40: /* ccons ::= defer_subclause */ +#line 294 "parse.y" +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);} +#line 2521 "parse.c" + break; + case 41: /* ccons ::= COLLATE ID|STRING */ +#line 295 "parse.y" +{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} +#line 2526 "parse.c" + break; + case 44: /* refargs ::= */ +#line 308 "parse.y" +{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */} +#line 2531 "parse.c" + break; + case 45: /* refargs ::= refargs refarg */ +#line 309 "parse.y" +{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; } +#line 2536 "parse.c" + break; + case 46: /* refarg ::= MATCH nm */ +#line 311 "parse.y" +{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; } +#line 2541 "parse.c" + break; + case 47: /* refarg ::= ON INSERT refact */ +#line 312 "parse.y" +{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; } +#line 2546 "parse.c" + break; + case 48: /* refarg ::= ON DELETE refact */ +#line 313 "parse.y" +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; } +#line 2551 "parse.c" + break; + case 49: /* refarg ::= ON UPDATE refact */ +#line 314 "parse.y" +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; } +#line 2556 "parse.c" + break; + case 50: /* refact ::= SET NULL */ +#line 316 "parse.y" +{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */} +#line 2561 "parse.c" + break; + case 51: /* refact ::= SET DEFAULT */ +#line 317 "parse.y" +{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */} +#line 2566 "parse.c" + break; + case 52: /* refact ::= CASCADE */ +#line 318 "parse.y" +{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */} +#line 2571 "parse.c" + break; + case 53: /* refact ::= RESTRICT */ +#line 319 "parse.y" +{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */} +#line 2576 "parse.c" + break; + case 54: /* refact ::= NO ACTION */ +#line 320 "parse.y" +{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */} +#line 2581 "parse.c" + break; + case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ +#line 322 "parse.y" +{yymsp[-2].minor.yy194 = 0;} +#line 2586 "parse.c" + break; + case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); + case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144); +#line 323 "parse.y" +{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;} +#line 2593 "parse.c" + break; + case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); + case 187: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==187); + case 190: /* in_op ::= NOT IN */ yytestcase(yyruleno==190); + case 216: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==216); +#line 326 "parse.y" +{yymsp[-1].minor.yy194 = 1;} +#line 2602 "parse.c" + break; + case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ +#line 327 "parse.y" +{yymsp[-1].minor.yy194 = 0;} +#line 2607 "parse.c" + break; + case 61: /* tconscomma ::= COMMA */ +#line 333 "parse.y" +{pParse->constraintName.n = 0;} +#line 2612 "parse.c" + break; + case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ +#line 337 "parse.y" +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);} +#line 2617 "parse.c" + break; + case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ +#line 339 "parse.y" +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} +#line 2623 "parse.c" + break; + case 65: /* tcons ::= CHECK LP expr RP onconf */ +#line 342 "parse.y" +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);} +#line 2628 "parse.c" + break; + case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ +#line 344 "parse.y" +{ + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194); +} +#line 2636 "parse.c" + break; + case 68: /* onconf ::= */ + case 70: /* orconf ::= */ yytestcase(yyruleno==70); +#line 358 "parse.y" +{yymsp[1].minor.yy194 = OE_Default;} +#line 2642 "parse.c" + break; + case 69: /* onconf ::= ON CONFLICT resolvetype */ +#line 359 "parse.y" +{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;} +#line 2647 "parse.c" + break; + case 72: /* resolvetype ::= IGNORE */ +#line 363 "parse.y" +{yymsp[0].minor.yy194 = OE_Ignore;} +#line 2652 "parse.c" + break; + case 73: /* resolvetype ::= REPLACE */ + case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145); +#line 364 "parse.y" +{yymsp[0].minor.yy194 = OE_Replace;} +#line 2658 "parse.c" + break; + case 74: /* cmd ::= DROP TABLE ifexists fullname */ +#line 368 "parse.y" +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194); +} +#line 2665 "parse.c" + break; + case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ +#line 379 "parse.y" +{ + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194); +} +#line 2672 "parse.c" + break; + case 78: /* cmd ::= DROP VIEW ifexists fullname */ +#line 382 "parse.y" +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194); +} +#line 2679 "parse.c" + break; + case 79: /* cmd ::= select */ +#line 389 "parse.y" +{ + SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; + sqlite3Select(pParse, yymsp[0].minor.yy243, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); +} +#line 2688 "parse.c" + break; + case 80: /* select ::= with selectnowith */ +#line 426 "parse.y" +{ + Select *p = yymsp[0].minor.yy243; + if( p ){ + p->pWith = yymsp[-1].minor.yy285; + parserDoubleLinkSelect(pParse, p); + }else{ + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285); + } + yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/ +} +#line 2702 "parse.c" + break; + case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */ +#line 439 "parse.y" +{ + Select *pRhs = yymsp[0].minor.yy243; + Select *pLhs = yymsp[-2].minor.yy243; + if( pRhs && pRhs->pPrior ){ + SrcList *pFrom; + Token x; + x.n = 0; + parserDoubleLinkSelect(pParse, pRhs); + pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); + pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); + } + if( pRhs ){ + pRhs->op = (u8)yymsp[-1].minor.yy194; + pRhs->pPrior = pLhs; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; + pRhs->selFlags &= ~SF_MultiValue; + if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1; + }else{ + sqlite3SelectDelete(pParse->db, pLhs); + } + yymsp[-2].minor.yy243 = pRhs; +} +#line 2728 "parse.c" + break; + case 82: /* multiselect_op ::= UNION */ + case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84); +#line 462 "parse.y" +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/} +#line 2734 "parse.c" + break; + case 83: /* multiselect_op ::= UNION ALL */ +#line 463 "parse.y" +{yymsp[-1].minor.yy194 = TK_ALL;} +#line 2739 "parse.c" + break; + case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ +#line 467 "parse.y" +{ +#if SELECTTRACE_ENABLED + Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ +#endif + yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset); +#if SELECTTRACE_ENABLED + /* Populate the Select.zSelName[] string that is used to help with + ** query planner debugging, to differentiate between multiple Select + ** objects in a complex query. + ** + ** If the SELECT keyword is immediately followed by a C-style comment + ** then extract the first few alphanumeric characters from within that + ** comment to be the zSelName value. Otherwise, the label is #N where + ** is an integer that is incremented with each SELECT statement seen. + */ + if( yymsp[-8].minor.yy243!=0 ){ + const char *z = s.z+6; + int i; + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d", + ++pParse->nSelect); + while( z[0]==' ' ) z++; + if( z[0]=='/' && z[1]=='*' ){ + z += 2; + while( z[0]==' ' ) z++; + for(i=0; sqlite3Isalnum(z[i]); i++){} + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z); + } + } +#endif /* SELECTRACE_ENABLED */ +} +#line 2773 "parse.c" + break; + case 86: /* values ::= VALUES LP nexprlist RP */ +#line 501 "parse.y" +{ + yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0); +} +#line 2780 "parse.c" + break; + case 87: /* values ::= values COMMA LP exprlist RP */ +#line 504 "parse.y" +{ + Select *pRight, *pLeft = yymsp[-4].minor.yy243; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; + if( pRight ){ + pRight->op = TK_ALL; + pRight->pPrior = pLeft; + yymsp[-4].minor.yy243 = pRight; + }else{ + yymsp[-4].minor.yy243 = pLeft; + } +} +#line 2796 "parse.c" + break; + case 88: /* distinct ::= DISTINCT */ +#line 521 "parse.y" +{yymsp[0].minor.yy194 = SF_Distinct;} +#line 2801 "parse.c" + break; + case 89: /* distinct ::= ALL */ +#line 522 "parse.y" +{yymsp[0].minor.yy194 = SF_All;} +#line 2806 "parse.c" + break; + case 91: /* sclp ::= */ + case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119); + case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126); + case 203: /* exprlist ::= */ yytestcase(yyruleno==203); + case 206: /* paren_exprlist ::= */ yytestcase(yyruleno==206); + case 211: /* eidlist_opt ::= */ yytestcase(yyruleno==211); +#line 535 "parse.y" +{yymsp[1].minor.yy148 = 0;} +#line 2816 "parse.c" + break; + case 92: /* selcollist ::= sclp expr as */ +#line 536 "parse.y" +{ + yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190); +} +#line 2825 "parse.c" + break; + case 93: /* selcollist ::= sclp STAR */ +#line 541 "parse.y" +{ + Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p); +} +#line 2833 "parse.c" + break; + case 94: /* selcollist ::= sclp nm DOT STAR */ +#line 545 "parse.y" +{ + Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, 0); + Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); + Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot); +} +#line 2843 "parse.c" + break; + case 95: /* as ::= AS nm */ + case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106); + case 225: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==225); + case 226: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==226); +#line 556 "parse.y" +{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} +#line 2851 "parse.c" + break; + case 97: /* from ::= */ +#line 570 "parse.y" +{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));} +#line 2856 "parse.c" + break; + case 98: /* from ::= FROM seltablist */ +#line 571 "parse.y" +{ + yymsp[-1].minor.yy185 = yymsp[0].minor.yy185; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185); +} +#line 2864 "parse.c" + break; + case 99: /* stl_prefix ::= seltablist joinop */ +#line 579 "parse.y" +{ + if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194; +} +#line 2871 "parse.c" + break; + case 100: /* stl_prefix ::= */ +#line 582 "parse.y" +{yymsp[1].minor.yy185 = 0;} +#line 2876 "parse.c" + break; + case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ +#line 584 "parse.y" +{ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0); +} +#line 2884 "parse.c" + break; + case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ +#line 589 "parse.y" +{ + yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148); +} +#line 2892 "parse.c" + break; + case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ +#line 595 "parse.y" +{ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + } +#line 2899 "parse.c" + break; + case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ +#line 599 "parse.y" +{ + if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){ + yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185; + }else if( yymsp[-4].minor.yy185->nSrc==1 ){ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + if( yymsp[-6].minor.yy185 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy185->a; + pNew->zName = pOld->zName; + pNew->zDatabase = pOld->zDatabase; + pNew->pSelect = pOld->pSelect; + pOld->zName = pOld->zDatabase = 0; + pOld->pSelect = 0; + } + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185); + }else{ + Select *pSubquery; + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + } + } +#line 2925 "parse.c" + break; + case 105: /* dbnm ::= */ + case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114); +#line 624 "parse.y" +{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} +#line 2931 "parse.c" + break; + case 107: /* fullname ::= nm dbnm */ +#line 630 "parse.y" +{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} +#line 2936 "parse.c" + break; + case 108: /* joinop ::= COMMA|JOIN */ +#line 633 "parse.y" +{ yymsp[0].minor.yy194 = JT_INNER; } +#line 2941 "parse.c" + break; + case 109: /* joinop ::= JOIN_KW JOIN */ +#line 635 "parse.y" +{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} +#line 2946 "parse.c" + break; + case 110: /* joinop ::= JOIN_KW nm JOIN */ +#line 637 "parse.y" +{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} +#line 2951 "parse.c" + break; + case 111: /* joinop ::= JOIN_KW nm nm JOIN */ +#line 639 "parse.y" +{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} +#line 2956 "parse.c" + break; + case 112: /* on_opt ::= ON expr */ + case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129); + case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136); + case 199: /* case_else ::= ELSE expr */ yytestcase(yyruleno==199); +#line 643 "parse.y" +{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;} +#line 2964 "parse.c" + break; + case 113: /* on_opt ::= */ + case 128: /* having_opt ::= */ yytestcase(yyruleno==128); + case 135: /* where_opt ::= */ yytestcase(yyruleno==135); + case 200: /* case_else ::= */ yytestcase(yyruleno==200); + case 202: /* case_operand ::= */ yytestcase(yyruleno==202); +#line 644 "parse.y" +{yymsp[1].minor.yy72 = 0;} +#line 2973 "parse.c" + break; + case 115: /* indexed_opt ::= INDEXED BY nm */ +#line 658 "parse.y" +{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} +#line 2978 "parse.c" + break; + case 116: /* indexed_opt ::= NOT INDEXED */ +#line 659 "parse.y" +{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} +#line 2983 "parse.c" + break; + case 117: /* using_opt ::= USING LP idlist RP */ +#line 663 "parse.y" +{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} +#line 2988 "parse.c" + break; + case 118: /* using_opt ::= */ + case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146); +#line 664 "parse.y" +{yymsp[1].minor.yy254 = 0;} +#line 2994 "parse.c" + break; + case 120: /* orderby_opt ::= ORDER BY sortlist */ + case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127); +#line 678 "parse.y" +{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;} +#line 3000 "parse.c" + break; + case 121: /* sortlist ::= sortlist COMMA expr sortorder */ +#line 679 "parse.y" +{ + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194); +} +#line 3008 "parse.c" + break; + case 122: /* sortlist ::= expr sortorder */ +#line 683 "parse.y" +{ + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194); +} +#line 3016 "parse.c" + break; + case 123: /* sortorder ::= ASC */ +#line 690 "parse.y" +{yymsp[0].minor.yy194 = SQLITE_SO_ASC;} +#line 3021 "parse.c" + break; + case 124: /* sortorder ::= DESC */ +#line 691 "parse.y" +{yymsp[0].minor.yy194 = SQLITE_SO_DESC;} +#line 3026 "parse.c" + break; + case 125: /* sortorder ::= */ +#line 692 "parse.y" +{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;} +#line 3031 "parse.c" + break; + case 130: /* limit_opt ::= */ +#line 717 "parse.y" +{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;} +#line 3036 "parse.c" + break; + case 131: /* limit_opt ::= LIMIT expr */ +#line 718 "parse.y" +{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;} +#line 3041 "parse.c" + break; + case 132: /* limit_opt ::= LIMIT expr OFFSET expr */ +#line 720 "parse.y" +{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;} +#line 3046 "parse.c" + break; + case 133: /* limit_opt ::= LIMIT expr COMMA expr */ +#line 722 "parse.y" +{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;} +#line 3051 "parse.c" + break; + case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt orderby_opt limit_opt */ +#line 728 "parse.y" +{ + sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0); + yymsp[-2].minor.yy72 = sqlite3LimitWhere(pParse, yymsp[-4].minor.yy185, yymsp[-2].minor.yy72, yymsp[-1].minor.yy148, yymsp[0].minor.yy354.pLimit, yymsp[0].minor.yy354.pOffset, "DELETE"); + sqlite3DeleteFrom(pParse,yymsp[-4].minor.yy185,yymsp[-2].minor.yy72); +} +#line 3061 "parse.c" + break; + case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt orderby_opt limit_opt */ +#line 753 "parse.y" +{ + sqlite3WithPush(pParse, yymsp[-9].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-5].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-3].minor.yy148,"set list"); + yymsp[-2].minor.yy72 = sqlite3LimitWhere(pParse, yymsp[-6].minor.yy185, yymsp[-2].minor.yy72, yymsp[-1].minor.yy148, yymsp[0].minor.yy354.pLimit, yymsp[0].minor.yy354.pOffset, "UPDATE"); + sqlite3Update(pParse,yymsp[-6].minor.yy185,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-7].minor.yy194); +} +#line 3072 "parse.c" + break; + case 138: /* setlist ::= setlist COMMA nm EQ expr */ +#line 774 "parse.y" +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1); +} +#line 3080 "parse.c" + break; + case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ +#line 778 "parse.y" +{ + yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); +} +#line 3087 "parse.c" + break; + case 140: /* setlist ::= nm EQ expr */ +#line 781 "parse.y" +{ + yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1); +} +#line 3095 "parse.c" + yymsp[-2].minor.yy148 = yylhsminor.yy148; + break; + case 141: /* setlist ::= LP idlist RP EQ expr */ +#line 785 "parse.y" +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); +} +#line 3103 "parse.c" + break; + case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ +#line 791 "parse.y" +{ + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194); +} +#line 3111 "parse.c" + break; + case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ +#line 796 "parse.y" +{ + sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194); +} +#line 3119 "parse.c" + break; + case 147: /* idlist_opt ::= LP idlist RP */ +#line 811 "parse.y" +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} +#line 3124 "parse.c" + break; + case 148: /* idlist ::= idlist COMMA nm */ +#line 813 "parse.y" +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} +#line 3129 "parse.c" + break; + case 149: /* idlist ::= nm */ +#line 815 "parse.y" +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} +#line 3134 "parse.c" + break; + case 150: /* expr ::= LP expr RP */ +#line 865 "parse.y" +{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;} +#line 3139 "parse.c" + break; + case 151: /* term ::= NULL */ + case 156: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==156); + case 157: /* term ::= STRING */ yytestcase(yyruleno==157); +#line 866 "parse.y" +{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} +#line 3146 "parse.c" + break; + case 152: /* expr ::= ID|INDEXED */ + case 153: /* expr ::= JOIN_KW */ yytestcase(yyruleno==153); +#line 867 "parse.y" +{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} +#line 3152 "parse.c" + break; + case 154: /* expr ::= nm DOT nm */ +#line 869 "parse.y" +{ + Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); +} +#line 3162 "parse.c" + break; + case 155: /* expr ::= nm DOT nm DOT nm */ +#line 875 "parse.y" +{ + Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); + Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); + Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0); + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); +} +#line 3174 "parse.c" + break; + case 158: /* term ::= INTEGER */ +#line 885 "parse.y" +{ + yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z; + yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n; + if( yylhsminor.yy190.pExpr ) yylhsminor.yy190.pExpr->flags |= EP_Leaf; +} +#line 3184 "parse.c" + yymsp[0].minor.yy190 = yylhsminor.yy190; + break; + case 159: /* expr ::= VARIABLE */ +#line 891 "parse.y" +{ + if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ + u32 n = yymsp[0].minor.yy0.n; + spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr, n); + }else{ + /* When doing a nested parse, one can include terms in an expression + ** that look like this: #1 #2 ... These terms refer to registers + ** in the virtual machine. #N is the N-th register. */ + Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ + assert( t.n>=2 ); + spanSet(&yymsp[0].minor.yy190, &t, &t); + if( pParse->nested==0 ){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); + yymsp[0].minor.yy190.pExpr = 0; + }else{ + yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, 0); + if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable); + } + } +} +#line 3210 "parse.c" + break; + case 160: /* expr ::= expr COLLATE ID|STRING */ +#line 912 "parse.y" +{ + yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; +} +#line 3218 "parse.c" + break; + case 161: /* expr ::= CAST LP expr AS typetoken RP */ +#line 917 "parse.y" +{ + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy190.pExpr, 0, &yymsp[-1].minor.yy0); +} +#line 3226 "parse.c" + break; + case 162: /* expr ::= ID|INDEXED LP distinct exprlist RP */ +#line 922 "parse.y" +{ + if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); + } + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); + if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->flags |= EP_Distinct; + } +} +#line 3240 "parse.c" + yymsp[-4].minor.yy190 = yylhsminor.yy190; + break; + case 163: /* expr ::= ID|INDEXED LP STAR RP */ +#line 932 "parse.y" +{ + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); +} +#line 3249 "parse.c" + yymsp[-3].minor.yy190 = yylhsminor.yy190; + break; + case 164: /* term ::= CTIME_KW */ +#line 936 "parse.y" +{ + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); + spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); +} +#line 3258 "parse.c" + yymsp[0].minor.yy190 = yylhsminor.yy190; + break; + case 165: /* expr ::= LP nexprlist COMMA expr RP */ +#line 965 "parse.y" +{ + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr); + yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0, 0); + if( yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->x.pList = pList; + spanSet(&yylhsminor.yy190, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } +} +#line 3273 "parse.c" + yymsp[-4].minor.yy190 = yylhsminor.yy190; + break; + case 166: /* expr ::= expr AND expr */ + case 167: /* expr ::= expr OR expr */ yytestcase(yyruleno==167); + case 168: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==168); + case 169: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==169); + case 170: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==170); + case 171: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==171); + case 172: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==172); + case 173: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==173); +#line 976 "parse.y" +{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);} +#line 3286 "parse.c" + break; + case 174: /* likeop ::= LIKE_KW|MATCH */ +#line 989 "parse.y" +{yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/} +#line 3291 "parse.c" + break; + case 175: /* likeop ::= NOT LIKE_KW|MATCH */ +#line 990 "parse.y" +{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} +#line 3296 "parse.c" + break; + case 176: /* expr ::= expr likeop expr */ +#line 991 "parse.y" +{ + ExprList *pList; + int bNot = yymsp[-1].minor.yy0.n & 0x80000000; + yymsp[-1].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr); + yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0); + exprNot(pParse, bNot, &yymsp[-2].minor.yy190); + yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc; +} +#line 3311 "parse.c" + break; + case 177: /* expr ::= expr likeop expr ESCAPE expr */ +#line 1002 "parse.y" +{ + ExprList *pList; + int bNot = yymsp[-3].minor.yy0.n & 0x80000000; + yymsp[-3].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0); + exprNot(pParse, bNot, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc; +} +#line 3327 "parse.c" + break; + case 178: /* expr ::= expr ISNULL|NOTNULL */ +#line 1029 "parse.y" +{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);} +#line 3332 "parse.c" + break; + case 179: /* expr ::= expr NOT NULL */ +#line 1030 "parse.y" +{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);} +#line 3337 "parse.c" + break; + case 180: /* expr ::= expr IS expr */ +#line 1051 "parse.y" +{ + spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL); +} +#line 3345 "parse.c" + break; + case 181: /* expr ::= expr IS NOT expr */ +#line 1055 "parse.y" +{ + spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL); +} +#line 3353 "parse.c" + break; + case 182: /* expr ::= NOT expr */ + case 183: /* expr ::= BITNOT expr */ yytestcase(yyruleno==183); +#line 1079 "parse.y" +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} +#line 3359 "parse.c" + break; + case 184: /* expr ::= MINUS expr */ +#line 1083 "parse.y" +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} +#line 3364 "parse.c" + break; + case 185: /* expr ::= PLUS expr */ +#line 1085 "parse.y" +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} +#line 3369 "parse.c" + break; + case 186: /* between_op ::= BETWEEN */ + case 189: /* in_op ::= IN */ yytestcase(yyruleno==189); +#line 1088 "parse.y" +{yymsp[0].minor.yy194 = 0;} +#line 3375 "parse.c" + break; + case 188: /* expr ::= expr between_op expr AND expr */ +#line 1090 "parse.y" +{ + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = pList; + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; +} +#line 3391 "parse.c" + break; + case 191: /* expr ::= expr in_op LP exprlist RP */ +#line 1106 "parse.y" +{ + if( yymsp[-1].minor.yy148==0 ){ + /* Expressions of the form + ** + ** expr1 IN () + ** expr1 NOT IN () + ** + ** simplify to constants 0 (false) and 1 (true), respectively, + ** regardless of the value of expr1. + */ + sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy194]); + }else if( yymsp[-1].minor.yy148->nExpr==1 ){ + /* Expressions of the form: + ** + ** expr1 IN (?1) + ** expr1 NOT IN (?2) + ** + ** with exactly one value on the RHS can be simplified to something + ** like this: + ** + ** expr1 == ?1 + ** expr1 <> ?2 + ** + ** But, the RHS of the == or <> is marked with the EP_Generic flag + ** so that it may not contribute to the computation of comparison + ** affinity or the collating sequence to use for comparison. Otherwise, + ** the semantics would be subtly different from IN or NOT IN. + */ + Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr; + yymsp[-1].minor.yy148->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); + /* pRHS cannot be NULL because a malloc error would have been detected + ** before now and control would have never reached this point */ + if( ALWAYS(pRHS) ){ + pRHS->flags &= ~EP_Collate; + pRHS->flags |= EP_Generic; + } + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS, 0); + }else{ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); + } + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + } + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + } +#line 3446 "parse.c" + break; + case 192: /* expr ::= LP select RP */ +#line 1157 "parse.y" +{ + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243); + } +#line 3455 "parse.c" + break; + case 193: /* expr ::= expr in_op LP select RP */ +#line 1162 "parse.y" +{ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + } +#line 3465 "parse.c" + break; + case 194: /* expr ::= expr in_op nm dbnm paren_exprlist */ +#line 1168 "parse.y" +{ + SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); + Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); + if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; + } +#line 3478 "parse.c" + break; + case 195: /* expr ::= EXISTS LP select RP */ +#line 1177 "parse.y" +{ + Expr *p; + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243); + } +#line 3488 "parse.c" + break; + case 196: /* expr ::= CASE case_operand case_exprlist case_else END */ +#line 1186 "parse.y" +{ + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72); + } +} +#line 3503 "parse.c" + break; + case 197: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ +#line 1199 "parse.y" +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); +} +#line 3511 "parse.c" + break; + case 198: /* case_exprlist ::= WHEN expr THEN expr */ +#line 1203 "parse.y" +{ + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr); +} +#line 3519 "parse.c" + break; + case 201: /* case_operand ::= expr */ +#line 1213 "parse.y" +{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/} +#line 3524 "parse.c" + break; + case 204: /* nexprlist ::= nexprlist COMMA expr */ +#line 1224 "parse.y" +{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);} +#line 3529 "parse.c" + break; + case 205: /* nexprlist ::= expr */ +#line 1226 "parse.y" +{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/} +#line 3534 "parse.c" + break; + case 207: /* paren_exprlist ::= LP exprlist RP */ + case 212: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==212); +#line 1234 "parse.y" +{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;} +#line 3540 "parse.c" + break; + case 208: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ +#line 1241 "parse.y" +{ + sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, + sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF); +} +#line 3549 "parse.c" + break; + case 209: /* uniqueflag ::= UNIQUE */ + case 250: /* raisetype ::= ABORT */ yytestcase(yyruleno==250); +#line 1248 "parse.y" +{yymsp[0].minor.yy194 = OE_Abort;} +#line 3555 "parse.c" + break; + case 210: /* uniqueflag ::= */ +#line 1249 "parse.y" +{yymsp[1].minor.yy194 = OE_None;} +#line 3560 "parse.c" + break; + case 213: /* eidlist ::= eidlist COMMA nm collate sortorder */ +#line 1299 "parse.y" +{ + yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); +} +#line 3567 "parse.c" + break; + case 214: /* eidlist ::= nm collate sortorder */ +#line 1302 "parse.y" +{ + yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/ +} +#line 3574 "parse.c" + break; + case 217: /* cmd ::= DROP INDEX ifexists fullname */ +#line 1313 "parse.y" +{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);} +#line 3579 "parse.c" + break; + case 218: /* cmd ::= VACUUM */ +#line 1319 "parse.y" +{sqlite3Vacuum(pParse,0);} +#line 3584 "parse.c" + break; + case 219: /* cmd ::= VACUUM nm */ +#line 1320 "parse.y" +{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} +#line 3589 "parse.c" + break; + case 220: /* cmd ::= PRAGMA nm dbnm */ +#line 1327 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} +#line 3594 "parse.c" + break; + case 221: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ +#line 1328 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} +#line 3599 "parse.c" + break; + case 222: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ +#line 1329 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} +#line 3604 "parse.c" + break; + case 223: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ +#line 1331 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} +#line 3609 "parse.c" + break; + case 224: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ +#line 1333 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} +#line 3614 "parse.c" + break; + case 227: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ +#line 1349 "parse.y" +{ + Token all; + all.z = yymsp[-3].minor.yy0.z; + all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all); +} +#line 3624 "parse.c" + break; + case 228: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ +#line 1358 "parse.y" +{ + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194); + yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ +} +#line 3632 "parse.c" + break; + case 229: /* trigger_time ::= BEFORE */ +#line 1364 "parse.y" +{ yymsp[0].minor.yy194 = TK_BEFORE; } +#line 3637 "parse.c" + break; + case 230: /* trigger_time ::= AFTER */ +#line 1365 "parse.y" +{ yymsp[0].minor.yy194 = TK_AFTER; } +#line 3642 "parse.c" + break; + case 231: /* trigger_time ::= INSTEAD OF */ +#line 1366 "parse.y" +{ yymsp[-1].minor.yy194 = TK_INSTEAD;} +#line 3647 "parse.c" + break; + case 232: /* trigger_time ::= */ +#line 1367 "parse.y" +{ yymsp[1].minor.yy194 = TK_BEFORE; } +#line 3652 "parse.c" + break; + case 233: /* trigger_event ::= DELETE|INSERT */ + case 234: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==234); +#line 1371 "parse.y" +{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;} +#line 3658 "parse.c" + break; + case 235: /* trigger_event ::= UPDATE OF idlist */ +#line 1373 "parse.y" +{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;} +#line 3663 "parse.c" + break; + case 236: /* when_clause ::= */ + case 255: /* key_opt ::= */ yytestcase(yyruleno==255); +#line 1380 "parse.y" +{ yymsp[1].minor.yy72 = 0; } +#line 3669 "parse.c" + break; + case 237: /* when_clause ::= WHEN expr */ + case 256: /* key_opt ::= KEY expr */ yytestcase(yyruleno==256); +#line 1381 "parse.y" +{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; } +#line 3675 "parse.c" + break; + case 238: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ +#line 1385 "parse.y" +{ + assert( yymsp[-2].minor.yy145!=0 ); + yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145; + yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145; +} +#line 3684 "parse.c" + break; + case 239: /* trigger_cmd_list ::= trigger_cmd SEMI */ +#line 1390 "parse.y" +{ + assert( yymsp[-1].minor.yy145!=0 ); + yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145; +} +#line 3692 "parse.c" + break; + case 240: /* trnm ::= nm DOT nm */ +#line 1401 "parse.y" +{ + yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; + sqlite3ErrorMsg(pParse, + "qualified table names are not allowed on INSERT, UPDATE, and DELETE " + "statements within triggers"); +} +#line 3702 "parse.c" + break; + case 241: /* tridxby ::= INDEXED BY nm */ +#line 1413 "parse.y" +{ + sqlite3ErrorMsg(pParse, + "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} +#line 3711 "parse.c" + break; + case 242: /* tridxby ::= NOT INDEXED */ +#line 1418 "parse.y" +{ + sqlite3ErrorMsg(pParse, + "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} +#line 3720 "parse.c" + break; + case 243: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ +#line 1431 "parse.y" +{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);} +#line 3725 "parse.c" + break; + case 244: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ +#line 1435 "parse.y" +{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/} +#line 3730 "parse.c" + break; + case 245: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ +#line 1439 "parse.y" +{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);} +#line 3735 "parse.c" + break; + case 246: /* trigger_cmd ::= select */ +#line 1443 "parse.y" +{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/} +#line 3740 "parse.c" + break; + case 247: /* expr ::= RAISE LP IGNORE RP */ +#line 1446 "parse.y" +{ + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); + if( yymsp[-3].minor.yy190.pExpr ){ + yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore; + } +} +#line 3751 "parse.c" + break; + case 248: /* expr ::= RAISE LP raisetype COMMA nm RP */ +#line 1453 "parse.y" +{ + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); + if( yymsp[-5].minor.yy190.pExpr ) { + yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194; + } +} +#line 3762 "parse.c" + break; + case 249: /* raisetype ::= ROLLBACK */ +#line 1463 "parse.y" +{yymsp[0].minor.yy194 = OE_Rollback;} +#line 3767 "parse.c" + break; + case 251: /* raisetype ::= FAIL */ +#line 1465 "parse.y" +{yymsp[0].minor.yy194 = OE_Fail;} +#line 3772 "parse.c" + break; + case 252: /* cmd ::= DROP TRIGGER ifexists fullname */ +#line 1470 "parse.y" +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194); +} +#line 3779 "parse.c" + break; + case 253: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ +#line 1477 "parse.y" +{ + sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72); +} +#line 3786 "parse.c" + break; + case 254: /* cmd ::= DETACH database_kw_opt expr */ +#line 1480 "parse.y" +{ + sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr); +} +#line 3793 "parse.c" + break; + case 257: /* cmd ::= REINDEX */ +#line 1495 "parse.y" +{sqlite3Reindex(pParse, 0, 0);} +#line 3798 "parse.c" + break; + case 258: /* cmd ::= REINDEX nm dbnm */ +#line 1496 "parse.y" +{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} +#line 3803 "parse.c" + break; + case 259: /* cmd ::= ANALYZE */ +#line 1501 "parse.y" +{sqlite3Analyze(pParse, 0, 0);} +#line 3808 "parse.c" + break; + case 260: /* cmd ::= ANALYZE nm dbnm */ +#line 1502 "parse.y" +{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} +#line 3813 "parse.c" + break; + case 261: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ +#line 1507 "parse.y" +{ + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0); +} +#line 3820 "parse.c" + break; + case 262: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ +#line 1511 "parse.y" +{ + yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; + sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); +} +#line 3828 "parse.c" + break; + case 263: /* add_column_fullname ::= fullname */ +#line 1515 "parse.y" +{ + disableLookaside(pParse); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185); +} +#line 3836 "parse.c" + break; + case 264: /* cmd ::= create_vtab */ +#line 1525 "parse.y" +{sqlite3VtabFinishParse(pParse,0);} +#line 3841 "parse.c" + break; + case 265: /* cmd ::= create_vtab LP vtabarglist RP */ +#line 1526 "parse.y" +{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} +#line 3846 "parse.c" + break; + case 266: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ +#line 1528 "parse.y" +{ + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194); +} +#line 3853 "parse.c" + break; + case 267: /* vtabarg ::= */ +#line 1533 "parse.y" +{sqlite3VtabArgInit(pParse);} +#line 3858 "parse.c" + break; + case 268: /* vtabargtoken ::= ANY */ + case 269: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==269); + case 270: /* lp ::= LP */ yytestcase(yyruleno==270); +#line 1535 "parse.y" +{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} +#line 3865 "parse.c" + break; + case 271: /* with ::= */ +#line 1550 "parse.y" +{yymsp[1].minor.yy285 = 0;} +#line 3870 "parse.c" + break; + case 272: /* with ::= WITH wqlist */ +#line 1552 "parse.y" +{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; } +#line 3875 "parse.c" + break; + case 273: /* with ::= WITH RECURSIVE wqlist */ +#line 1553 "parse.y" +{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; } +#line 3880 "parse.c" + break; + case 274: /* wqlist ::= nm eidlist_opt AS LP select RP */ +#line 1555 "parse.y" +{ + yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/ +} +#line 3887 "parse.c" + break; + case 275: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ +#line 1558 "parse.y" +{ + yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); +} +#line 3894 "parse.c" + break; + default: + /* (276) input ::= cmdlist */ yytestcase(yyruleno==276); + /* (277) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==277); + /* (278) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=278); + /* (279) ecmd ::= SEMI */ yytestcase(yyruleno==279); + /* (280) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==280); + /* (281) explain ::= */ yytestcase(yyruleno==281); + /* (282) trans_opt ::= */ yytestcase(yyruleno==282); + /* (283) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==283); + /* (284) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==284); + /* (285) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==285); + /* (286) savepoint_opt ::= */ yytestcase(yyruleno==286); + /* (287) cmd ::= create_table create_table_args */ yytestcase(yyruleno==287); + /* (288) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==288); + /* (289) columnlist ::= columnname carglist */ yytestcase(yyruleno==289); + /* (290) nm ::= ID|INDEXED */ yytestcase(yyruleno==290); + /* (291) nm ::= STRING */ yytestcase(yyruleno==291); + /* (292) nm ::= JOIN_KW */ yytestcase(yyruleno==292); + /* (293) typetoken ::= typename */ yytestcase(yyruleno==293); + /* (294) typename ::= ID|STRING */ yytestcase(yyruleno==294); + /* (295) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=295); + /* (296) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=296); + /* (297) carglist ::= carglist ccons */ yytestcase(yyruleno==297); + /* (298) carglist ::= */ yytestcase(yyruleno==298); + /* (299) ccons ::= NULL onconf */ yytestcase(yyruleno==299); + /* (300) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==300); + /* (301) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==301); + /* (302) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=302); + /* (303) tconscomma ::= */ yytestcase(yyruleno==303); + /* (304) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=304); + /* (305) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=305); + /* (306) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=306); + /* (307) oneselect ::= values */ yytestcase(yyruleno==307); + /* (308) sclp ::= selcollist COMMA */ yytestcase(yyruleno==308); + /* (309) as ::= ID|STRING */ yytestcase(yyruleno==309); + /* (310) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=310); + /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311); + /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312); + /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313); + /* (314) nmnum ::= ON */ yytestcase(yyruleno==314); + /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315); + /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316); + /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317); + /* (318) foreach_clause ::= */ yytestcase(yyruleno==318); + /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319); + /* (320) trnm ::= nm */ yytestcase(yyruleno==320); + /* (321) tridxby ::= */ yytestcase(yyruleno==321); + /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322); + /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323); + /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324); + /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325); + /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326); + /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327); + /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328); + /* (329) anylist ::= */ yytestcase(yyruleno==329); + /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330); + /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331); + break; +/********** End reduce actions ************************************************/ + }; + assert( yyrulenoYY_MAX_SHIFT ){ + yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yymsp -= yysize-1; + yypParser->yytos = yymsp; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yyTraceShift(yypParser, yyact); + }else{ + assert( yyact == YY_ACCEPT_ACTION ); + yypParser->yytos -= yysize; + yy_accept(yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +#ifndef YYNOERRORRECOVERY +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + sqlite3ParserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ +/************ Begin %parse_failure code ***************************************/ +/************ End %parse_failure code *****************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} +#endif /* YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ +){ + sqlite3ParserARG_FETCH; +#define TOKEN yyminor +/************ Begin %syntax_error code ****************************************/ +#line 32 "parse.y" + + UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ + assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); +#line 4014 "parse.c" +/************ End %syntax_error code ******************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + sqlite3ParserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + assert( yypParser->yytos==yypParser->yystack ); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +/*********** Begin %parse_accept code *****************************************/ +/*********** End %parse_accept code *******************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "sqlite3ParserAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** Outputs: +** None. +*/ +void sqlite3Parser( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + sqlite3ParserTOKENTYPE yyminor /* The value for the token */ + sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + unsigned int yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) + int yyendofinput; /* True if we are at the end of input */ +#endif +#ifdef YYERRORSYMBOL + int yyerrorhit = 0; /* True if yymajor has invoked an error */ +#endif + yyParser *yypParser; /* The parser */ + + yypParser = (yyParser*)yyp; + assert( yypParser->yytos!=0 ); +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) + yyendofinput = (yymajor==0); +#endif + sqlite3ParserARG_STORE; + +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); + } +#endif + + do{ + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); + if( yyact <= YY_MAX_SHIFTREDUCE ){ + yy_shift(yypParser,yyact,yymajor,yyminor); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt--; +#endif + yymajor = YYNOCODE; + }else if( yyact <= YY_MAX_REDUCE ){ + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); + }else{ + assert( yyact == YY_ERROR_ACTION ); + yyminorunion.yy0 = yyminor; +#ifdef YYERRORSYMBOL + int yymx; +#endif +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminor); + } + yymx = yypParser->yytos->major; + if( yymx==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); + yymajor = YYNOCODE; + }else{ + while( yypParser->yytos >= yypParser->yystack + && yymx != YYERRORSYMBOL + && (yyact = yy_find_reduce_action( + yypParser->yytos->stateno, + YYERRORSYMBOL)) >= YY_MIN_REDUCE + ){ + yy_pop_parser_stack(yypParser); + } + if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + yymajor = YYNOCODE; + }else if( yymx!=YYERRORSYMBOL ){ + yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor, yyminor); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor, yyminor); + } + yypParser->yyerrcnt = 3; + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + } + yymajor = YYNOCODE; +#endif + } + }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); +#ifndef NDEBUG + if( yyTraceFILE ){ + yyStackEntry *i; + char cDiv = '['; + fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); + cDiv = ' '; + } + fprintf(yyTraceFILE,"]\n"); + } +#endif + return; +} diff --git a/parse.h b/parse.h new file mode 100644 index 0000000000..cd17509bc2 --- /dev/null +++ b/parse.h @@ -0,0 +1,170 @@ +#define TK_SEMI 1 +#define TK_EXPLAIN 2 +#define TK_QUERY 3 +#define TK_PLAN 4 +#define TK_BEGIN 5 +#define TK_TRANSACTION 6 +#define TK_DEFERRED 7 +#define TK_IMMEDIATE 8 +#define TK_EXCLUSIVE 9 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_SAVEPOINT 13 +#define TK_RELEASE 14 +#define TK_TO 15 +#define TK_TABLE 16 +#define TK_CREATE 17 +#define TK_IF 18 +#define TK_NOT 19 +#define TK_EXISTS 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_WITHOUT 25 +#define TK_COMMA 26 +#define TK_OR 27 +#define TK_AND 28 +#define TK_IS 29 +#define TK_MATCH 30 +#define TK_LIKE_KW 31 +#define TK_BETWEEN 32 +#define TK_IN 33 +#define TK_ISNULL 34 +#define TK_NOTNULL 35 +#define TK_NE 36 +#define TK_EQ 37 +#define TK_GT 38 +#define TK_LE 39 +#define TK_LT 40 +#define TK_GE 41 +#define TK_ESCAPE 42 +#define TK_BITAND 43 +#define TK_BITOR 44 +#define TK_LSHIFT 45 +#define TK_RSHIFT 46 +#define TK_PLUS 47 +#define TK_MINUS 48 +#define TK_STAR 49 +#define TK_SLASH 50 +#define TK_REM 51 +#define TK_CONCAT 52 +#define TK_COLLATE 53 +#define TK_BITNOT 54 +#define TK_ID 55 +#define TK_INDEXED 56 +#define TK_ABORT 57 +#define TK_ACTION 58 +#define TK_AFTER 59 +#define TK_ANALYZE 60 +#define TK_ASC 61 +#define TK_ATTACH 62 +#define TK_BEFORE 63 +#define TK_BY 64 +#define TK_CASCADE 65 +#define TK_CAST 66 +#define TK_COLUMNKW 67 +#define TK_CONFLICT 68 +#define TK_DATABASE 69 +#define TK_DESC 70 +#define TK_DETACH 71 +#define TK_EACH 72 +#define TK_FAIL 73 +#define TK_FOR 74 +#define TK_IGNORE 75 +#define TK_INITIALLY 76 +#define TK_INSTEAD 77 +#define TK_NO 78 +#define TK_KEY 79 +#define TK_OF 80 +#define TK_OFFSET 81 +#define TK_PRAGMA 82 +#define TK_RAISE 83 +#define TK_RECURSIVE 84 +#define TK_REPLACE 85 +#define TK_RESTRICT 86 +#define TK_ROW 87 +#define TK_TRIGGER 88 +#define TK_VACUUM 89 +#define TK_VIEW 90 +#define TK_VIRTUAL 91 +#define TK_WITH 92 +#define TK_REINDEX 93 +#define TK_RENAME 94 +#define TK_CTIME_KW 95 +#define TK_ANY 96 +#define TK_STRING 97 +#define TK_JOIN_KW 98 +#define TK_CONSTRAINT 99 +#define TK_DEFAULT 100 +#define TK_NULL 101 +#define TK_PRIMARY 102 +#define TK_UNIQUE 103 +#define TK_CHECK 104 +#define TK_REFERENCES 105 +#define TK_AUTOINCR 106 +#define TK_ON 107 +#define TK_INSERT 108 +#define TK_DELETE 109 +#define TK_UPDATE 110 +#define TK_SET 111 +#define TK_DEFERRABLE 112 +#define TK_FOREIGN 113 +#define TK_DROP 114 +#define TK_UNION 115 +#define TK_ALL 116 +#define TK_EXCEPT 117 +#define TK_INTERSECT 118 +#define TK_SELECT 119 +#define TK_VALUES 120 +#define TK_DISTINCT 121 +#define TK_DOT 122 +#define TK_FROM 123 +#define TK_JOIN 124 +#define TK_USING 125 +#define TK_ORDER 126 +#define TK_GROUP 127 +#define TK_HAVING 128 +#define TK_LIMIT 129 +#define TK_WHERE 130 +#define TK_INTO 131 +#define TK_FLOAT 132 +#define TK_BLOB 133 +#define TK_INTEGER 134 +#define TK_VARIABLE 135 +#define TK_CASE 136 +#define TK_WHEN 137 +#define TK_THEN 138 +#define TK_ELSE 139 +#define TK_INDEX 140 +#define TK_ALTER 141 +#define TK_ADD 142 +#define TK_TO_TEXT 143 +#define TK_TO_BLOB 144 +#define TK_TO_NUMERIC 145 +#define TK_TO_INT 146 +#define TK_TO_REAL 147 +#define TK_ISNOT 148 +#define TK_END_OF_FILE 149 +#define TK_UNCLOSED_STRING 150 +#define TK_FUNCTION 151 +#define TK_COLUMN 152 +#define TK_AGG_FUNCTION 153 +#define TK_AGG_COLUMN 154 +#define TK_UMINUS 155 +#define TK_UPLUS 156 +#define TK_REGISTER 157 +#define TK_VECTOR 158 +#define TK_SELECT_COLUMN 159 +#define TK_ASTERISK 160 +#define TK_SPAN 161 +#define TK_SPACE 162 +#define TK_ILLEGAL 163 + +/* The token codes above must all fit in 8 bits */ +#define TKFLG_MASK 0xff + +/* Flags that can be added to a token code when it is not +** being stored in a u8: */ +#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */ diff --git a/sqlcipher.preprocessed.xcodeproj/project.pbxproj b/sqlcipher.preprocessed.xcodeproj/project.pbxproj index 8a21aea117..7579e41f60 100644 --- a/sqlcipher.preprocessed.xcodeproj/project.pbxproj +++ b/sqlcipher.preprocessed.xcodeproj/project.pbxproj @@ -215,23 +215,6 @@ 23F5BC3B20887FAB000CCD37 /* sqlite3.h in Headers */ = {isa = PBXBuildFile; fileRef = 232DA3CF1FB082C70075F021 /* sqlite3.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - 23E737CD1FB1693400EEBC3D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 23E737C91FB168B500EEBC3D; - remoteInfo = preprocess; - }; - 23F5BBD120887FAB000CCD37 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 23121ADC1E6FF9110012B45E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 23E737C91FB168B500EEBC3D; - remoteInfo = preprocess; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ 23121C071E6FFA890012B45E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 232DA3201FB06FFD0075F021 /* keywordhash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = keywordhash.h; path = ../keywordhash.h; sourceTree = ""; }; @@ -636,7 +619,6 @@ buildRules = ( ); dependencies = ( - 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */, ); name = "sqlcipher for Coverage"; productName = sqlcipher; @@ -655,7 +637,6 @@ buildRules = ( ); dependencies = ( - 23F5BBD020887FAB000CCD37 /* PBXTargetDependency */, ); name = sqlcipher; productName = sqlcipher; @@ -932,19 +913,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - 23E737CE1FB1693400EEBC3D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 23E737C91FB168B500EEBC3D /* preprocess */; - targetProxy = 23E737CD1FB1693400EEBC3D /* PBXContainerItemProxy */; - }; - 23F5BBD020887FAB000CCD37 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 23E737C91FB168B500EEBC3D /* preprocess */; - targetProxy = 23F5BBD120887FAB000CCD37 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin XCBuildConfiguration section */ 23121AE61E6FF9110012B45E /* Debug */ = { isa = XCBuildConfiguration; diff --git a/sqlite3.h b/sqlite3.h new file mode 100644 index 0000000000..8222b7930e --- /dev/null +++ b/sqlite3.h @@ -0,0 +1,10371 @@ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the SQLite library +** presents to client programs. If a C-function, structure, datatype, +** or constant definition does not appear in this file, then it is +** not a published API of SQLite, is subject to change without +** notice, and should not be referenced by programs that use SQLite. +** +** Some of the definitions that are in this file are marked as +** "experimental". Experimental interfaces are normally new +** features recently added to SQLite. We do not anticipate changes +** to experimental interfaces but reserve the right to make minor changes +** if experience from use "in the wild" suggest such changes are prudent. +** +** The official C-language API documentation for SQLite is derived +** from comments in this file. This file is the authoritative source +** on how SQLite interfaces are supposed to operate. +** +** The name of this file under configuration management is "sqlite.h.in". +** The makefile makes some minor changes to this file (such as inserting +** the version number) and changes its name to "sqlite3.h" as +** part of the build process. +*/ +#ifndef SQLITE3_H +#define SQLITE3_H +#include /* Needed for the definition of va_list */ + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + + +/* +** Provide the ability to override linkage features of the interface. +*/ +#ifndef SQLITE_EXTERN +# define SQLITE_EXTERN extern +#endif +#ifndef SQLITE_API +# define SQLITE_API +#endif +#ifndef SQLITE_CDECL +# define SQLITE_CDECL +#endif +#ifndef SQLITE_APICALL +# define SQLITE_APICALL +#endif +#ifndef SQLITE_STDCALL +# define SQLITE_STDCALL SQLITE_APICALL +#endif +#ifndef SQLITE_CALLBACK +# define SQLITE_CALLBACK +#endif +#ifndef SQLITE_SYSAPI +# define SQLITE_SYSAPI +#endif + +/* +** These no-op macros are used in front of interfaces to mark those +** interfaces as either deprecated or experimental. New applications +** should not use deprecated interfaces - they are supported for backwards +** compatibility only. Application writers should be aware that +** experimental interfaces are subject to change in point releases. +** +** These macros used to resolve to various kinds of compiler magic that +** would generate warning messages when they were used. But that +** compiler magic ended up generating such a flurry of bug reports +** that we have taken it all out and gone back to using simple +** noop macros. +*/ +#define SQLITE_DEPRECATED +#define SQLITE_EXPERIMENTAL + +/* +** Ensure these symbols were not defined by some previous header file. +*/ +#ifdef SQLITE_VERSION +# undef SQLITE_VERSION +#endif +#ifdef SQLITE_VERSION_NUMBER +# undef SQLITE_VERSION_NUMBER +#endif + +/* +** CAPI3REF: Compile-Time Library Version Numbers +** +** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header +** evaluates to a string literal that is the SQLite version in the +** format "X.Y.Z" where X is the major version number (always 3 for +** SQLite3) and Y is the minor version number and Z is the release number.)^ +** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer +** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same +** numbers used in [SQLITE_VERSION].)^ +** The SQLITE_VERSION_NUMBER for any given release of SQLite will also +** be larger than the release from which it is derived. Either Y will +** be held constant and Z will be incremented or else Y will be incremented +** and Z will be reset to zero. +** +** Since [version 3.6.18] ([dateof:3.6.18]), +** SQLite source code has been stored in the +** Fossil configuration management +** system. ^The SQLITE_SOURCE_ID macro evaluates to +** a string which identifies a particular check-in of SQLite +** within its configuration management system. ^The SQLITE_SOURCE_ID +** string contains the date and time of the check-in (UTC) and an SHA1 +** hash of the entire source tree. +** +** See also: [sqlite3_libversion()], +** [sqlite3_libversion_number()], [sqlite3_sourceid()], +** [sqlite_version()] and [sqlite_source_id()]. +*/ +#define SQLITE_VERSION "3.15.2" +#define SQLITE_VERSION_NUMBER 3015002 +#define SQLITE_SOURCE_ID "2016-11-28 19:13:37 bbd85d235f7037c6a033a9690534391ffeacecc8" + +/* +** CAPI3REF: Run-Time Library Version Numbers +** KEYWORDS: sqlite3_version, sqlite3_sourceid +** +** These interfaces provide the same information as the [SQLITE_VERSION], +** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros +** but are associated with the library instead of the header file. ^(Cautious +** programmers might include assert() statements in their application to +** verify that values returned by these interfaces match the macros in +** the header, and thus ensure that the application is +** compiled with matching library and header files. +** +**
+** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
+** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
+** 
)^ +** +** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] +** macro. ^The sqlite3_libversion() function returns a pointer to the +** to the sqlite3_version[] string constant. The sqlite3_libversion() +** function is provided for use in DLLs since DLL users usually do not have +** direct access to string constants within the DLL. ^The +** sqlite3_libversion_number() function returns an integer equal to +** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** a pointer to a string constant whose value is the same as the +** [SQLITE_SOURCE_ID] C preprocessor macro. +** +** See also: [sqlite_version()] and [sqlite_source_id()]. +*/ +SQLITE_API SQLITE_EXTERN const char sqlite3_version[]; +SQLITE_API const char *sqlite3_libversion(void); +SQLITE_API const char *sqlite3_sourceid(void); +SQLITE_API int sqlite3_libversion_number(void); + +/* +** CAPI3REF: Run-Time Library Compilation Options Diagnostics +** +** ^The sqlite3_compileoption_used() function returns 0 or 1 +** indicating whether the specified option was defined at +** compile time. ^The SQLITE_ prefix may be omitted from the +** option name passed to sqlite3_compileoption_used(). +** +** ^The sqlite3_compileoption_get() function allows iterating +** over the list of options that were defined at compile time by +** returning the N-th compile time option string. ^If N is out of range, +** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ +** prefix is omitted from any strings returned by +** sqlite3_compileoption_get(). +** +** ^Support for the diagnostic functions sqlite3_compileoption_used() +** and sqlite3_compileoption_get() may be omitted by specifying the +** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. +** +** See also: SQL functions [sqlite_compileoption_used()] and +** [sqlite_compileoption_get()] and the [compile_options pragma]. +*/ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_API int sqlite3_compileoption_used(const char *zOptName); +SQLITE_API const char *sqlite3_compileoption_get(int N); +#endif + +/* +** CAPI3REF: Test To See If The Library Is Threadsafe +** +** ^The sqlite3_threadsafe() function returns zero if and only if +** SQLite was compiled with mutexing code omitted due to the +** [SQLITE_THREADSAFE] compile-time option being set to 0. +** +** SQLite can be compiled with or without mutexes. When +** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes +** are enabled and SQLite is threadsafe. When the +** [SQLITE_THREADSAFE] macro is 0, +** the mutexes are omitted. Without the mutexes, it is not safe +** to use SQLite concurrently from more than one thread. +** +** Enabling mutexes incurs a measurable performance penalty. +** So if speed is of utmost importance, it makes sense to disable +** the mutexes. But for maximum safety, mutexes should be enabled. +** ^The default behavior is for mutexes to be enabled. +** +** This interface can be used by an application to make sure that the +** version of SQLite that it is linking against was compiled with +** the desired setting of the [SQLITE_THREADSAFE] macro. +** +** This interface only reports on the compile-time mutex setting +** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with +** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but +** can be fully or partially disabled using a call to [sqlite3_config()] +** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], +** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the +** sqlite3_threadsafe() function shows only the compile-time setting of +** thread safety, not any run-time changes to that setting made by +** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() +** is unchanged by calls to sqlite3_config().)^ +** +** See the [threading mode] documentation for additional information. +*/ +SQLITE_API int sqlite3_threadsafe(void); + +/* +** CAPI3REF: Database Connection Handle +** KEYWORDS: {database connection} {database connections} +** +** Each open SQLite database is represented by a pointer to an instance of +** the opaque structure named "sqlite3". It is useful to think of an sqlite3 +** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and +** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] +** and [sqlite3_close_v2()] are its destructors. There are many other +** interfaces (such as +** [sqlite3_prepare_v2()], [sqlite3_create_function()], and +** [sqlite3_busy_timeout()] to name but three) that are methods on an +** sqlite3 object. +*/ +typedef struct sqlite3 sqlite3; + +/* +** CAPI3REF: 64-Bit Integer Types +** KEYWORDS: sqlite_int64 sqlite_uint64 +** +** Because there is no cross-platform way to specify 64-bit integer types +** SQLite includes typedefs for 64-bit signed and unsigned integers. +** +** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. +** The sqlite_int64 and sqlite_uint64 types are supported for backwards +** compatibility only. +** +** ^The sqlite3_int64 and sqlite_int64 types can store integer values +** between -9223372036854775808 and +9223372036854775807 inclusive. ^The +** sqlite3_uint64 and sqlite_uint64 types can store integer values +** between 0 and +18446744073709551615 inclusive. +*/ +#ifdef SQLITE_INT64_TYPE + typedef SQLITE_INT64_TYPE sqlite_int64; + typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +#elif defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 sqlite_int64; + typedef unsigned __int64 sqlite_uint64; +#else + typedef long long int sqlite_int64; + typedef unsigned long long int sqlite_uint64; +#endif +typedef sqlite_int64 sqlite3_int64; +typedef sqlite_uint64 sqlite3_uint64; + +/* +** If compiling for a processor that lacks floating point support, +** substitute integer for floating-point. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# define double sqlite3_int64 +#endif + +/* +** CAPI3REF: Closing A Database Connection +** DESTRUCTOR: sqlite3 +** +** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors +** for the [sqlite3] object. +** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if +** the [sqlite3] object is successfully destroyed and all associated +** resources are deallocated. +** +** ^If the database connection is associated with unfinalized prepared +** statements or unfinished sqlite3_backup objects then sqlite3_close() +** will leave the database connection open and return [SQLITE_BUSY]. +** ^If sqlite3_close_v2() is called with unfinalized prepared statements +** and/or unfinished sqlite3_backups, then the database connection becomes +** an unusable "zombie" which will automatically be deallocated when the +** last prepared statement is finalized or the last sqlite3_backup is +** finished. The sqlite3_close_v2() interface is intended for use with +** host languages that are garbage collected, and where the order in which +** destructors are called is arbitrary. +** +** Applications should [sqlite3_finalize | finalize] all [prepared statements], +** [sqlite3_blob_close | close] all [BLOB handles], and +** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated +** with the [sqlite3] object prior to attempting to close the object. ^If +** sqlite3_close_v2() is called on a [database connection] that still has +** outstanding [prepared statements], [BLOB handles], and/or +** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation +** of resources is deferred until all [prepared statements], [BLOB handles], +** and [sqlite3_backup] objects are also destroyed. +** +** ^If an [sqlite3] object is destroyed while a transaction is open, +** the transaction is automatically rolled back. +** +** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] +** must be either a NULL +** pointer or an [sqlite3] object pointer obtained +** from [sqlite3_open()], [sqlite3_open16()], or +** [sqlite3_open_v2()], and not previously closed. +** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer +** argument is a harmless no-op. +*/ +SQLITE_API int sqlite3_close(sqlite3*); +SQLITE_API int sqlite3_close_v2(sqlite3*); + +/* +** The type for a callback function. +** This is legacy and deprecated. It is included for historical +** compatibility and is not documented. +*/ +typedef int (*sqlite3_callback)(void*,int,char**, char**); + +/* +** CAPI3REF: One-Step Query Execution Interface +** METHOD: sqlite3 +** +** The sqlite3_exec() interface is a convenience wrapper around +** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], +** that allows an application to run multiple statements of SQL +** without having to use a lot of C code. +** +** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, +** semicolon-separate SQL statements passed into its 2nd argument, +** in the context of the [database connection] passed in as its 1st +** argument. ^If the callback function of the 3rd argument to +** sqlite3_exec() is not NULL, then it is invoked for each result row +** coming out of the evaluated SQL statements. ^The 4th argument to +** sqlite3_exec() is relayed through to the 1st argument of each +** callback invocation. ^If the callback pointer to sqlite3_exec() +** is NULL, then no callback is ever invoked and result rows are +** ignored. +** +** ^If an error occurs while evaluating the SQL statements passed into +** sqlite3_exec(), then execution of the current statement stops and +** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() +** is not NULL then any error message is written into memory obtained +** from [sqlite3_malloc()] and passed back through the 5th parameter. +** To avoid memory leaks, the application should invoke [sqlite3_free()] +** on error message strings returned through the 5th parameter of +** sqlite3_exec() after the error message string is no longer needed. +** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors +** occur, then sqlite3_exec() sets the pointer in its 5th parameter to +** NULL before returning. +** +** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() +** routine returns SQLITE_ABORT without invoking the callback again and +** without running any subsequent SQL statements. +** +** ^The 2nd argument to the sqlite3_exec() callback function is the +** number of columns in the result. ^The 3rd argument to the sqlite3_exec() +** callback is an array of pointers to strings obtained as if from +** [sqlite3_column_text()], one for each column. ^If an element of a +** result row is NULL then the corresponding string pointer for the +** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the +** sqlite3_exec() callback is an array of pointers to strings where each +** entry represents the name of corresponding result column as obtained +** from [sqlite3_column_name()]. +** +** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer +** to an empty string, or a pointer that contains only whitespace and/or +** SQL comments, then no SQL statements are evaluated and the database +** is not changed. +** +** Restrictions: +** +**
    +**
  • The application must ensure that the 1st parameter to sqlite3_exec() +** is a valid and open [database connection]. +**
  • The application must not close the [database connection] specified by +** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. +**
  • The application must not modify the SQL statement text passed into +** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. +**
+*/ +SQLITE_API int sqlite3_exec( + sqlite3*, /* An open database */ + const char *sql, /* SQL to be evaluated */ + int (*callback)(void*,int,char**,char**), /* Callback function */ + void *, /* 1st argument to callback */ + char **errmsg /* Error msg written here */ +); + +/* +** CAPI3REF: Result Codes +** KEYWORDS: {result code definitions} +** +** Many SQLite functions return an integer result code from the set shown +** here in order to indicate success or failure. +** +** New error codes may be added in future versions of SQLite. +** +** See also: [extended result code definitions] +*/ +#define SQLITE_OK 0 /* Successful result */ +/* beginning-of-error-codes */ +#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* The database file is locked */ +#define SQLITE_LOCKED 6 /* A table in the database is locked */ +#define SQLITE_NOMEM 7 /* A malloc() failed */ +#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ +#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ +#define SQLITE_FULL 13 /* Insertion failed because database is full */ +#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ +#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ +#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_SCHEMA 17 /* The database schema changed */ +#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ +#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ +#define SQLITE_MISMATCH 20 /* Data type mismatch */ +#define SQLITE_MISUSE 21 /* Library used incorrectly */ +#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* Authorization denied */ +#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ +#define SQLITE_NOTADB 26 /* File opened that is not a database file */ +#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ +#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ +#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +/* end-of-error-codes */ + +/* +** CAPI3REF: Extended Result Codes +** KEYWORDS: {extended result code definitions} +** +** In its default configuration, SQLite API routines return one of 30 integer +** [result codes]. However, experience has shown that many of +** these result codes are too coarse-grained. They do not provide as +** much information about problems as programmers might like. In an effort to +** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] +** and later) include +** support for additional result codes that provide more detailed information +** about errors. These [extended result codes] are enabled or disabled +** on a per database connection basis using the +** [sqlite3_extended_result_codes()] API. Or, the extended code for +** the most recent error can be obtained using +** [sqlite3_extended_errcode()]. +*/ +#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) +#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) +#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) +#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) +#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) +#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) +#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) +#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) +#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) +#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) +#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) +#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) +#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) +#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) +#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) +#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) +#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) +#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) +#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) +#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) +#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) +#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) +#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) +#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) +#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) +#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) +#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) +#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) +#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) +#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) +#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) +#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) +#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) +#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) +#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) +#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) +#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) +#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) +#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) +#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) +#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) +#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) +#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) +#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) +#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) +#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) +#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) + +/* +** CAPI3REF: Flags For File Open Operations +** +** These bit values are intended for use in the +** 3rd parameter to the [sqlite3_open_v2()] interface and +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. +*/ +#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ +#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ +#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ +#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ +#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ +#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ +#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ +#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ +#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ + +/* Reserved: 0x00F00000 */ + +/* +** CAPI3REF: Device Characteristics +** +** The xDeviceCharacteristics method of the [sqlite3_io_methods] +** object returns an integer which is a vector of these +** bit values expressing I/O characteristics of the mass storage +** device that holds the file that the [sqlite3_io_methods] +** refers to. +** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that +** after reboot following a crash or power loss, the only bytes in a +** file that were written at the application level might have changed +** and that adjacent bytes, even bytes within the same sector are +** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN +** flag indicate that a file cannot be deleted when open. The +** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on +** read-only media and cannot be changed even by processes with +** elevated privileges. +*/ +#define SQLITE_IOCAP_ATOMIC 0x00000001 +#define SQLITE_IOCAP_ATOMIC512 0x00000002 +#define SQLITE_IOCAP_ATOMIC1K 0x00000004 +#define SQLITE_IOCAP_ATOMIC2K 0x00000008 +#define SQLITE_IOCAP_ATOMIC4K 0x00000010 +#define SQLITE_IOCAP_ATOMIC8K 0x00000020 +#define SQLITE_IOCAP_ATOMIC16K 0x00000040 +#define SQLITE_IOCAP_ATOMIC32K 0x00000080 +#define SQLITE_IOCAP_ATOMIC64K 0x00000100 +#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 +#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 +#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 +#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 +#define SQLITE_IOCAP_IMMUTABLE 0x00002000 + +/* +** CAPI3REF: File Locking Levels +** +** SQLite uses one of these integer values as the second +** argument to calls it makes to the xLock() and xUnlock() methods +** of an [sqlite3_io_methods] object. +*/ +#define SQLITE_LOCK_NONE 0 +#define SQLITE_LOCK_SHARED 1 +#define SQLITE_LOCK_RESERVED 2 +#define SQLITE_LOCK_PENDING 3 +#define SQLITE_LOCK_EXCLUSIVE 4 + +/* +** CAPI3REF: Synchronization Type Flags +** +** When SQLite invokes the xSync() method of an +** [sqlite3_io_methods] object it uses a combination of +** these integer values as the second argument. +** +** When the SQLITE_SYNC_DATAONLY flag is used, it means that the +** sync operation only needs to flush data to mass storage. Inode +** information need not be flushed. If the lower four bits of the flag +** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics. +** If the lower four bits equal SQLITE_SYNC_FULL, that means +** to use Mac OS X style fullsync instead of fsync(). +** +** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags +** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL +** settings. The [synchronous pragma] determines when calls to the +** xSync VFS method occur and applies uniformly across all platforms. +** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how +** energetic or rigorous or forceful the sync operations are and +** only make a difference on Mac OSX for the default SQLite code. +** (Third-party VFS implementations might also make the distinction +** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the +** operating systems natively supported by SQLite, only Mac OSX +** cares about the difference.) +*/ +#define SQLITE_SYNC_NORMAL 0x00002 +#define SQLITE_SYNC_FULL 0x00003 +#define SQLITE_SYNC_DATAONLY 0x00010 + +/* +** CAPI3REF: OS Interface Open File Handle +** +** An [sqlite3_file] object represents an open file in the +** [sqlite3_vfs | OS interface layer]. Individual OS interface +** implementations will +** want to subclass this object by appending additional fields +** for their own use. The pMethods entry is a pointer to an +** [sqlite3_io_methods] object that defines methods for performing +** I/O operations on the open file. +*/ +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ +}; + +/* +** CAPI3REF: OS Interface File Virtual Methods Object +** +** Every file opened by the [sqlite3_vfs.xOpen] method populates an +** [sqlite3_file] object (or, more commonly, a subclass of the +** [sqlite3_file] object) with a pointer to an instance of this object. +** This object defines the methods used to perform various operations +** against the open file represented by the [sqlite3_file] object. +** +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element +** to a non-NULL pointer, then the sqlite3_io_methods.xClose method +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element +** to NULL. +** +** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or +** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). +** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] +** flag may be ORed in to indicate that only the data of the file +** and not its inode needs to be synced. +** +** The integer values to xLock() and xUnlock() are one of +**
    +**
  • [SQLITE_LOCK_NONE], +**
  • [SQLITE_LOCK_SHARED], +**
  • [SQLITE_LOCK_RESERVED], +**
  • [SQLITE_LOCK_PENDING], or +**
  • [SQLITE_LOCK_EXCLUSIVE]. +**
+** xLock() increases the lock. xUnlock() decreases the lock. +** The xCheckReservedLock() method checks whether any database connection, +** either in this process or in some other process, is holding a RESERVED, +** PENDING, or EXCLUSIVE lock on the file. It returns true +** if such a lock exists and false otherwise. +** +** The xFileControl() method is a generic interface that allows custom +** VFS implementations to directly control an open file using the +** [sqlite3_file_control()] interface. The second "op" argument is an +** integer opcode. The third argument is a generic pointer intended to +** point to a structure that may contain arguments or space in which to +** write return values. Potential uses for xFileControl() might be +** functions to enable blocking locks with timeouts, to change the +** locking strategy (for example to use dot-file locks), to inquire +** about the status of a lock, or to break stale locks. The SQLite +** core reserves all opcodes less than 100 for its own use. +** A [file control opcodes | list of opcodes] less than 100 is available. +** Applications that define a custom xFileControl method should use opcodes +** greater than 100 to avoid conflicts. VFS implementations should +** return [SQLITE_NOTFOUND] for file control opcodes that they do not +** recognize. +** +** The xSectorSize() method returns the sector size of the +** device that underlies the file. The sector size is the +** minimum write that can be performed without disturbing +** other bytes in the file. The xDeviceCharacteristics() +** method returns a bit vector describing behaviors of the +** underlying device: +** +**
    +**
  • [SQLITE_IOCAP_ATOMIC] +**
  • [SQLITE_IOCAP_ATOMIC512] +**
  • [SQLITE_IOCAP_ATOMIC1K] +**
  • [SQLITE_IOCAP_ATOMIC2K] +**
  • [SQLITE_IOCAP_ATOMIC4K] +**
  • [SQLITE_IOCAP_ATOMIC8K] +**
  • [SQLITE_IOCAP_ATOMIC16K] +**
  • [SQLITE_IOCAP_ATOMIC32K] +**
  • [SQLITE_IOCAP_ATOMIC64K] +**
  • [SQLITE_IOCAP_SAFE_APPEND] +**
  • [SQLITE_IOCAP_SEQUENTIAL] +**
+** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). +** +** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill +** in the unread portions of the buffer with zeros. A VFS that +** fails to zero-fill short reads might seem to work. However, +** failure to zero-fill short reads will eventually lead to +** database corruption. +*/ +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Methods above are valid for version 1 */ + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); + /* Methods above are valid for version 2 */ + int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); + int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); + /* Methods above are valid for version 3 */ + /* Additional methods may be added in future releases */ +}; + +/* +** CAPI3REF: Standard File Control Opcodes +** KEYWORDS: {file control opcodes} {file control opcode} +** +** These integer constants are opcodes for the xFileControl method +** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] +** interface. +** +**
    +**
  • [[SQLITE_FCNTL_LOCKSTATE]] +** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This +** opcode causes the xFileControl method to write the current state of +** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], +** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) +** into an integer that the pArg argument points to. This capability +** is used during testing and is only available when the SQLITE_TEST +** compile-time option is used. +** +**
  • [[SQLITE_FCNTL_SIZE_HINT]] +** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS +** layer a hint of how large the database file will grow to be during the +** current transaction. This hint is not guaranteed to be accurate but it +** is often close. The underlying VFS might choose to preallocate database +** file space based on this hint in order to help writes to the database +** file run faster. +** +**
  • [[SQLITE_FCNTL_CHUNK_SIZE]] +** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS +** extends and truncates the database file in chunks of a size specified +** by the user. The fourth argument to [sqlite3_file_control()] should +** point to an integer (type int) containing the new chunk-size to use +** for the nominated database. Allocating database file space in large +** chunks (say 1MB at a time), may reduce file-system fragmentation and +** improve performance on some systems. +** +**
  • [[SQLITE_FCNTL_FILE_POINTER]] +** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer +** to the [sqlite3_file] object associated with a particular database +** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER]. +** +**
  • [[SQLITE_FCNTL_JOURNAL_POINTER]] +** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer +** to the [sqlite3_file] object associated with the journal file (either +** the [rollback journal] or the [write-ahead log]) for a particular database +** connection. See also [SQLITE_FCNTL_FILE_POINTER]. +** +**
  • [[SQLITE_FCNTL_SYNC_OMITTED]] +** No longer in use. +** +**
  • [[SQLITE_FCNTL_SYNC]] +** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and +** sent to the VFS immediately before the xSync method is invoked on a +** database file descriptor. Or, if the xSync method is not invoked +** because the user has configured SQLite with +** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place +** of the xSync method. In most cases, the pointer argument passed with +** this file-control is NULL. However, if the database file is being synced +** as part of a multi-database commit, the argument points to a nul-terminated +** string containing the transactions master-journal file name. VFSes that +** do not need this signal should silently ignore this opcode. Applications +** should not call [sqlite3_file_control()] with this opcode as doing so may +** disrupt the operation of the specialized VFSes that do require it. +** +**
  • [[SQLITE_FCNTL_COMMIT_PHASETWO]] +** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite +** and sent to the VFS after a transaction has been committed immediately +** but before the database is unlocked. VFSes that do not need this signal +** should silently ignore this opcode. Applications should not call +** [sqlite3_file_control()] with this opcode as doing so may disrupt the +** operation of the specialized VFSes that do require it. +** +**
  • [[SQLITE_FCNTL_WIN32_AV_RETRY]] +** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic +** retry counts and intervals for certain disk I/O operations for the +** windows [VFS] in order to provide robustness in the presence of +** anti-virus programs. By default, the windows VFS will retry file read, +** file write, and file delete operations up to 10 times, with a delay +** of 25 milliseconds before the first retry and with the delay increasing +** by an additional 25 milliseconds with each subsequent retry. This +** opcode allows these two values (10 retries and 25 milliseconds of delay) +** to be adjusted. The values are changed for all database connections +** within the same process. The argument is a pointer to an array of two +** integers where the first integer i the new retry count and the second +** integer is the delay. If either integer is negative, then the setting +** is not changed but instead the prior value of that setting is written +** into the array entry, allowing the current retry settings to be +** interrogated. The zDbName parameter is ignored. +** +**
  • [[SQLITE_FCNTL_PERSIST_WAL]] +** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the +** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary +** write ahead log and shared memory files used for transaction control +** are automatically deleted when the latest connection to the database +** closes. Setting persistent WAL mode causes those files to persist after +** close. Persisting the files is useful when other processes that do not +** have write permission on the directory containing the database file want +** to read the database file, as the WAL and shared memory files must exist +** in order for the database to be readable. The fourth parameter to +** [sqlite3_file_control()] for this opcode should be a pointer to an integer. +** That integer is 0 to disable persistent WAL mode or 1 to enable persistent +** WAL mode. If the integer is -1, then it is overwritten with the current +** WAL persistence setting. +** +**
  • [[SQLITE_FCNTL_POWERSAFE_OVERWRITE]] +** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the +** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting +** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the +** xDeviceCharacteristics methods. The fourth parameter to +** [sqlite3_file_control()] for this opcode should be a pointer to an integer. +** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage +** mode. If the integer is -1, then it is overwritten with the current +** zero-damage mode setting. +** +**
  • [[SQLITE_FCNTL_OVERWRITE]] +** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening +** a write transaction to indicate that, unless it is rolled back for some +** reason, the entire database file will be overwritten by the current +** transaction. This is used by VACUUM operations. +** +**
  • [[SQLITE_FCNTL_VFSNAME]] +** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of +** all [VFSes] in the VFS stack. The names are of all VFS shims and the +** final bottom-level VFS are written into memory obtained from +** [sqlite3_malloc()] and the result is stored in the char* variable +** that the fourth parameter of [sqlite3_file_control()] points to. +** The caller is responsible for freeing the memory when done. As with +** all file-control actions, there is no guarantee that this will actually +** do anything. Callers should initialize the char* variable to a NULL +** pointer in case this file-control is not implemented. This file-control +** is intended for diagnostic use only. +** +**
  • [[SQLITE_FCNTL_VFS_POINTER]] +** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level +** [VFSes] currently in use. ^(The argument X in +** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be +** of type "[sqlite3_vfs] **". This opcodes will set *X +** to a pointer to the top-level VFS.)^ +** ^When there are multiple VFS shims in the stack, this opcode finds the +** upper-most shim only. +** +**
  • [[SQLITE_FCNTL_PRAGMA]] +** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] +** file control is sent to the open [sqlite3_file] object corresponding +** to the database file to which the pragma statement refers. ^The argument +** to the [SQLITE_FCNTL_PRAGMA] file control is an array of +** pointers to strings (char**) in which the second element of the array +** is the name of the pragma and the third element is the argument to the +** pragma or NULL if the pragma has no argument. ^The handler for an +** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element +** of the char** argument point to a string obtained from [sqlite3_mprintf()] +** or the equivalent and that string will become the result of the pragma or +** the error message if the pragma fails. ^If the +** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal +** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] +** file control returns [SQLITE_OK], then the parser assumes that the +** VFS has handled the PRAGMA itself and the parser generates a no-op +** prepared statement if result string is NULL, or that returns a copy +** of the result string if the string is non-NULL. +** ^If the [SQLITE_FCNTL_PRAGMA] file control returns +** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means +** that the VFS encountered an error while handling the [PRAGMA] and the +** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] +** file control occurs at the beginning of pragma statement analysis and so +** it is able to override built-in [PRAGMA] statements. +** +**
  • [[SQLITE_FCNTL_BUSYHANDLER]] +** ^The [SQLITE_FCNTL_BUSYHANDLER] +** file-control may be invoked by SQLite on the database file handle +** shortly after it is opened in order to provide a custom VFS with access +** to the connections busy-handler callback. The argument is of type (void **) +** - an array of two (void *) values. The first (void *) actually points +** to a function of type (int (*)(void *)). In order to invoke the connections +** busy-handler, this function should be invoked with the second (void *) in +** the array as the only argument. If it returns non-zero, then the operation +** should be retried. If it returns zero, the custom VFS should abandon the +** current operation. +** +**
  • [[SQLITE_FCNTL_TEMPFILENAME]] +** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control +** to have SQLite generate a +** temporary filename using the same algorithm that is followed to generate +** temporary filenames for TEMP tables and other internal uses. The +** argument should be a char** which will be filled with the filename +** written into memory obtained from [sqlite3_malloc()]. The caller should +** invoke [sqlite3_free()] on the result to avoid a memory leak. +** +**
  • [[SQLITE_FCNTL_MMAP_SIZE]] +** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the +** maximum number of bytes that will be used for memory-mapped I/O. +** The argument is a pointer to a value of type sqlite3_int64 that +** is an advisory maximum number of bytes in the file to memory map. The +** pointer is overwritten with the old value. The limit is not changed if +** the value originally pointed to is negative, and so the current limit +** can be queried by passing in a pointer to a negative number. This +** file-control is used internally to implement [PRAGMA mmap_size]. +** +**
  • [[SQLITE_FCNTL_TRACE]] +** The [SQLITE_FCNTL_TRACE] file control provides advisory information +** to the VFS about what the higher layers of the SQLite stack are doing. +** This file control is used by some VFS activity tracing [shims]. +** The argument is a zero-terminated string. Higher layers in the +** SQLite stack may generate instances of this file control if +** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled. +** +**
  • [[SQLITE_FCNTL_HAS_MOVED]] +** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a +** pointer to an integer and it writes a boolean into that integer depending +** on whether or not the file has been renamed, moved, or deleted since it +** was first opened. +** +**
  • [[SQLITE_FCNTL_WIN32_GET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the +** underlying native file handle associated with a file handle. This file +** control interprets its argument as a pointer to a native file handle and +** writes the resulting value there. +** +**
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This +** opcode causes the xFileControl method to swap the file handle with the one +** pointed to by the pArg argument. This capability is used during testing +** and only needs to be supported when SQLITE_TEST is defined. +** +**
  • [[SQLITE_FCNTL_WAL_BLOCK]] +** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might +** be advantageous to block on the next WAL lock if the lock is not immediately +** available. The WAL subsystem issues this signal during rare +** circumstances in order to fix a problem with priority inversion. +** Applications should not use this file-control. +** +**
  • [[SQLITE_FCNTL_ZIPVFS]] +** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other +** VFS should return SQLITE_NOTFOUND for this opcode. +** +**
  • [[SQLITE_FCNTL_RBU]] +** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by +** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for +** this opcode. +**
+*/ +#define SQLITE_FCNTL_LOCKSTATE 1 +#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 +#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 +#define SQLITE_FCNTL_LAST_ERRNO 4 +#define SQLITE_FCNTL_SIZE_HINT 5 +#define SQLITE_FCNTL_CHUNK_SIZE 6 +#define SQLITE_FCNTL_FILE_POINTER 7 +#define SQLITE_FCNTL_SYNC_OMITTED 8 +#define SQLITE_FCNTL_WIN32_AV_RETRY 9 +#define SQLITE_FCNTL_PERSIST_WAL 10 +#define SQLITE_FCNTL_OVERWRITE 11 +#define SQLITE_FCNTL_VFSNAME 12 +#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 +#define SQLITE_FCNTL_PRAGMA 14 +#define SQLITE_FCNTL_BUSYHANDLER 15 +#define SQLITE_FCNTL_TEMPFILENAME 16 +#define SQLITE_FCNTL_MMAP_SIZE 18 +#define SQLITE_FCNTL_TRACE 19 +#define SQLITE_FCNTL_HAS_MOVED 20 +#define SQLITE_FCNTL_SYNC 21 +#define SQLITE_FCNTL_COMMIT_PHASETWO 22 +#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 +#define SQLITE_FCNTL_WAL_BLOCK 24 +#define SQLITE_FCNTL_ZIPVFS 25 +#define SQLITE_FCNTL_RBU 26 +#define SQLITE_FCNTL_VFS_POINTER 27 +#define SQLITE_FCNTL_JOURNAL_POINTER 28 +#define SQLITE_FCNTL_WIN32_GET_HANDLE 29 + +/* deprecated names */ +#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE +#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE +#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO + + +/* +** CAPI3REF: Mutex Handle +** +** The mutex module within SQLite defines [sqlite3_mutex] to be an +** abstract type for a mutex object. The SQLite core never looks +** at the internal representation of an [sqlite3_mutex]. It only +** deals with pointers to the [sqlite3_mutex] object. +** +** Mutexes are created using [sqlite3_mutex_alloc()]. +*/ +typedef struct sqlite3_mutex sqlite3_mutex; + +/* +** CAPI3REF: Loadable Extension Thunk +** +** A pointer to the opaque sqlite3_api_routines structure is passed as +** the third parameter to entry points of [loadable extensions]. This +** structure must be typedefed in order to work around compiler warnings +** on some platforms. +*/ +typedef struct sqlite3_api_routines sqlite3_api_routines; + +/* +** CAPI3REF: OS Interface Object +** +** An instance of the sqlite3_vfs object defines the interface between +** the SQLite core and the underlying operating system. The "vfs" +** in the name of the object stands for "virtual file system". See +** the [VFS | VFS documentation] for further information. +** +** The value of the iVersion field is initially 1 but may be larger in +** future versions of SQLite. Additional fields may be appended to this +** object when the iVersion value is increased. Note that the structure +** of the sqlite3_vfs object changes in the transaction between +** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not +** modified. +** +** The szOsFile field is the size of the subclassed [sqlite3_file] +** structure used by this VFS. mxPathname is the maximum length of +** a pathname in this VFS. +** +** Registered sqlite3_vfs objects are kept on a linked list formed by +** the pNext pointer. The [sqlite3_vfs_register()] +** and [sqlite3_vfs_unregister()] interfaces manage this list +** in a thread-safe way. The [sqlite3_vfs_find()] interface +** searches the list. Neither the application code nor the VFS +** implementation should use the pNext pointer. +** +** The pNext field is the only field in the sqlite3_vfs +** structure that SQLite will ever modify. SQLite will only access +** or modify this field while holding a particular static mutex. +** The application should never modify anything within the sqlite3_vfs +** object once the object has been registered. +** +** The zName field holds the name of the VFS module. The name must +** be unique across all VFS modules. +** +** [[sqlite3_vfs.xOpen]] +** ^SQLite guarantees that the zFilename parameter to xOpen +** is either a NULL pointer or string obtained +** from xFullPathname() with an optional suffix added. +** ^If a suffix is added to the zFilename parameter, it will +** consist of a single "-" character followed by no more than +** 11 alphanumeric and/or "-" characters. +** ^SQLite further guarantees that +** the string will be valid and unchanged until xClose() is +** called. Because of the previous sentence, +** the [sqlite3_file] can safely store a pointer to the +** filename if it needs to remember the filename for some reason. +** If the zFilename parameter to xOpen is a NULL pointer then xOpen +** must invent its own temporary name for the file. ^Whenever the +** xFilename parameter is NULL it will also be the case that the +** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. +** +** The flags argument to xOpen() includes all bits set in +** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] +** or [sqlite3_open16()] is used, then flags includes at least +** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. +** If xOpen() opens a file read-only then it sets *pOutFlags to +** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. +** +** ^(SQLite will also add one of the following flags to the xOpen() +** call, depending on the object being opened: +** +**
    +**
  • [SQLITE_OPEN_MAIN_DB] +**
  • [SQLITE_OPEN_MAIN_JOURNAL] +**
  • [SQLITE_OPEN_TEMP_DB] +**
  • [SQLITE_OPEN_TEMP_JOURNAL] +**
  • [SQLITE_OPEN_TRANSIENT_DB] +**
  • [SQLITE_OPEN_SUBJOURNAL] +**
  • [SQLITE_OPEN_MASTER_JOURNAL] +**
  • [SQLITE_OPEN_WAL] +**
)^ +** +** The file I/O implementation can use the object type flags to +** change the way it deals with files. For example, an application +** that does not care about crash recovery or rollback might make +** the open of a journal file a no-op. Writes to this journal would +** also be no-ops, and any attempt to read the journal would return +** SQLITE_IOERR. Or the implementation might recognize that a database +** file will be doing page-aligned sector reads and writes in a random +** order and set up its I/O subsystem accordingly. +** +** SQLite might also add one of the following flags to the xOpen method: +** +**
    +**
  • [SQLITE_OPEN_DELETEONCLOSE] +**
  • [SQLITE_OPEN_EXCLUSIVE] +**
+** +** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be +** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] +** will be set for TEMP databases and their journals, transient +** databases, and subjournals. +** +** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction +** with the [SQLITE_OPEN_CREATE] flag, which are both directly +** analogous to the O_EXCL and O_CREAT flags of the POSIX open() +** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the +** SQLITE_OPEN_CREATE, is used to indicate that file should always +** be created, and that it is an error if it already exists. +** It is not used to indicate the file should be opened +** for exclusive access. +** +** ^At least szOsFile bytes of memory are allocated by SQLite +** to hold the [sqlite3_file] structure passed as the third +** argument to xOpen. The xOpen method does not have to +** allocate the structure; it should just fill it in. Note that +** the xOpen method must set the sqlite3_file.pMethods to either +** a valid [sqlite3_io_methods] object or to NULL. xOpen must do +** this even if the open fails. SQLite expects that the sqlite3_file.pMethods +** element will be valid after xOpen returns regardless of the success +** or failure of the xOpen call. +** +** [[sqlite3_vfs.xAccess]] +** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] +** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to +** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] +** to test whether a file is at least readable. The file can be a +** directory. +** +** ^SQLite will always allocate at least mxPathname+1 bytes for the +** output buffer xFullPathname. The exact size of the output buffer +** is also passed as a parameter to both methods. If the output buffer +** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is +** handled as a fatal error by SQLite, vfs implementations should endeavor +** to prevent this by setting mxPathname to a sufficiently large value. +** +** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() +** interfaces are not strictly a part of the filesystem, but they are +** included in the VFS structure for completeness. +** The xRandomness() function attempts to return nBytes bytes +** of good-quality randomness into zOut. The return value is +** the actual number of bytes of randomness obtained. +** The xSleep() method causes the calling thread to sleep for at +** least the number of microseconds given. ^The xCurrentTime() +** method returns a Julian Day Number for the current date and time as +** a floating point value. +** ^The xCurrentTimeInt64() method returns, as an integer, the Julian +** Day Number multiplied by 86400000 (the number of milliseconds in +** a 24-hour day). +** ^SQLite will use the xCurrentTimeInt64() method to get the current +** date and time if that method is available (if iVersion is 2 or +** greater and the function pointer is not NULL) and will fall back +** to xCurrentTime() if xCurrentTimeInt64() is unavailable. +** +** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** are not used by the SQLite core. These optional interfaces are provided +** by some VFSes to facilitate testing of the VFS code. By overriding +** system calls with functions under its control, a test program can +** simulate faults and error conditions that would otherwise be difficult +** or impossible to induce. The set of system calls that can be overridden +** varies from one VFS to another, and from one version of the same VFS to the +** next. Applications that use these interfaces must be prepared for any +** or all of these interfaces to be NULL or for their behavior to change +** from one release to the next. Applications must not attempt to access +** any of these methods if the iVersion of the VFS is less than 3. +*/ +typedef struct sqlite3_vfs sqlite3_vfs; +typedef void (*sqlite3_syscall_ptr)(void); +struct sqlite3_vfs { + int iVersion; /* Structure version number (currently 3) */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs *pNext; /* Next registered VFS */ + const char *zName; /* Name of this virtual file system */ + void *pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char *); + /* + ** The methods above are in version 1 of the sqlite_vfs object + ** definition. Those that follow are added in version 2 or later + */ + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + /* + ** The methods above are in versions 1 and 2 of the sqlite_vfs object. + ** Those below are for version 3 and greater. + */ + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + /* + ** The methods above are in versions 1 through 3 of the sqlite_vfs object. + ** New fields may be appended in future versions. The iVersion + ** value will increment whenever this happens. + */ +}; + +/* +** CAPI3REF: Flags for the xAccess VFS method +** +** These integer constants can be used as the third parameter to +** the xAccess method of an [sqlite3_vfs] object. They determine +** what kind of permissions the xAccess method is looking for. +** With SQLITE_ACCESS_EXISTS, the xAccess method +** simply checks whether the file exists. +** With SQLITE_ACCESS_READWRITE, the xAccess method +** checks whether the named directory is both readable and writable +** (in other words, if files can be added, removed, and renamed within +** the directory). +** The SQLITE_ACCESS_READWRITE constant is currently used only by the +** [temp_store_directory pragma], though this could change in a future +** release of SQLite. +** With SQLITE_ACCESS_READ, the xAccess method +** checks whether the file is readable. The SQLITE_ACCESS_READ constant is +** currently unused, though it might be used in a future release of +** SQLite. +*/ +#define SQLITE_ACCESS_EXISTS 0 +#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ +#define SQLITE_ACCESS_READ 2 /* Unused */ + +/* +** CAPI3REF: Flags for the xShmLock VFS method +** +** These integer constants define the various locking operations +** allowed by the xShmLock method of [sqlite3_io_methods]. The +** following are the only legal combinations of flags to the +** xShmLock method: +** +**
    +**
  • SQLITE_SHM_LOCK | SQLITE_SHM_SHARED +**
  • SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE +**
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED +**
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE +**
+** +** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as +** was given on the corresponding lock. +** +** The xShmLock method can transition between unlocked and SHARED or +** between unlocked and EXCLUSIVE. It cannot transition between SHARED +** and EXCLUSIVE. +*/ +#define SQLITE_SHM_UNLOCK 1 +#define SQLITE_SHM_LOCK 2 +#define SQLITE_SHM_SHARED 4 +#define SQLITE_SHM_EXCLUSIVE 8 + +/* +** CAPI3REF: Maximum xShmLock index +** +** The xShmLock method on [sqlite3_io_methods] may use values +** between 0 and this upper bound as its "offset" argument. +** The SQLite core will never attempt to acquire or release a +** lock outside of this range +*/ +#define SQLITE_SHM_NLOCK 8 + + +/* +** CAPI3REF: Initialize The SQLite Library +** +** ^The sqlite3_initialize() routine initializes the +** SQLite library. ^The sqlite3_shutdown() routine +** deallocates any resources that were allocated by sqlite3_initialize(). +** These routines are designed to aid in process initialization and +** shutdown on embedded systems. Workstation applications using +** SQLite normally do not need to invoke either of these routines. +** +** A call to sqlite3_initialize() is an "effective" call if it is +** the first time sqlite3_initialize() is invoked during the lifetime of +** the process, or if it is the first time sqlite3_initialize() is invoked +** following a call to sqlite3_shutdown(). ^(Only an effective call +** of sqlite3_initialize() does any initialization. All other calls +** are harmless no-ops.)^ +** +** A call to sqlite3_shutdown() is an "effective" call if it is the first +** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only +** an effective call to sqlite3_shutdown() does any deinitialization. +** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ +** +** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() +** is not. The sqlite3_shutdown() interface must only be called from a +** single thread. All open [database connections] must be closed and all +** other SQLite resources must be deallocated prior to invoking +** sqlite3_shutdown(). +** +** Among other things, ^sqlite3_initialize() will invoke +** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() +** will invoke sqlite3_os_end(). +** +** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. +** ^If for some reason, sqlite3_initialize() is unable to initialize +** the library (perhaps it is unable to allocate a needed resource such +** as a mutex) it returns an [error code] other than [SQLITE_OK]. +** +** ^The sqlite3_initialize() routine is called internally by many other +** SQLite interfaces so that an application usually does not need to +** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] +** calls sqlite3_initialize() so the SQLite library will be automatically +** initialized when [sqlite3_open()] is called if it has not be initialized +** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] +** compile-time option, then the automatic calls to sqlite3_initialize() +** are omitted and the application must call sqlite3_initialize() directly +** prior to using any other SQLite interface. For maximum portability, +** it is recommended that applications always invoke sqlite3_initialize() +** directly prior to using any other SQLite interface. Future releases +** of SQLite may require this. In other words, the behavior exhibited +** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the +** default behavior in some future release of SQLite. +** +** The sqlite3_os_init() routine does operating-system specific +** initialization of the SQLite library. The sqlite3_os_end() +** routine undoes the effect of sqlite3_os_init(). Typical tasks +** performed by these routines include allocation or deallocation +** of static resources, initialization of global variables, +** setting up a default [sqlite3_vfs] module, or setting up +** a default configuration using [sqlite3_config()]. +** +** The application should never invoke either sqlite3_os_init() +** or sqlite3_os_end() directly. The application should only invoke +** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() +** interface is called automatically by sqlite3_initialize() and +** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate +** implementations for sqlite3_os_init() and sqlite3_os_end() +** are built into SQLite when it is compiled for Unix, Windows, or OS/2. +** When [custom builds | built for other platforms] +** (using the [SQLITE_OS_OTHER=1] compile-time +** option) the application must supply a suitable implementation for +** sqlite3_os_init() and sqlite3_os_end(). An application-supplied +** implementation of sqlite3_os_init() or sqlite3_os_end() +** must return [SQLITE_OK] on success and some other [error code] upon +** failure. +*/ +SQLITE_API int sqlite3_initialize(void); +SQLITE_API int sqlite3_shutdown(void); +SQLITE_API int sqlite3_os_init(void); +SQLITE_API int sqlite3_os_end(void); + +/* +** CAPI3REF: Configuring The SQLite Library +** +** The sqlite3_config() interface is used to make global configuration +** changes to SQLite in order to tune SQLite to the specific needs of +** the application. The default configuration is recommended for most +** applications and so this routine is usually not necessary. It is +** provided to support rare applications with unusual needs. +** +** The sqlite3_config() interface is not threadsafe. The application +** must ensure that no other SQLite interfaces are invoked by other +** threads while sqlite3_config() is running. +** +** The sqlite3_config() interface +** may only be invoked prior to library initialization using +** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. +** ^If sqlite3_config() is called after [sqlite3_initialize()] and before +** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. +** Note, however, that ^sqlite3_config() can be called as part of the +** implementation of an application-defined [sqlite3_os_init()]. +** +** The first argument to sqlite3_config() is an integer +** [configuration option] that determines +** what property of SQLite is to be configured. Subsequent arguments +** vary depending on the [configuration option] +** in the first argument. +** +** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. +** ^If the option is unknown or SQLite is unable to set the option +** then this routine returns a non-zero [error code]. +*/ +SQLITE_API int sqlite3_config(int, ...); + +/* +** CAPI3REF: Configure database connections +** METHOD: sqlite3 +** +** The sqlite3_db_config() interface is used to make configuration +** changes to a [database connection]. The interface is similar to +** [sqlite3_config()] except that the changes apply to a single +** [database connection] (specified in the first argument). +** +** The second argument to sqlite3_db_config(D,V,...) is the +** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code +** that indicates what aspect of the [database connection] is being configured. +** Subsequent arguments vary depending on the configuration verb. +** +** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if +** the call is considered successful. +*/ +SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Memory Allocation Routines +** +** An instance of this object defines the interface between SQLite +** and low-level memory allocation routines. +** +** This object is used in only one place in the SQLite interface. +** A pointer to an instance of this object is the argument to +** [sqlite3_config()] when the configuration option is +** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. +** By creating an instance of this object +** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) +** during configuration, an application can specify an alternative +** memory allocation subsystem for SQLite to use for all of its +** dynamic memory needs. +** +** Note that SQLite comes with several [built-in memory allocators] +** that are perfectly adequate for the overwhelming majority of applications +** and that this object is only useful to a tiny minority of applications +** with specialized memory allocation requirements. This object is +** also used during testing of SQLite in order to specify an alternative +** memory allocator that simulates memory out-of-memory conditions in +** order to verify that SQLite recovers gracefully from such +** conditions. +** +** The xMalloc, xRealloc, and xFree methods must work like the +** malloc(), realloc() and free() functions from the standard C library. +** ^SQLite guarantees that the second argument to +** xRealloc is always a value returned by a prior call to xRoundup. +** +** xSize should return the allocated size of a memory allocation +** previously obtained from xMalloc or xRealloc. The allocated size +** is always at least as big as the requested size but may be larger. +** +** The xRoundup method returns what would be the allocated size of +** a memory allocation given a particular requested size. Most memory +** allocators round up memory allocations at least to the next multiple +** of 8. Some allocators round up to a larger multiple or to a power of 2. +** Every memory allocation request coming in through [sqlite3_malloc()] +** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, +** that causes the corresponding memory allocation to fail. +** +** The xInit method initializes the memory allocator. For example, +** it might allocate any require mutexes or initialize internal data +** structures. The xShutdown method is invoked (indirectly) by +** [sqlite3_shutdown()] and should deallocate any resources acquired +** by xInit. The pAppData pointer is used as the only parameter to +** xInit and xShutdown. +** +** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes +** the xInit method, so the xInit method need not be threadsafe. The +** xShutdown method is only called from [sqlite3_shutdown()] so it does +** not need to be threadsafe either. For all other methods, SQLite +** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the +** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which +** it is by default) and so the methods are automatically serialized. +** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other +** methods must be threadsafe or else make their own arrangements for +** serialization. +** +** SQLite will never invoke xInit() more than once without an intervening +** call to xShutdown(). +*/ +typedef struct sqlite3_mem_methods sqlite3_mem_methods; +struct sqlite3_mem_methods { + void *(*xMalloc)(int); /* Memory allocation function */ + void (*xFree)(void*); /* Free a prior allocation */ + void *(*xRealloc)(void*,int); /* Resize an allocation */ + int (*xSize)(void*); /* Return the size of an allocation */ + int (*xRoundup)(int); /* Round up request size to allocation size */ + int (*xInit)(void*); /* Initialize the memory allocator */ + void (*xShutdown)(void*); /* Deinitialize the memory allocator */ + void *pAppData; /* Argument to xInit() and xShutdown() */ +}; + +/* +** CAPI3REF: Configuration Options +** KEYWORDS: {configuration option} +** +** These constants are the available integer configuration options that +** can be passed as the first argument to the [sqlite3_config()] interface. +** +** New configuration options may be added in future releases of SQLite. +** Existing configuration options might be discontinued. Applications +** should check the return code from [sqlite3_config()] to make sure that +** the call worked. The [sqlite3_config()] interface will return a +** non-zero [error code] if a discontinued or unsupported configuration option +** is invoked. +** +**
+** [[SQLITE_CONFIG_SINGLETHREAD]]
SQLITE_CONFIG_SINGLETHREAD
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Single-thread. In other words, it disables +** all mutexing and puts SQLite into a mode where it can only be used +** by a single thread. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to change the [threading mode] from its default +** value of Single-thread and so [sqlite3_config()] will return +** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD +** configuration option.
+** +** [[SQLITE_CONFIG_MULTITHREAD]]
SQLITE_CONFIG_MULTITHREAD
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Multi-thread. In other words, it disables +** mutexing on [database connection] and [prepared statement] objects. +** The application is responsible for serializing access to +** [database connections] and [prepared statements]. But other mutexes +** are enabled so that SQLite will be safe to use in a multi-threaded +** environment as long as no two threads attempt to use the same +** [database connection] at the same time. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to set the Multi-thread [threading mode] and +** [sqlite3_config()] will return [SQLITE_ERROR] if called with the +** SQLITE_CONFIG_MULTITHREAD configuration option.
+** +** [[SQLITE_CONFIG_SERIALIZED]]
SQLITE_CONFIG_SERIALIZED
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Serialized. In other words, this option enables +** all mutexes including the recursive +** mutexes on [database connection] and [prepared statement] objects. +** In this mode (which is the default when SQLite is compiled with +** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access +** to [database connections] and [prepared statements] so that the +** application is free to use the same [database connection] or the +** same [prepared statement] in different threads at the same time. +** ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to set the Serialized [threading mode] and +** [sqlite3_config()] will return [SQLITE_ERROR] if called with the +** SQLITE_CONFIG_SERIALIZED configuration option.
+** +** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
+**
^(The SQLITE_CONFIG_MALLOC option takes a single argument which is +** a pointer to an instance of the [sqlite3_mem_methods] structure. +** The argument specifies +** alternative low-level memory allocation routines to be used in place of +** the memory allocation routines built into SQLite.)^ ^SQLite makes +** its own private copy of the content of the [sqlite3_mem_methods] structure +** before the [sqlite3_config()] call returns.
+** +** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
+**
^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which +** is a pointer to an instance of the [sqlite3_mem_methods] structure. +** The [sqlite3_mem_methods] +** structure is filled with the currently defined memory allocation routines.)^ +** This option can be used to overload the default memory allocation +** routines with a wrapper that simulations memory allocation failure or +** tracks memory usage, for example.
+** +** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
+**
^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +** interpreted as a boolean, which enables or disables the collection of +** memory allocation statistics. ^(When memory allocation statistics are +** disabled, the following SQLite interfaces become non-operational: +**
    +**
  • [sqlite3_memory_used()] +**
  • [sqlite3_memory_highwater()] +**
  • [sqlite3_soft_heap_limit64()] +**
  • [sqlite3_status64()] +**
)^ +** ^Memory allocation statistics are enabled by default unless SQLite is +** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory +** allocation statistics are disabled by default. +**
+** +** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
+**
^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer +** that SQLite can use for scratch memory. ^(There are three arguments +** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte +** aligned memory buffer from which the scratch allocations will be +** drawn, the size of each scratch allocation (sz), +** and the maximum number of scratch allocations (N).)^ +** The first argument must be a pointer to an 8-byte aligned buffer +** of at least sz*N bytes of memory. +** ^SQLite will not use more than one scratch buffers per thread. +** ^SQLite will never request a scratch buffer that is more than 6 +** times the database page size. +** ^If SQLite needs needs additional +** scratch memory beyond what is provided by this configuration option, then +** [sqlite3_malloc()] will be used to obtain the memory needed.

+** ^When the application provides any amount of scratch memory using +** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large +** [sqlite3_malloc|heap allocations]. +** This can help [Robson proof|prevent memory allocation failures] due to heap +** fragmentation in low-memory embedded systems. +**

+** +** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
+**
^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool +** that SQLite can use for the database page cache with the default page +** cache implementation. +** This configuration option is a no-op if an application-define page +** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. +** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to +** 8-byte aligned memory (pMem), the size of each page cache line (sz), +** and the number of cache lines (N). +** The sz argument should be the size of the largest database page +** (a power of two between 512 and 65536) plus some extra bytes for each +** page header. ^The number of extra bytes needed by the page header +** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ]. +** ^It is harmless, apart from the wasted memory, +** for the sz parameter to be larger than necessary. The pMem +** argument must be either a NULL pointer or a pointer to an 8-byte +** aligned block of memory of at least sz*N bytes, otherwise +** subsequent behavior is undefined. +** ^When pMem is not NULL, SQLite will strive to use the memory provided +** to satisfy page cache needs, falling back to [sqlite3_malloc()] if +** a page cache line is larger than sz bytes or if all of the pMem buffer +** is exhausted. +** ^If pMem is NULL and N is non-zero, then each database connection +** does an initial bulk allocation for page cache memory +** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or +** of -1024*N bytes if N is negative, . ^If additional +** page cache memory is needed beyond what is provided by the initial +** allocation, then SQLite goes to [sqlite3_malloc()] separately for each +** additional cache line.
+** +** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
+**
^The SQLITE_CONFIG_HEAP option specifies a static memory buffer +** that SQLite will use for all of its dynamic memory allocation needs +** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and +** [SQLITE_CONFIG_PAGECACHE]. +** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled +** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns +** [SQLITE_ERROR] if invoked otherwise. +** ^There are three arguments to SQLITE_CONFIG_HEAP: +** An 8-byte aligned pointer to the memory, +** the number of bytes in the memory buffer, and the minimum allocation size. +** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts +** to using its default memory allocator (the system malloc() implementation), +** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the +** memory pointer is not NULL then the alternative memory +** allocator is engaged to handle all of SQLites memory allocation needs. +** The first pointer (the memory pointer) must be aligned to an 8-byte +** boundary or subsequent behavior of SQLite will be undefined. +** The minimum allocation size is capped at 2**12. Reasonable values +** for the minimum allocation size are 2**5 through 2**8.
+** +** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
+**
^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a +** pointer to an instance of the [sqlite3_mutex_methods] structure. +** The argument specifies alternative low-level mutex routines to be used +** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of +** the content of the [sqlite3_mutex_methods] structure before the call to +** [sqlite3_config()] returns. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** the entire mutexing subsystem is omitted from the build and hence calls to +** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will +** return [SQLITE_ERROR].
+** +** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
+**
^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which +** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The +** [sqlite3_mutex_methods] +** structure is filled with the currently defined mutex routines.)^ +** This option can be used to overload the default mutex allocation +** routines with a wrapper used to track mutex usage for performance +** profiling or testing, for example. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** the entire mutexing subsystem is omitted from the build and hence calls to +** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will +** return [SQLITE_ERROR].
+** +** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
+**
^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine +** the default size of lookaside memory on each [database connection]. +** The first argument is the +** size of each lookaside buffer slot and the second is the number of +** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE +** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] +** option to [sqlite3_db_config()] can be used to change the lookaside +** configuration on individual connections.)^
+** +** [[SQLITE_CONFIG_PCACHE2]]
SQLITE_CONFIG_PCACHE2
+**
^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is +** a pointer to an [sqlite3_pcache_methods2] object. This object specifies +** the interface to a custom page cache implementation.)^ +** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
+** +** [[SQLITE_CONFIG_GETPCACHE2]]
SQLITE_CONFIG_GETPCACHE2
+**
^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of +** the current page cache implementation into that object.)^
+** +** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
+**
The SQLITE_CONFIG_LOG option is used to configure the SQLite +** global [error log]. +** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a +** function with a call signature of void(*)(void*,int,const char*), +** and a pointer to void. ^If the function pointer is not NULL, it is +** invoked by [sqlite3_log()] to process each logging event. ^If the +** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. +** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is +** passed through as the first parameter to the application-defined logger +** function whenever that function is invoked. ^The second parameter to +** the logger function is a copy of the first parameter to the corresponding +** [sqlite3_log()] call and is intended to be a [result code] or an +** [extended result code]. ^The third parameter passed to the logger is +** log message after formatting via [sqlite3_snprintf()]. +** The SQLite logging interface is not reentrant; the logger function +** supplied by the application must not invoke any SQLite interface. +** In a multi-threaded application, the application-defined logger +** function must be threadsafe.
+** +** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI +**
^(The SQLITE_CONFIG_URI option takes a single argument of type int. +** If non-zero, then URI handling is globally enabled. If the parameter is zero, +** then URI handling is globally disabled.)^ ^If URI handling is globally +** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], +** [sqlite3_open16()] or +** specified as part of [ATTACH] commands are interpreted as URIs, regardless +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database +** connection is opened. ^If it is globally disabled, filenames are +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the +** database connection is opened. ^(By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** [SQLITE_USE_URI] symbol defined.)^ +** +** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
SQLITE_CONFIG_COVERING_INDEX_SCAN +**
^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer +** argument which is interpreted as a boolean in order to enable or disable +** the use of covering indices for full table scans in the query optimizer. +** ^The default setting is determined +** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" +** if that compile-time option is omitted. +** The ability to disable the use of covering indices for full table scans +** is because some incorrectly coded legacy applications might malfunction +** when the optimization is enabled. Providing the ability to +** disable the optimization allows the older, buggy application code to work +** without change even with newer versions of SQLite. +** +** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] +**
SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE +**
These options are obsolete and should not be used by new code. +** They are retained for backwards compatibility but are now no-ops. +**
+** +** [[SQLITE_CONFIG_SQLLOG]] +**
SQLITE_CONFIG_SQLLOG +**
This option is only available if sqlite is compiled with the +** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should +** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). +** The second should be of type (void*). The callback is invoked by the library +** in three separate circumstances, identified by the value passed as the +** fourth parameter. If the fourth parameter is 0, then the database connection +** passed as the second argument has just been opened. The third argument +** points to a buffer containing the name of the main database file. If the +** fourth parameter is 1, then the SQL statement that the third parameter +** points to has just been executed. Or, if the fourth parameter is 2, then +** the connection being passed as the second parameter is being closed. The +** third parameter is passed NULL In this case. An example of using this +** configuration option can be seen in the "test_sqllog.c" source file in +** the canonical SQLite source tree.
+** +** [[SQLITE_CONFIG_MMAP_SIZE]] +**
SQLITE_CONFIG_MMAP_SIZE +**
^SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values +** that are the default mmap size limit (the default setting for +** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. +** ^The default setting can be overridden by each database connection using +** either the [PRAGMA mmap_size] command, or by using the +** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size +** will be silently truncated if necessary so that it does not exceed the +** compile-time maximum mmap size set by the +** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ +** ^If either argument to this option is negative, then that argument is +** changed to its compile-time default. +** +** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] +**
SQLITE_CONFIG_WIN32_HEAPSIZE +**
^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is +** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro +** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value +** that specifies the maximum size of the created heap. +** +** [[SQLITE_CONFIG_PCACHE_HDRSZ]] +**
SQLITE_CONFIG_PCACHE_HDRSZ +**
^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which +** is a pointer to an integer and writes into that integer the number of extra +** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. +** The amount of extra space required can change depending on the compiler, +** target platform, and SQLite version. +** +** [[SQLITE_CONFIG_PMASZ]] +**
SQLITE_CONFIG_PMASZ +**
^The SQLITE_CONFIG_PMASZ option takes a single parameter which +** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded +** sorter to that integer. The default minimum PMA Size is set by the +** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched +** to help with sort operations when multithreaded sorting +** is enabled (using the [PRAGMA threads] command) and the amount of content +** to be sorted exceeds the page size times the minimum of the +** [PRAGMA cache_size] setting and this value. +** +** [[SQLITE_CONFIG_STMTJRNL_SPILL]] +**
SQLITE_CONFIG_STMTJRNL_SPILL +**
^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which +** becomes the [statement journal] spill-to-disk threshold. +** [Statement journals] are held in memory until their size (in bytes) +** exceeds this threshold, at which point they are written to disk. +** Or if the threshold is -1, statement journals are always held +** exclusively in memory. +** Since many statement journals never become large, setting the spill +** threshold to a value such as 64KiB can greatly reduce the amount of +** I/O required to support statement rollback. +** The default value for this setting is controlled by the +** [SQLITE_STMTJRNL_SPILL] compile-time option. +**
+*/ +#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ +#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ +#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ +#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ +#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ +#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ +#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ +#define SQLITE_CONFIG_PCACHE 14 /* no-op */ +#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ +#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ +#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ +#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ +#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ +#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ +#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ +#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ +#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ + +/* +** CAPI3REF: Database Connection Configuration Options +** +** These constants are the available integer configuration options that +** can be passed as the second argument to the [sqlite3_db_config()] interface. +** +** New configuration options may be added in future releases of SQLite. +** Existing configuration options might be discontinued. Applications +** should check the return code from [sqlite3_db_config()] to make sure that +** the call worked. ^The [sqlite3_db_config()] interface will return a +** non-zero [error code] if a discontinued or unsupported configuration option +** is invoked. +** +**
+**
SQLITE_DBCONFIG_LOOKASIDE
+**
^This option takes three additional arguments that determine the +** [lookaside memory allocator] configuration for the [database connection]. +** ^The first argument (the third parameter to [sqlite3_db_config()] is a +** pointer to a memory buffer to use for lookaside memory. +** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb +** may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the +** size of each lookaside buffer slot. ^The third argument is the number of +** slots. The size of the buffer in the first argument must be greater than +** or equal to the product of the second and third arguments. The buffer +** must be aligned to an 8-byte boundary. ^If the second argument to +** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally +** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** configuration for a database connection can only be changed when that +** connection is not currently using lookaside memory, or in other words +** when the "current value" returned by +** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. +** Any attempt to change the lookaside memory configuration when lookaside +** memory is in use leaves the configuration unchanged and returns +** [SQLITE_BUSY].)^
+** +**
SQLITE_DBCONFIG_ENABLE_FKEY
+**
^This option is used to enable or disable the enforcement of +** [foreign key constraints]. There should be two additional arguments. +** The first argument is an integer which is 0 to disable FK enforcement, +** positive to enable FK enforcement or negative to leave FK enforcement +** unchanged. The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether FK enforcement is off or on +** following this call. The second parameter may be a NULL pointer, in +** which case the FK enforcement setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_TRIGGER
+**
^This option is used to enable or disable [CREATE TRIGGER | triggers]. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable triggers, +** positive to enable triggers or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether triggers are disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the trigger setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
+**
^This option is used to enable or disable the two-argument +** version of the [fts3_tokenizer()] function which is part of the +** [FTS3] full-text search engine extension. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable fts3_tokenizer() or +** positive to enable fts3_tokenizer() or negative to leave the setting +** unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the new setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
+**
^This option is used to enable or disable the [sqlite3_load_extension()] +** interface independently of the [load_extension()] SQL function. +** The [sqlite3_enable_load_extension()] API enables or disables both the +** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. +** There should be two additional arguments. +** When the first argument to this interface is 1, then only the C-API is +** enabled and the SQL function remains disabled. If the first argument to +** this interface is 0, then both the C-API and the SQL function are disabled. +** If the first argument is -1, then no changes are made to state of either the +** C-API or the SQL function. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface +** is disabled or enabled following this call. The second parameter may +** be a NULL pointer, in which case the new setting is not reported back. +**
+** +**
SQLITE_DBCONFIG_MAINDBNAME
+**
^This option is used to change the name of the "main" database +** schema. ^The sole argument is a pointer to a constant UTF8 string +** which will become the new schema name in place of "main". ^SQLite +** does not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into this DBCONFIG option is unchanged +** until after the database connection closes. +**
+** +**
+*/ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ + + +/* +** CAPI3REF: Enable Or Disable Extended Result Codes +** METHOD: sqlite3 +** +** ^The sqlite3_extended_result_codes() routine enables or disables the +** [extended result codes] feature of SQLite. ^The extended result +** codes are disabled by default for historical compatibility. +*/ +SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); + +/* +** CAPI3REF: Last Insert Rowid +** METHOD: sqlite3 +** +** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) +** has a unique 64-bit signed +** integer key called the [ROWID | "rowid"]. ^The rowid is always available +** as an undeclared column named ROWID, OID, or _ROWID_ as long as those +** names are not also used by explicitly declared columns. ^If +** the table has a column of type [INTEGER PRIMARY KEY] then that column +** is another alias for the rowid. +** +** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the +** most recent successful [INSERT] into a rowid table or [virtual table] +** on database connection D. +** ^Inserts into [WITHOUT ROWID] tables are not recorded. +** ^If no successful [INSERT]s into rowid tables +** have ever occurred on the database connection D, +** then sqlite3_last_insert_rowid(D) returns zero. +** +** ^(If an [INSERT] occurs within a trigger or within a [virtual table] +** method, then this routine will return the [rowid] of the inserted +** row as long as the trigger or virtual table method is running. +** But once the trigger or virtual table method ends, the value returned +** by this routine reverts to what it was before the trigger or virtual +** table method began.)^ +** +** ^An [INSERT] that fails due to a constraint violation is not a +** successful [INSERT] and does not change the value returned by this +** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, +** and INSERT OR ABORT make no changes to the return value of this +** routine when their insertion fails. ^(When INSERT OR REPLACE +** encounters a constraint violation, it does not fail. The +** INSERT continues to completion after deleting rows that caused +** the constraint problem so INSERT OR REPLACE will always change +** the return value of this interface.)^ +** +** ^For the purposes of this routine, an [INSERT] is considered to +** be successful even if it is subsequently rolled back. +** +** This function is accessible to SQL statements via the +** [last_insert_rowid() SQL function]. +** +** If a separate thread performs a new [INSERT] on the same +** database connection while the [sqlite3_last_insert_rowid()] +** function is running and thus changes the last insert [rowid], +** then the value returned by [sqlite3_last_insert_rowid()] is +** unpredictable and might not equal either the old or the new +** last insert [rowid]. +*/ +SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + +/* +** CAPI3REF: Count The Number Of Rows Modified +** METHOD: sqlite3 +** +** ^This function returns the number of rows modified, inserted or +** deleted by the most recently completed INSERT, UPDATE or DELETE +** statement on the database connection specified by the only parameter. +** ^Executing any other type of SQL statement does not modify the value +** returned by this function. +** +** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are +** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], +** [foreign key actions] or [REPLACE] constraint resolution are not counted. +** +** Changes to a view that are intercepted by +** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value +** returned by sqlite3_changes() immediately after an INSERT, UPDATE or +** DELETE statement run on a view is always zero. Only changes made to real +** tables are counted. +** +** Things are more complicated if the sqlite3_changes() function is +** executed while a trigger program is running. This may happen if the +** program uses the [changes() SQL function], or if some other callback +** function invokes sqlite3_changes() directly. Essentially: +** +**
    +**
  • ^(Before entering a trigger program the value returned by +** sqlite3_changes() function is saved. After the trigger program +** has finished, the original value is restored.)^ +** +**
  • ^(Within a trigger program each INSERT, UPDATE and DELETE +** statement sets the value returned by sqlite3_changes() +** upon completion as normal. Of course, this value will not include +** any changes performed by sub-triggers, as the sqlite3_changes() +** value will be saved and restored after each sub-trigger has run.)^ +**
+** +** ^This means that if the changes() SQL function (or similar) is used +** by the first INSERT, UPDATE or DELETE statement within a trigger, it +** returns the value as set when the calling statement began executing. +** ^If it is used by the second or subsequent such statement within a trigger +** program, the value returned reflects the number of rows modified by the +** previous INSERT, UPDATE or DELETE statement within the same trigger. +** +** See also the [sqlite3_total_changes()] interface, the +** [count_changes pragma], and the [changes() SQL function]. +** +** If a separate thread makes changes on the same database connection +** while [sqlite3_changes()] is running then the value returned +** is unpredictable and not meaningful. +*/ +SQLITE_API int sqlite3_changes(sqlite3*); + +/* +** CAPI3REF: Total Number Of Rows Modified +** METHOD: sqlite3 +** +** ^This function returns the total number of rows inserted, modified or +** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed +** since the database connection was opened, including those executed as +** part of trigger programs. ^Executing any other type of SQL statement +** does not affect the value returned by sqlite3_total_changes(). +** +** ^Changes made as part of [foreign key actions] are included in the +** count, but those made as part of REPLACE constraint resolution are +** not. ^Changes to a view that are intercepted by INSTEAD OF triggers +** are not counted. +** +** See also the [sqlite3_changes()] interface, the +** [count_changes pragma], and the [total_changes() SQL function]. +** +** If a separate thread makes changes on the same database connection +** while [sqlite3_total_changes()] is running then the value +** returned is unpredictable and not meaningful. +*/ +SQLITE_API int sqlite3_total_changes(sqlite3*); + +/* +** CAPI3REF: Interrupt A Long-Running Query +** METHOD: sqlite3 +** +** ^This function causes any pending database operation to abort and +** return at its earliest opportunity. This routine is typically +** called in response to a user action such as pressing "Cancel" +** or Ctrl-C where the user wants a long query operation to halt +** immediately. +** +** ^It is safe to call this routine from a thread different from the +** thread that is currently running the database operation. But it +** is not safe to call this routine with a [database connection] that +** is closed or might close before sqlite3_interrupt() returns. +** +** ^If an SQL operation is very nearly finished at the time when +** sqlite3_interrupt() is called, then it might not have an opportunity +** to be interrupted and might continue to completion. +** +** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. +** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE +** that is inside an explicit transaction, then the entire transaction +** will be rolled back automatically. +** +** ^The sqlite3_interrupt(D) call is in effect until all currently running +** SQL statements on [database connection] D complete. ^Any new SQL statements +** that are started after the sqlite3_interrupt() call and before the +** running statements reaches zero are interrupted as if they had been +** running prior to the sqlite3_interrupt() call. ^New SQL statements +** that are started after the running statement count reaches zero are +** not effected by the sqlite3_interrupt(). +** ^A call to sqlite3_interrupt(D) that occurs when there are no running +** SQL statements is a no-op and has no effect on SQL statements +** that are started after the sqlite3_interrupt() call returns. +** +** If the database connection closes while [sqlite3_interrupt()] +** is running then bad things will likely happen. +*/ +SQLITE_API void sqlite3_interrupt(sqlite3*); + +/* +** CAPI3REF: Determine If An SQL Statement Is Complete +** +** These routines are useful during command-line input to determine if the +** currently entered text seems to form a complete SQL statement or +** if additional input is needed before sending the text into +** SQLite for parsing. ^These routines return 1 if the input string +** appears to be a complete SQL statement. ^A statement is judged to be +** complete if it ends with a semicolon token and is not a prefix of a +** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within +** string literals or quoted identifier names or comments are not +** independent tokens (they are part of the token in which they are +** embedded) and thus do not count as a statement terminator. ^Whitespace +** and comments that follow the final semicolon are ignored. +** +** ^These routines return 0 if the statement is incomplete. ^If a +** memory allocation fails, then SQLITE_NOMEM is returned. +** +** ^These routines do not parse the SQL statements thus +** will not detect syntactically incorrect SQL. +** +** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior +** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked +** automatically by sqlite3_complete16(). If that initialization fails, +** then the return value from sqlite3_complete16() will be non-zero +** regardless of whether or not the input SQL is complete.)^ +** +** The input to [sqlite3_complete()] must be a zero-terminated +** UTF-8 string. +** +** The input to [sqlite3_complete16()] must be a zero-terminated +** UTF-16 string in native byte order. +*/ +SQLITE_API int sqlite3_complete(const char *sql); +SQLITE_API int sqlite3_complete16(const void *sql); + +/* +** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors +** KEYWORDS: {busy-handler callback} {busy handler} +** METHOD: sqlite3 +** +** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X +** that might be invoked with argument P whenever +** an attempt is made to access a database table associated with +** [database connection] D when another thread +** or process has the table locked. +** The sqlite3_busy_handler() interface is used to implement +** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. +** +** ^If the busy callback is NULL, then [SQLITE_BUSY] +** is returned immediately upon encountering the lock. ^If the busy callback +** is not NULL, then the callback might be invoked with two arguments. +** +** ^The first argument to the busy handler is a copy of the void* pointer which +** is the third argument to sqlite3_busy_handler(). ^The second argument to +** the busy handler callback is the number of times that the busy handler has +** been invoked previously for the same locking event. ^If the +** busy callback returns 0, then no additional attempts are made to +** access the database and [SQLITE_BUSY] is returned +** to the application. +** ^If the callback returns non-zero, then another attempt +** is made to access the database and the cycle repeats. +** +** The presence of a busy handler does not guarantee that it will be invoked +** when there is lock contention. ^If SQLite determines that invoking the busy +** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] +** to the application instead of invoking the +** busy handler. +** Consider a scenario where one process is holding a read lock that +** it is trying to promote to a reserved lock and +** a second process is holding a reserved lock that it is trying +** to promote to an exclusive lock. The first process cannot proceed +** because it is blocked by the second and the second process cannot +** proceed because it is blocked by the first. If both processes +** invoke the busy handlers, neither will make any progress. Therefore, +** SQLite returns [SQLITE_BUSY] for the first process, hoping that this +** will induce the first process to release its read lock and allow +** the second process to proceed. +** +** ^The default busy callback is NULL. +** +** ^(There can only be a single busy handler defined for each +** [database connection]. Setting a new busy handler clears any +** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] +** or evaluating [PRAGMA busy_timeout=N] will change the +** busy handler and thus clear any previously set busy handler. +** +** The busy callback should not take any actions which modify the +** database connection that invoked the busy handler. In other words, +** the busy handler is not reentrant. Any such actions +** result in undefined behavior. +** +** A busy handler must not close the database connection +** or [prepared statement] that invoked the busy handler. +*/ +SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); + +/* +** CAPI3REF: Set A Busy Timeout +** METHOD: sqlite3 +** +** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps +** for a specified amount of time when a table is locked. ^The handler +** will sleep multiple times until at least "ms" milliseconds of sleeping +** have accumulated. ^After at least "ms" milliseconds of sleeping, +** the handler returns 0 which causes [sqlite3_step()] to return +** [SQLITE_BUSY]. +** +** ^Calling this routine with an argument less than or equal to zero +** turns off all busy handlers. +** +** ^(There can only be a single busy handler for a particular +** [database connection] at any given moment. If another busy handler +** was defined (using [sqlite3_busy_handler()]) prior to calling +** this routine, that other busy handler is cleared.)^ +** +** See also: [PRAGMA busy_timeout] +*/ +SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); + +/* +** CAPI3REF: Convenience Routines For Running Queries +** METHOD: sqlite3 +** +** This is a legacy interface that is preserved for backwards compatibility. +** Use of this interface is not recommended. +** +** Definition: A result table is memory data structure created by the +** [sqlite3_get_table()] interface. A result table records the +** complete query results from one or more queries. +** +** The table conceptually has a number of rows and columns. But +** these numbers are not part of the result table itself. These +** numbers are obtained separately. Let N be the number of rows +** and M be the number of columns. +** +** A result table is an array of pointers to zero-terminated UTF-8 strings. +** There are (N+1)*M elements in the array. The first M pointers point +** to zero-terminated strings that contain the names of the columns. +** The remaining entries all point to query results. NULL values result +** in NULL pointers. All other values are in their UTF-8 zero-terminated +** string representation as returned by [sqlite3_column_text()]. +** +** A result table might consist of one or more memory allocations. +** It is not safe to pass a result table directly to [sqlite3_free()]. +** A result table should be deallocated using [sqlite3_free_table()]. +** +** ^(As an example of the result table format, suppose a query result +** is as follows: +** +**
+**        Name        | Age
+**        -----------------------
+**        Alice       | 43
+**        Bob         | 28
+**        Cindy       | 21
+** 
+** +** There are two column (M==2) and three rows (N==3). Thus the +** result table has 8 entries. Suppose the result table is stored +** in an array names azResult. Then azResult holds this content: +** +**
+**        azResult[0] = "Name";
+**        azResult[1] = "Age";
+**        azResult[2] = "Alice";
+**        azResult[3] = "43";
+**        azResult[4] = "Bob";
+**        azResult[5] = "28";
+**        azResult[6] = "Cindy";
+**        azResult[7] = "21";
+** 
)^ +** +** ^The sqlite3_get_table() function evaluates one or more +** semicolon-separated SQL statements in the zero-terminated UTF-8 +** string of its 2nd parameter and returns a result table to the +** pointer given in its 3rd parameter. +** +** After the application has finished with the result from sqlite3_get_table(), +** it must pass the result table pointer to sqlite3_free_table() in order to +** release the memory that was malloced. Because of the way the +** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling +** function must not try to call [sqlite3_free()] directly. Only +** [sqlite3_free_table()] is able to release the memory properly and safely. +** +** The sqlite3_get_table() interface is implemented as a wrapper around +** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access +** to any internal data structures of SQLite. It uses only the public +** interface defined here. As a consequence, errors that occur in the +** wrapper layer outside of the internal [sqlite3_exec()] call are not +** reflected in subsequent calls to [sqlite3_errcode()] or +** [sqlite3_errmsg()]. +*/ +SQLITE_API int sqlite3_get_table( + sqlite3 *db, /* An open database */ + const char *zSql, /* SQL to be evaluated */ + char ***pazResult, /* Results of the query */ + int *pnRow, /* Number of result rows written here */ + int *pnColumn, /* Number of result columns written here */ + char **pzErrmsg /* Error msg written here */ +); +SQLITE_API void sqlite3_free_table(char **result); + +/* +** CAPI3REF: Formatted String Printing Functions +** +** These routines are work-alikes of the "printf()" family of functions +** from the standard C library. +** These routines understand most of the common K&R formatting options, +** plus some additional non-standard formats, detailed below. +** Note that some of the more obscure formatting options from recent +** C-library standards are omitted from this implementation. +** +** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their +** results into memory obtained from [sqlite3_malloc()]. +** The strings returned by these two routines should be +** released by [sqlite3_free()]. ^Both routines return a +** NULL pointer if [sqlite3_malloc()] is unable to allocate enough +** memory to hold the resulting string. +** +** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from +** the standard C library. The result is written into the +** buffer supplied as the second parameter whose size is given by +** the first parameter. Note that the order of the +** first two parameters is reversed from snprintf().)^ This is an +** historical accident that cannot be fixed without breaking +** backwards compatibility. ^(Note also that sqlite3_snprintf() +** returns a pointer to its buffer instead of the number of +** characters actually written into the buffer.)^ We admit that +** the number of characters written would be a more useful return +** value but we cannot change the implementation of sqlite3_snprintf() +** now without breaking compatibility. +** +** ^As long as the buffer size is greater than zero, sqlite3_snprintf() +** guarantees that the buffer is always zero-terminated. ^The first +** parameter "n" is the total size of the buffer, including space for +** the zero terminator. So the longest string that can be completely +** written will be n-1 characters. +** +** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). +** +** These routines all implement some additional formatting +** options that are useful for constructing SQL statements. +** All of the usual printf() formatting options apply. In addition, there +** is are "%q", "%Q", "%w" and "%z" options. +** +** ^(The %q option works like %s in that it substitutes a nul-terminated +** string from the argument list. But %q also doubles every '\'' character. +** %q is designed for use inside a string literal.)^ By doubling each '\'' +** character it escapes that character and allows it to be inserted into +** the string. +** +** For example, assume the string variable zText contains text as follows: +** +**
+**  char *zText = "It's a happy day!";
+** 
+** +** One can use this text in an SQL statement as follows: +** +**
+**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
+**  sqlite3_exec(db, zSQL, 0, 0, 0);
+**  sqlite3_free(zSQL);
+** 
+** +** Because the %q format string is used, the '\'' character in zText +** is escaped and the SQL generated is as follows: +** +**
+**  INSERT INTO table1 VALUES('It''s a happy day!')
+** 
+** +** This is correct. Had we used %s instead of %q, the generated SQL +** would have looked like this: +** +**
+**  INSERT INTO table1 VALUES('It's a happy day!');
+** 
+** +** This second example is an SQL syntax error. As a general rule you should +** always use %q instead of %s when inserting text into a string literal. +** +** ^(The %Q option works like %q except it also adds single quotes around +** the outside of the total string. Additionally, if the parameter in the +** argument list is a NULL pointer, %Q substitutes the text "NULL" (without +** single quotes).)^ So, for example, one could say: +** +**
+**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
+**  sqlite3_exec(db, zSQL, 0, 0, 0);
+**  sqlite3_free(zSQL);
+** 
+** +** The code above will render a correct SQL statement in the zSQL +** variable even if the zText variable is a NULL pointer. +** +** ^(The "%w" formatting option is like "%q" except that it expects to +** be contained within double-quotes instead of single quotes, and it +** escapes the double-quote character instead of the single-quote +** character.)^ The "%w" formatting option is intended for safely inserting +** table and column names into a constructed SQL statement. +** +** ^(The "%z" formatting option works like "%s" but with the +** addition that after the string has been read and copied into +** the result, [sqlite3_free()] is called on the input string.)^ +*/ +SQLITE_API char *sqlite3_mprintf(const char*,...); +SQLITE_API char *sqlite3_vmprintf(const char*, va_list); +SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); +SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); + +/* +** CAPI3REF: Memory Allocation Subsystem +** +** The SQLite core uses these three routines for all of its own +** internal memory allocation needs. "Core" in the previous sentence +** does not include operating-system specific VFS implementation. The +** Windows VFS uses native malloc() and free() for some operations. +** +** ^The sqlite3_malloc() routine returns a pointer to a block +** of memory at least N bytes in length, where N is the parameter. +** ^If sqlite3_malloc() is unable to obtain sufficient free +** memory, it returns a NULL pointer. ^If the parameter N to +** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns +** a NULL pointer. +** +** ^The sqlite3_malloc64(N) routine works just like +** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead +** of a signed 32-bit integer. +** +** ^Calling sqlite3_free() with a pointer previously returned +** by sqlite3_malloc() or sqlite3_realloc() releases that memory so +** that it might be reused. ^The sqlite3_free() routine is +** a no-op if is called with a NULL pointer. Passing a NULL pointer +** to sqlite3_free() is harmless. After being freed, memory +** should neither be read nor written. Even reading previously freed +** memory might result in a segmentation fault or other severe error. +** Memory corruption, a segmentation fault, or other severe error +** might result if sqlite3_free() is called with a non-NULL pointer that +** was not obtained from sqlite3_malloc() or sqlite3_realloc(). +** +** ^The sqlite3_realloc(X,N) interface attempts to resize a +** prior memory allocation X to be at least N bytes. +** ^If the X parameter to sqlite3_realloc(X,N) +** is a NULL pointer then its behavior is identical to calling +** sqlite3_malloc(N). +** ^If the N parameter to sqlite3_realloc(X,N) is zero or +** negative then the behavior is exactly the same as calling +** sqlite3_free(X). +** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation +** of at least N bytes in size or NULL if insufficient memory is available. +** ^If M is the size of the prior allocation, then min(N,M) bytes +** of the prior allocation are copied into the beginning of buffer returned +** by sqlite3_realloc(X,N) and the prior allocation is freed. +** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the +** prior allocation is not freed. +** +** ^The sqlite3_realloc64(X,N) interfaces works the same as +** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead +** of a 32-bit signed integer. +** +** ^If X is a memory allocation previously obtained from sqlite3_malloc(), +** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then +** sqlite3_msize(X) returns the size of that memory allocation in bytes. +** ^The value returned by sqlite3_msize(X) might be larger than the number +** of bytes requested when X was allocated. ^If X is a NULL pointer then +** sqlite3_msize(X) returns zero. If X points to something that is not +** the beginning of memory allocation, or if it points to a formerly +** valid memory allocation that has now been freed, then the behavior +** of sqlite3_msize(X) is undefined and possibly harmful. +** +** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), +** sqlite3_malloc64(), and sqlite3_realloc64() +** is always aligned to at least an 8 byte boundary, or to a +** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time +** option is used. +** +** In SQLite version 3.5.0 and 3.5.1, it was possible to define +** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in +** implementation of these routines to be omitted. That capability +** is no longer provided. Only built-in memory allocators can be used. +** +** Prior to SQLite version 3.7.10, the Windows OS interface layer called +** the system malloc() and free() directly when converting +** filenames between the UTF-8 encoding used by SQLite +** and whatever filename encoding is used by the particular Windows +** installation. Memory allocation errors were detected, but +** they were reported back as [SQLITE_CANTOPEN] or +** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. +** +** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] +** must be either NULL or else pointers obtained from a prior +** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have +** not yet been released. +** +** The application must not read or write any part of +** a block of memory after it has been released using +** [sqlite3_free()] or [sqlite3_realloc()]. +*/ +SQLITE_API void *sqlite3_malloc(int); +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); +SQLITE_API void *sqlite3_realloc(void*, int); +SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); +SQLITE_API void sqlite3_free(void*); +SQLITE_API sqlite3_uint64 sqlite3_msize(void*); + +/* +** CAPI3REF: Memory Allocator Statistics +** +** SQLite provides these two interfaces for reporting on the status +** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] +** routines, which form the built-in memory allocation subsystem. +** +** ^The [sqlite3_memory_used()] routine returns the number of bytes +** of memory currently outstanding (malloced but not freed). +** ^The [sqlite3_memory_highwater()] routine returns the maximum +** value of [sqlite3_memory_used()] since the high-water mark +** was last reset. ^The values returned by [sqlite3_memory_used()] and +** [sqlite3_memory_highwater()] include any overhead +** added by SQLite in its implementation of [sqlite3_malloc()], +** but not overhead added by the any underlying system library +** routines that [sqlite3_malloc()] may call. +** +** ^The memory high-water mark is reset to the current value of +** [sqlite3_memory_used()] if and only if the parameter to +** [sqlite3_memory_highwater()] is true. ^The value returned +** by [sqlite3_memory_highwater(1)] is the high-water mark +** prior to the reset. +*/ +SQLITE_API sqlite3_int64 sqlite3_memory_used(void); +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); + +/* +** CAPI3REF: Pseudo-Random Number Generator +** +** SQLite contains a high-quality pseudo-random number generator (PRNG) used to +** select random [ROWID | ROWIDs] when inserting new records into a table that +** already uses the largest possible [ROWID]. The PRNG is also used for +** the build-in random() and randomblob() SQL functions. This interface allows +** applications to access the same PRNG for other purposes. +** +** ^A call to this routine stores N bytes of randomness into buffer P. +** ^The P parameter can be a NULL pointer. +** +** ^If this routine has not been previously called or if the previous +** call had N less than one or a NULL pointer for P, then the PRNG is +** seeded using randomness obtained from the xRandomness method of +** the default [sqlite3_vfs] object. +** ^If the previous call to this routine had an N of 1 or more and a +** non-NULL P then the pseudo-randomness is generated +** internally and without recourse to the [sqlite3_vfs] xRandomness +** method. +*/ +SQLITE_API void sqlite3_randomness(int N, void *P); + +/* +** CAPI3REF: Compile-Time Authorization Callbacks +** METHOD: sqlite3 +** +** ^This routine registers an authorizer callback with a particular +** [database connection], supplied in the first argument. +** ^The authorizer callback is invoked as SQL statements are being compiled +** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], +** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** points during the compilation process, as logic is being created +** to perform various actions, the authorizer callback is invoked to +** see if those actions are allowed. ^The authorizer callback should +** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the +** specific action but allow the SQL statement to continue to be +** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be +** rejected with an error. ^If the authorizer callback returns +** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] +** then the [sqlite3_prepare_v2()] or equivalent call that triggered +** the authorizer will fail with an error message. +** +** When the callback returns [SQLITE_OK], that means the operation +** requested is ok. ^When the callback returns [SQLITE_DENY], the +** [sqlite3_prepare_v2()] or equivalent call that triggered the +** authorizer will fail with an error message explaining that +** access is denied. +** +** ^The first parameter to the authorizer callback is a copy of the third +** parameter to the sqlite3_set_authorizer() interface. ^The second parameter +** to the callback is an integer [SQLITE_COPY | action code] that specifies +** the particular action to be authorized. ^The third through sixth parameters +** to the callback are zero-terminated strings that contain additional +** details about the action to be authorized. +** +** ^If the action code is [SQLITE_READ] +** and the callback returns [SQLITE_IGNORE] then the +** [prepared statement] statement is constructed to substitute +** a NULL value in place of the table column that would have +** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] +** return can be used to deny an untrusted user access to individual +** columns of a table. +** ^If the action code is [SQLITE_DELETE] and the callback returns +** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the +** [truncate optimization] is disabled and all rows are deleted individually. +** +** An authorizer is used when [sqlite3_prepare | preparing] +** SQL statements from an untrusted source, to ensure that the SQL statements +** do not try to access data they are not allowed to see, or that they do not +** try to execute malicious statements that damage the database. For +** example, an application may allow a user to enter arbitrary +** SQL queries for evaluation by a database. But the application does +** not want the user to be able to make arbitrary changes to the +** database. An authorizer could then be put in place while the +** user-entered SQL is being [sqlite3_prepare | prepared] that +** disallows everything except [SELECT] statements. +** +** Applications that need to process SQL from untrusted sources +** might also consider lowering resource limits using [sqlite3_limit()] +** and limiting database size using the [max_page_count] [PRAGMA] +** in addition to using an authorizer. +** +** ^(Only a single authorizer can be in place on a database connection +** at a time. Each call to sqlite3_set_authorizer overrides the +** previous call.)^ ^Disable the authorizer by installing a NULL callback. +** The authorizer is disabled by default. +** +** The authorizer callback must not do anything that will modify +** the database connection that invoked the authorizer callback. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the +** statement might be re-prepared during [sqlite3_step()] due to a +** schema change. Hence, the application should ensure that the +** correct authorizer callback remains in place during the [sqlite3_step()]. +** +** ^Note that the authorizer callback is invoked only during +** [sqlite3_prepare()] or its variants. Authorization is not +** performed during statement evaluation in [sqlite3_step()], unless +** as stated in the previous paragraph, sqlite3_step() invokes +** sqlite3_prepare_v2() to reprepare a statement after a schema change. +*/ +SQLITE_API int sqlite3_set_authorizer( + sqlite3*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData +); + +/* +** CAPI3REF: Authorizer Return Codes +** +** The [sqlite3_set_authorizer | authorizer callback function] must +** return either [SQLITE_OK] or one of these two constants in order +** to signal SQLite whether or not the action is permitted. See the +** [sqlite3_set_authorizer | authorizer documentation] for additional +** information. +** +** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] +** returned from the [sqlite3_vtab_on_conflict()] interface. +*/ +#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ +#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ + +/* +** CAPI3REF: Authorizer Action Codes +** +** The [sqlite3_set_authorizer()] interface registers a callback function +** that is invoked to authorize certain SQL statement actions. The +** second parameter to the callback is an integer code that specifies +** what action is being authorized. These are the integer action codes that +** the authorizer callback may be passed. +** +** These action code values signify what kind of operation is to be +** authorized. The 3rd and 4th parameters to the authorization +** callback function will be parameters or NULL depending on which of these +** codes is used as the second parameter. ^(The 5th parameter to the +** authorizer callback is the name of the database ("main", "temp", +** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback +** is the name of the inner-most trigger or view that is responsible for +** the access attempt or NULL if this access attempt is directly from +** top-level SQL code. +*/ +/******************************************* 3rd ************ 4th ***********/ +#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ +#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ +#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ +#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ +#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ +#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ +#define SQLITE_DELETE 9 /* Table Name NULL */ +#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ +#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ +#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ +#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ +#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ +#define SQLITE_DROP_VIEW 17 /* View Name NULL */ +#define SQLITE_INSERT 18 /* Table Name NULL */ +#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ +#define SQLITE_READ 20 /* Table Name Column Name */ +#define SQLITE_SELECT 21 /* NULL NULL */ +#define SQLITE_TRANSACTION 22 /* Operation NULL */ +#define SQLITE_UPDATE 23 /* Table Name Column Name */ +#define SQLITE_ATTACH 24 /* Filename NULL */ +#define SQLITE_DETACH 25 /* Database Name NULL */ +#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ +#define SQLITE_REINDEX 27 /* Index Name NULL */ +#define SQLITE_ANALYZE 28 /* Table Name NULL */ +#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ +#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ +#define SQLITE_FUNCTION 31 /* NULL Function Name */ +#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ +#define SQLITE_COPY 0 /* No longer used */ +#define SQLITE_RECURSIVE 33 /* NULL NULL */ + +/* +** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 +** +** These routines are deprecated. Use the [sqlite3_trace_v2()] interface +** instead of the routines described here. +** +** These routines register callback functions that can be used for +** tracing and profiling the execution of SQL statements. +** +** ^The callback function registered by sqlite3_trace() is invoked at +** various times when an SQL statement is being run by [sqlite3_step()]. +** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the +** SQL statement text as the statement first begins executing. +** ^(Additional sqlite3_trace() callbacks might occur +** as each triggered subprogram is entered. The callbacks for triggers +** contain a UTF-8 SQL comment that identifies the trigger.)^ +** +** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit +** the length of [bound parameter] expansion in the output of sqlite3_trace(). +** +** ^The callback function registered by sqlite3_profile() is invoked +** as each SQL statement finishes. ^The profile callback contains +** the original statement text and an estimate of wall-clock time +** of how long that statement took to run. ^The profile callback +** time is in units of nanoseconds, however the current implementation +** is only capable of millisecond resolution so the six least significant +** digits in the time are meaningless. Future versions of SQLite +** might provide greater resolution on the profiler callback. The +** sqlite3_profile() function is considered experimental and is +** subject to change in future versions of SQLite. +*/ +SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + +/* +** CAPI3REF: SQL Trace Event Codes +** KEYWORDS: SQLITE_TRACE +** +** These constants identify classes of events that can be monitored +** using the [sqlite3_trace_v2()] tracing logic. The third argument +** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** the following constants. ^The first argument to the trace callback +** is one of the following constants. +** +** New tracing constants may be added in future releases. +** +** ^A trace callback has four arguments: xCallback(T,C,P,X). +** ^The T argument is one of the integer type codes above. +** ^The C argument is a copy of the context pointer passed in as the +** fourth argument to [sqlite3_trace_v2()]. +** The P and X arguments are pointers whose meanings depend on T. +** +**
+** [[SQLITE_TRACE_STMT]]
SQLITE_TRACE_STMT
+**
^An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. ^The P argument is a pointer to the +** [prepared statement]. ^The X argument is a pointer to a string which +** is the unexpanded SQL text of the prepared statement or an SQL comment +** that indicates the invocation of a trigger. ^The callback can compute +** the same text that would have been returned by the legacy [sqlite3_trace()] +** interface by using the X argument when X begins with "--" and invoking +** [sqlite3_expanded_sql(P)] otherwise. +** +** [[SQLITE_TRACE_PROFILE]]
SQLITE_TRACE_PROFILE
+**
^An SQLITE_TRACE_PROFILE callback provides approximately the same +** information as is provided by the [sqlite3_profile()] callback. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. +** +** [[SQLITE_TRACE_ROW]]
SQLITE_TRACE_ROW
+**
^An SQLITE_TRACE_ROW callback is invoked whenever a prepared +** statement generates a single row of result. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument is unused. +** +** [[SQLITE_TRACE_CLOSE]]
SQLITE_TRACE_CLOSE
+**
^An SQLITE_TRACE_CLOSE callback is invoked when a database +** connection closes. +** ^The P argument is a pointer to the [database connection] object +** and the X argument is unused. +**
+*/ +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + +/* +** CAPI3REF: SQL Trace Hook +** METHOD: sqlite3 +** +** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback +** function X against [database connection] D, using property mask M +** and context pointer P. ^If the X callback is +** NULL or if the M mask is zero, then tracing is disabled. The +** M argument should be the bitwise OR-ed combination of +** zero or more [SQLITE_TRACE] constants. +** +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). +** +** ^The X callback is invoked whenever any of the events identified by +** mask M occur. ^The integer return value from the callback is currently +** ignored, though this may change in future releases. Callback +** implementations should return zero to ensure future compatibility. +** +** ^A trace callback is invoked with four arguments: callback(T,C,P,X). +** ^The T argument is one of the [SQLITE_TRACE] +** constants to indicate why the callback was invoked. +** ^The C argument is a copy of the context pointer. +** The P and X arguments are pointers whose meanings depend on T. +** +** The sqlite3_trace_v2() interface is intended to replace the legacy +** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which +** are deprecated. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); + +/* +** CAPI3REF: Query Progress Callbacks +** METHOD: sqlite3 +** +** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback +** function X to be invoked periodically during long running calls to +** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for +** database connection D. An example use for this +** interface is to keep a GUI updated during a large query. +** +** ^The parameter P is passed through as the only parameter to the +** callback function X. ^The parameter N is the approximate number of +** [virtual machine instructions] that are evaluated between successive +** invocations of the callback X. ^If N is less than one then the progress +** handler is disabled. +** +** ^Only a single progress handler may be defined at one time per +** [database connection]; setting a new progress handler cancels the +** old one. ^Setting parameter X to NULL disables the progress handler. +** ^The progress handler is also disabled by setting N to a value less +** than 1. +** +** ^If the progress callback returns non-zero, the operation is +** interrupted. This feature can be used to implement a +** "Cancel" button on a GUI progress dialog box. +** +** The progress handler callback must not do anything that will modify +** the database connection that invoked the progress handler. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +*/ +SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); + +/* +** CAPI3REF: Opening A New Database Connection +** CONSTRUCTOR: sqlite3 +** +** ^These routines open an SQLite database file as specified by the +** filename argument. ^The filename argument is interpreted as UTF-8 for +** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte +** order for sqlite3_open16(). ^(A [database connection] handle is usually +** returned in *ppDb, even if an error occurs. The only exception is that +** if SQLite is unable to allocate memory to hold the [sqlite3] object, +** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] +** object.)^ ^(If the database is opened (and/or created) successfully, then +** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The +** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain +** an English language description of the error following a failure of any +** of the sqlite3_open() routines. +** +** ^The default encoding will be UTF-8 for databases created using +** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases +** created using sqlite3_open16() will be UTF-16 in the native byte order. +** +** Whether or not an error occurs when it is opened, resources +** associated with the [database connection] handle should be released by +** passing it to [sqlite3_close()] when it is no longer required. +** +** The sqlite3_open_v2() interface works like sqlite3_open() +** except that it accepts two additional parameters for additional control +** over the new database connection. ^(The flags parameter to +** sqlite3_open_v2() can take one of +** the following three values, optionally combined with the +** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ +** +**
+** ^(
[SQLITE_OPEN_READONLY]
+**
The database is opened in read-only mode. If the database does not +** already exist, an error is returned.
)^ +** +** ^(
[SQLITE_OPEN_READWRITE]
+**
The database is opened for reading and writing if possible, or reading +** only if the file is write protected by the operating system. In either +** case the database must already exist, otherwise an error is returned.
)^ +** +** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
+**
The database is opened for reading and writing, and is created if +** it does not already exist. This is the behavior that is always used for +** sqlite3_open() and sqlite3_open16().
)^ +**
+** +** If the 3rd parameter to sqlite3_open_v2() is not one of the +** combinations shown above optionally combined with other +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] +** then the behavior is undefined. +** +** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection +** opens in the multi-thread [threading mode] as long as the single-thread +** mode has not been set at compile-time or start-time. ^If the +** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens +** in the serialized [threading mode] unless single-thread was +** previously selected at compile-time or start-time. +** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be +** eligible to use [shared cache mode], regardless of whether or not shared +** cache is enabled using [sqlite3_enable_shared_cache()]. ^The +** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not +** participate in [shared cache mode] even if it is enabled. +** +** ^The fourth parameter to sqlite3_open_v2() is the name of the +** [sqlite3_vfs] object that defines the operating system interface that +** the new database connection should use. ^If the fourth parameter is +** a NULL pointer then the default [sqlite3_vfs] object is used. +** +** ^If the filename is ":memory:", then a private, temporary in-memory database +** is created for the connection. ^This in-memory database will vanish when +** the database connection is closed. Future versions of SQLite might +** make use of additional special filenames that begin with the ":" character. +** It is recommended that when a database filename actually does begin with +** a ":" character you should prefix the filename with a pathname such as +** "./" to avoid ambiguity. +** +** ^If the filename is an empty string, then a private, temporary +** on-disk database will be created. ^This private database will be +** automatically deleted as soon as the database connection is closed. +** +** [[URI filenames in sqlite3_open()]]

URI Filenames

+** +** ^If [URI filename] interpretation is enabled, and the filename argument +** begins with "file:", then the filename is interpreted as a URI. ^URI +** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is +** set in the fourth argument to sqlite3_open_v2(), or if it has +** been enabled globally using the [SQLITE_CONFIG_URI] option with the +** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. +** As of SQLite version 3.7.7, URI filename interpretation is turned off +** by default, but future releases of SQLite might enable URI filename +** interpretation by default. See "[URI filenames]" for additional +** information. +** +** URI filenames are parsed according to RFC 3986. ^If the URI contains an +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if +** present, is ignored. +** +** ^SQLite uses the path component of the URI as the name of the disk file +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin +** with a '/' (meaning that the authority section is omitted from the URI) +** then the path is interpreted as a relative path. +** ^(On windows, the first component of an absolute path +** is a drive specification (e.g. "C:").)^ +** +** [[core URI query parameters]] +** The query component of a URI may contain parameters that are interpreted +** either by SQLite itself, or by a [VFS | custom VFS implementation]. +** SQLite and its built-in [VFSes] interpret the +** following query parameters: +** +**
    +**
  • vfs: ^The "vfs" parameter may be used to specify the name of +** a VFS object that provides the operating system interface that should +** be used to access the database file on disk. ^If this option is set to +** an empty string the default VFS object is used. ^Specifying an unknown +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is +** present, then the VFS specified by the option takes precedence over +** the value passed as the fourth parameter to sqlite3_open_v2(). +** +**
  • mode: ^(The mode parameter may be set to either "ro", "rw", +** "rwc", or "memory". Attempting to set it to any other value is +** an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_open_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is +** set to "memory" then a pure [in-memory database] that never reads +** or writes from disk is used. ^It is an error to specify a value for +** the mode parameter that is less restrictive than that specified by +** the flags passed in the third parameter to sqlite3_open_v2(). +** +**
  • cache: ^The cache parameter may be set to either "shared" or +** "private". ^Setting it to "shared" is equivalent to setting the +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in +** a URI filename, its value overrides any behavior requested by setting +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +** +**
  • psow: ^The psow parameter indicates whether or not the +** [powersafe overwrite] property does or does not apply to the +** storage media on which the database file resides. +** +**
  • nolock: ^The nolock parameter is a boolean query parameter +** which if set disables file locking in rollback journal modes. This +** is useful for accessing a database on a filesystem that does not +** support locking. Caution: Database corruption might result if two +** or more processes write to the same database and any one of those +** processes uses nolock=1. +** +**
  • immutable: ^The immutable parameter is a boolean query +** parameter that indicates that the database file is stored on +** read-only media. ^When immutable is set, SQLite assumes that the +** database file cannot be changed, even by a process with higher +** privilege, and so the database is opened read-only and all locking +** and change detection is disabled. Caution: Setting the immutable +** property on a database file that does in fact change can result +** in incorrect query results and/or [SQLITE_CORRUPT] errors. +** See also: [SQLITE_IOCAP_IMMUTABLE]. +** +**
+** +** ^Specifying an unknown parameter in the query component of a URI is not an +** error. Future versions of SQLite might understand additional query +** parameters. See "[query parameters with special meaning to SQLite]" for +** additional information. +** +** [[URI filename examples]]

URI filename examples

+** +** +**
URI filenames Results +**
file:data.db +** Open the file "data.db" in the current directory. +**
file:/home/fred/data.db
+** file:///home/fred/data.db
+** file://localhost/home/fred/data.db
+** Open the database file "/home/fred/data.db". +**
file://darkstar/home/fred/data.db +** An error. "darkstar" is not a recognized authority. +**
+** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db +** Windows only: Open the file "data.db" on fred's desktop on drive +** C:. Note that the %20 escaping in this example is not strictly +** necessary - space characters can be used literally +** in URI filenames. +**
file:data.db?mode=ro&cache=private +** Open file "data.db" in the current directory for read-only access. +** Regardless of whether or not shared-cache mode is enabled by +** default, use a private cache. +**
file:/home/fred/data.db?vfs=unix-dotfile +** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" +** that uses dot-files in place of posix advisory locking. +**
file:data.db?mode=readonly +** An error. "readonly" is not a valid option for the "mode" parameter. +**
+** +** ^URI hexadecimal escape sequences (%HH) are supported within the path and +** query components of a URI. A hexadecimal escape sequence consists of a +** percent sign - "%" - followed by exactly two hexadecimal digits +** specifying an octet value. ^Before the path or query components of a +** URI filename are interpreted, they are encoded using UTF-8 and all +** hexadecimal escape sequences replaced by a single byte containing the +** corresponding octet. If this process generates an invalid UTF-8 encoding, +** the results are undefined. +** +** Note to Windows users: The encoding used for the filename argument +** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever +** codepage is currently defined. Filenames containing international +** characters must be converted to UTF-8 prior to passing them into +** sqlite3_open() or sqlite3_open_v2(). +** +** Note to Windows Runtime users: The temporary directory must be set +** prior to calling sqlite3_open() or sqlite3_open_v2(). Otherwise, various +** features that require the use of temporary files may fail. +** +** See also: [sqlite3_temp_directory] +*/ +SQLITE_API int sqlite3_open( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +SQLITE_API int sqlite3_open16( + const void *filename, /* Database filename (UTF-16) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +SQLITE_API int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +); + +/* +** CAPI3REF: Obtain Values For URI Parameters +** +** These are utility routines, useful to VFS implementations, that check +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of that query parameter. +** +** If F is the database filename pointer passed into the xOpen() method of +** a VFS implementation when the flags parameter to xOpen() has one or +** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and +** P is the name of the query parameter, then +** sqlite3_uri_parameter(F,P) returns the value of the P +** parameter if it exists or a NULL pointer if P does not appear as a +** query parameter on F. If P is a query parameter of F +** has no explicit value, then sqlite3_uri_parameter(F,P) returns +** a pointer to an empty string. +** +** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean +** parameter and returns true (1) or false (0) according to the value +** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the +** value of query parameter P is one of "yes", "true", or "on" in any +** case or if the value begins with a non-zero number. The +** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of +** query parameter P is one of "no", "false", or "off" in any case or +** if the value begins with a numeric zero. If P is not a query +** parameter on F or if the value of P is does not match any of the +** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). +** +** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a +** 64-bit signed integer and returns that integer, or D if P does not +** exist. If the value of P is something other than an integer, then +** zero is returned. +** +** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and +** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and +** is not a database file pathname pointer that SQLite passed into the xOpen +** VFS method, then the behavior of this routine is undefined and probably +** undesirable. +*/ +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); +SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); +SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); + + +/* +** CAPI3REF: Error Codes And Messages +** METHOD: sqlite3 +** +** ^If the most recent sqlite3_* API call associated with +** [database connection] D failed, then the sqlite3_errcode(D) interface +** returns the numeric [result code] or [extended result code] for that +** API call. +** If the most recent API call was successful, +** then the return value from sqlite3_errcode() is undefined. +** ^The sqlite3_extended_errcode() +** interface is the same except that it always returns the +** [extended result code] even when extended result codes are +** disabled. +** +** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language +** text that describes the error, as either UTF-8 or UTF-16 respectively. +** ^(Memory to hold the error message string is managed internally. +** The application does not need to worry about freeing the result. +** However, the error string might be overwritten or deallocated by +** subsequent calls to other SQLite interface functions.)^ +** +** ^The sqlite3_errstr() interface returns the English-language text +** that describes the [result code], as UTF-8. +** ^(Memory to hold the error message string is managed internally +** and must not be freed by the application)^. +** +** When the serialized [threading mode] is in use, it might be the +** case that a second error occurs on a separate thread in between +** the time of the first error and the call to these interfaces. +** When that happens, the second error will be reported since these +** interfaces always report the most recent result. To avoid +** this, each thread can obtain exclusive use of the [database connection] D +** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning +** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after +** all calls to the interfaces listed here are completed. +** +** If an interface fails with SQLITE_MISUSE, that means the interface +** was invoked incorrectly by the application. In that case, the +** error code and message may or may not be set. +*/ +SQLITE_API int sqlite3_errcode(sqlite3 *db); +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); +SQLITE_API const char *sqlite3_errmsg(sqlite3*); +SQLITE_API const void *sqlite3_errmsg16(sqlite3*); +SQLITE_API const char *sqlite3_errstr(int); + +/* +** CAPI3REF: Prepared Statement Object +** KEYWORDS: {prepared statement} {prepared statements} +** +** An instance of this object represents a single SQL statement that +** has been compiled into binary form and is ready to be evaluated. +** +** Think of each SQL statement as a separate computer program. The +** original SQL text is source code. A prepared statement object +** is the compiled object code. All SQL must be converted into a +** prepared statement before it can be run. +** +** The life-cycle of a prepared statement object usually goes like this: +** +**
    +**
  1. Create the prepared statement object using [sqlite3_prepare_v2()]. +**
  2. Bind values to [parameters] using the sqlite3_bind_*() +** interfaces. +**
  3. Run the SQL by calling [sqlite3_step()] one or more times. +**
  4. Reset the prepared statement using [sqlite3_reset()] then go back +** to step 2. Do this zero or more times. +**
  5. Destroy the object using [sqlite3_finalize()]. +**
+*/ +typedef struct sqlite3_stmt sqlite3_stmt; + +/* +** CAPI3REF: Run-time Limits +** METHOD: sqlite3 +** +** ^(This interface allows the size of various constructs to be limited +** on a connection by connection basis. The first parameter is the +** [database connection] whose limit is to be set or queried. The +** second parameter is one of the [limit categories] that define a +** class of constructs to be size limited. The third parameter is the +** new limit for that construct.)^ +** +** ^If the new limit is a negative number, the limit is unchanged. +** ^(For each limit category SQLITE_LIMIT_NAME there is a +** [limits | hard upper bound] +** set at compile-time by a C preprocessor macro called +** [limits | SQLITE_MAX_NAME]. +** (The "_LIMIT_" in the name is changed to "_MAX_".))^ +** ^Attempts to increase a limit above its hard upper bound are +** silently truncated to the hard upper bound. +** +** ^Regardless of whether or not the limit was changed, the +** [sqlite3_limit()] interface returns the prior value of the limit. +** ^Hence, to find the current value of a limit without changing it, +** simply invoke this interface with the third parameter set to -1. +** +** Run-time limits are intended for use in applications that manage +** both their own internal database and also databases that are controlled +** by untrusted external sources. An example application might be a +** web browser that has its own databases for storing history and +** separate databases controlled by JavaScript applications downloaded +** off the Internet. The internal databases can be given the +** large, default limits. Databases managed by external sources can +** be given much smaller limits designed to prevent a denial of service +** attack. Developers might also want to use the [sqlite3_set_authorizer()] +** interface to further control untrusted SQL. The size of the database +** created by an untrusted script can be contained using the +** [max_page_count] [PRAGMA]. +** +** New run-time limit categories may be added in future releases. +*/ +SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); + +/* +** CAPI3REF: Run-Time Limit Categories +** KEYWORDS: {limit category} {*limit categories} +** +** These constants define various performance limits +** that can be lowered at run-time using [sqlite3_limit()]. +** The synopsis of the meanings of the various limits is shown below. +** Additional information is available at [limits | Limits in SQLite]. +** +**
+** [[SQLITE_LIMIT_LENGTH]] ^(
SQLITE_LIMIT_LENGTH
+**
The maximum size of any string or BLOB or table row, in bytes.
)^ +** +** [[SQLITE_LIMIT_SQL_LENGTH]] ^(
SQLITE_LIMIT_SQL_LENGTH
+**
The maximum length of an SQL statement, in bytes.
)^ +** +** [[SQLITE_LIMIT_COLUMN]] ^(
SQLITE_LIMIT_COLUMN
+**
The maximum number of columns in a table definition or in the +** result set of a [SELECT] or the maximum number of columns in an index +** or in an ORDER BY or GROUP BY clause.
)^ +** +** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
+**
The maximum depth of the parse tree on any expression.
)^ +** +** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
SQLITE_LIMIT_COMPOUND_SELECT
+**
The maximum number of terms in a compound SELECT statement.
)^ +** +** [[SQLITE_LIMIT_VDBE_OP]] ^(
SQLITE_LIMIT_VDBE_OP
+**
The maximum number of instructions in a virtual machine program +** used to implement an SQL statement. This limit is not currently +** enforced, though that might be added in some future release of +** SQLite.
)^ +** +** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
SQLITE_LIMIT_FUNCTION_ARG
+**
The maximum number of arguments on a function.
)^ +** +** [[SQLITE_LIMIT_ATTACHED]] ^(
SQLITE_LIMIT_ATTACHED
+**
The maximum number of [ATTACH | attached databases].)^
+** +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] +** ^(
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
+**
The maximum length of the pattern argument to the [LIKE] or +** [GLOB] operators.
)^ +** +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] +** ^(
SQLITE_LIMIT_VARIABLE_NUMBER
+**
The maximum index number of any [parameter] in an SQL statement.)^ +** +** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
+**
The maximum depth of recursion for triggers.
)^ +** +** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
+**
The maximum number of auxiliary worker threads that a single +** [prepared statement] may start.
)^ +**
+*/ +#define SQLITE_LIMIT_LENGTH 0 +#define SQLITE_LIMIT_SQL_LENGTH 1 +#define SQLITE_LIMIT_COLUMN 2 +#define SQLITE_LIMIT_EXPR_DEPTH 3 +#define SQLITE_LIMIT_COMPOUND_SELECT 4 +#define SQLITE_LIMIT_VDBE_OP 5 +#define SQLITE_LIMIT_FUNCTION_ARG 6 +#define SQLITE_LIMIT_ATTACHED 7 +#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 +#define SQLITE_LIMIT_VARIABLE_NUMBER 9 +#define SQLITE_LIMIT_TRIGGER_DEPTH 10 +#define SQLITE_LIMIT_WORKER_THREADS 11 + +/* +** CAPI3REF: Compiling An SQL Statement +** KEYWORDS: {SQL statement compiler} +** METHOD: sqlite3 +** CONSTRUCTOR: sqlite3_stmt +** +** To execute an SQL query, it must first be compiled into a byte-code +** program using one of these routines. +** +** The first argument, "db", is a [database connection] obtained from a +** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or +** [sqlite3_open16()]. The database connection must not have been closed. +** +** The second argument, "zSql", is the statement to be compiled, encoded +** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() +** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() +** use UTF-16. +** +** ^If the nByte argument is negative, then zSql is read up to the +** first zero terminator. ^If nByte is positive, then it is the +** number of bytes read from zSql. ^If nByte is zero, then no prepared +** statement is generated. +** If the caller knows that the supplied string is nul-terminated, then +** there is a small performance advantage to passing an nByte parameter that +** is the number of bytes in the input string including +** the nul-terminator. +** +** ^If pzTail is not NULL then *pzTail is made to point to the first byte +** past the end of the first SQL statement in zSql. These routines only +** compile the first statement in zSql, so *pzTail is left pointing to +** what remains uncompiled. +** +** ^*ppStmt is left pointing to a compiled [prepared statement] that can be +** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set +** to NULL. ^If the input text contains no SQL (if the input is an empty +** string or a comment) then *ppStmt is set to NULL. +** The calling procedure is responsible for deleting the compiled +** SQL statement using [sqlite3_finalize()] after it has finished with it. +** ppStmt may not be NULL. +** +** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; +** otherwise an [error code] is returned. +** +** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are +** recommended for all new programs. The two older interfaces are retained +** for backwards compatibility, but their use is discouraged. +** ^In the "v2" interfaces, the prepared statement +** that is returned (the [sqlite3_stmt] object) contains a copy of the +** original SQL text. This causes the [sqlite3_step()] interface to +** behave differently in three ways: +** +**
    +**
  1. +** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it +** always used to do, [sqlite3_step()] will automatically recompile the SQL +** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] +** retries will occur before sqlite3_step() gives up and returns an error. +**
  2. +** +**
  3. +** ^When an error occurs, [sqlite3_step()] will return one of the detailed +** [error codes] or [extended error codes]. ^The legacy behavior was that +** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code +** and the application would have to make a second call to [sqlite3_reset()] +** in order to find the underlying cause of the problem. With the "v2" prepare +** interfaces, the underlying reason for the error is returned immediately. +**
  4. +** +**
  5. +** ^If the specific value bound to [parameter | host parameter] in the +** WHERE clause might influence the choice of query plan for a statement, +** then the statement will be automatically recompiled, as if there had been +** a schema change, on the first [sqlite3_step()] call following any change +** to the [sqlite3_bind_text | bindings] of that [parameter]. +** ^The specific value of WHERE-clause [parameter] might influence the +** choice of query plan if the parameter is the left-hand side of a [LIKE] +** or [GLOB] operator or if the parameter is compared to an indexed column +** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. +**
  6. +**
+*/ +SQLITE_API int sqlite3_prepare( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare_v2( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16_v2( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); + +/* +** CAPI3REF: Retrieving Statement SQL +** METHOD: sqlite3_stmt +** +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 +** string containing the SQL text of prepared statement P with +** [bound parameters] expanded. +** +** ^(For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL".)^ +** +** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory +** is available to hold the result, or if the result would exceed the +** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** +** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of +** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time +** option causes sqlite3_expanded_sql() to always return NULL. +** +** ^The string returned by sqlite3_sql(P) is managed by SQLite and is +** automatically freed when the prepared statement is finalized. +** ^The string returned by sqlite3_expanded_sql(P), on the other hand, +** is obtained from [sqlite3_malloc()] and must be free by the application +** by passing it to [sqlite3_free()]. +*/ +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Determine If An SQL Statement Writes The Database +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if +** and only if the [prepared statement] X makes no direct changes to +** the content of the database file. +** +** Note that [application-defined SQL functions] or +** [virtual tables] might change the database indirectly as a side effect. +** ^(For example, if an application defines a function "eval()" that +** calls [sqlite3_exec()], then the following SQL statement would +** change the database file through side-effects: +** +**
+**    SELECT eval('DELETE FROM t1') FROM t2;
+** 
+** +** But because the [SELECT] statement does not change the database file +** directly, sqlite3_stmt_readonly() would still return true.)^ +** +** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], +** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, +** since the statements themselves do not actually modify the database but +** rather they control the timing of when other statements modify the +** database. ^The [ATTACH] and [DETACH] statements also cause +** sqlite3_stmt_readonly() to return true since, while those statements +** change the configuration of a database connection, they do not make +** changes to the content of the database files on disk. +*/ +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Determine If A Prepared Statement Has Been Reset +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the +** [prepared statement] S has been stepped at least once using +** [sqlite3_step(S)] but has neither run to completion (returned +** [SQLITE_DONE] from [sqlite3_step(S)]) nor +** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) +** interface returns false if S is a NULL pointer. If S is not a +** NULL pointer and is not a pointer to a valid [prepared statement] +** object, then the behavior is undefined and probably undesirable. +** +** This interface can be used in combination [sqlite3_next_stmt()] +** to locate all prepared statements associated with a database +** connection that are in need of being reset. This can be used, +** for example, in diagnostic routines to search for prepared +** statements that are holding a transaction open. +*/ +SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); + +/* +** CAPI3REF: Dynamically Typed Value Object +** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} +** +** SQLite uses the sqlite3_value object to represent all values +** that can be stored in a database table. SQLite uses dynamic typing +** for the values it stores. ^Values stored in sqlite3_value objects +** can be integers, floating point values, strings, BLOBs, or NULL. +** +** An sqlite3_value object may be either "protected" or "unprotected". +** Some interfaces require a protected sqlite3_value. Other interfaces +** will accept either a protected or an unprotected sqlite3_value. +** Every interface that accepts sqlite3_value arguments specifies +** whether or not it requires a protected sqlite3_value. The +** [sqlite3_value_dup()] interface can be used to construct a new +** protected sqlite3_value from an unprotected sqlite3_value. +** +** The terms "protected" and "unprotected" refer to whether or not +** a mutex is held. An internal mutex is held for a protected +** sqlite3_value object but no mutex is held for an unprotected +** sqlite3_value object. If SQLite is compiled to be single-threaded +** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) +** or if SQLite is run in one of reduced mutex modes +** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] +** then there is no distinction between protected and unprotected +** sqlite3_value objects and they can be used interchangeably. However, +** for maximum code portability it is recommended that applications +** still make the distinction between protected and unprotected +** sqlite3_value objects even when not strictly required. +** +** ^The sqlite3_value objects that are passed as parameters into the +** implementation of [application-defined SQL functions] are protected. +** ^The sqlite3_value object returned by +** [sqlite3_column_value()] is unprotected. +** Unprotected sqlite3_value objects may only be used with +** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** The [sqlite3_value_blob | sqlite3_value_type()] family of +** interfaces require protected sqlite3_value objects. +*/ +typedef struct Mem sqlite3_value; + +/* +** CAPI3REF: SQL Function Context Object +** +** The context in which an SQL function executes is stored in an +** sqlite3_context object. ^A pointer to an sqlite3_context object +** is always first parameter to [application-defined SQL functions]. +** The application-defined SQL function implementation will pass this +** pointer through into calls to [sqlite3_result_int | sqlite3_result()], +** [sqlite3_aggregate_context()], [sqlite3_user_data()], +** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], +** and/or [sqlite3_set_auxdata()]. +*/ +typedef struct sqlite3_context sqlite3_context; + +/* +** CAPI3REF: Binding Values To Prepared Statements +** KEYWORDS: {host parameter} {host parameters} {host parameter name} +** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} +** METHOD: sqlite3_stmt +** +** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, +** literals may be replaced by a [parameter] that matches one of following +** templates: +** +**
    +**
  • ? +**
  • ?NNN +**
  • :VVV +**
  • @VVV +**
  • $VVV +**
+** +** In the templates above, NNN represents an integer literal, +** and VVV represents an alphanumeric identifier.)^ ^The values of these +** parameters (also called "host parameter names" or "SQL parameters") +** can be set using the sqlite3_bind_*() routines defined here. +** +** ^The first argument to the sqlite3_bind_*() routines is always +** a pointer to the [sqlite3_stmt] object returned from +** [sqlite3_prepare_v2()] or its variants. +** +** ^The second argument is the index of the SQL parameter to be set. +** ^The leftmost SQL parameter has an index of 1. ^When the same named +** SQL parameter is used more than once, second and subsequent +** occurrences have the same index as the first occurrence. +** ^The index for named parameters can be looked up using the +** [sqlite3_bind_parameter_index()] API if desired. ^The index +** for "?NNN" parameters is the value of NNN. +** ^The NNN value must be between 1 and the [sqlite3_limit()] +** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). +** +** ^The third argument is the value to bind to the parameter. +** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() +** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter +** is ignored and the end result is the same as sqlite3_bind_null(). +** +** ^(In those routines that have a fourth argument, its value is the +** number of bytes in the parameter. To be clear: the value is the +** number of bytes in the value, not the number of characters.)^ +** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() +** is negative, then the length of the string is +** the number of bytes up to the first zero terminator. +** If the fourth parameter to sqlite3_bind_blob() is negative, then +** the behavior is undefined. +** If a non-negative fourth parameter is provided to sqlite3_bind_text() +** or sqlite3_bind_text16() or sqlite3_bind_text64() then +** that parameter must be the byte offset +** where the NUL terminator would occur assuming the string were NUL +** terminated. If any NUL characters occur at byte offsets less than +** the value of the fourth parameter then the resulting string value will +** contain embedded NULs. The result of expressions involving strings +** with embedded NULs is undefined. +** +** ^The fifth argument to the BLOB and string binding interfaces +** is a destructor used to dispose of the BLOB or +** string after SQLite has finished with it. ^The destructor is called +** to dispose of the BLOB or string even if the call to bind API fails. +** ^If the fifth argument is +** the special value [SQLITE_STATIC], then SQLite assumes that the +** information is in static, unmanaged space and does not need to be freed. +** ^If the fifth argument has the value [SQLITE_TRANSIENT], then +** SQLite makes its own private copy of the data immediately, before +** the sqlite3_bind_*() routine returns. +** +** ^The sixth argument to sqlite3_bind_text64() must be one of +** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] +** to specify the encoding of the text in the third parameter. If +** the sixth argument to sqlite3_bind_text64() is not one of the +** allowed values shown above, or if the text encoding is different +** from the encoding specified by the sixth parameter, then the behavior +** is undefined. +** +** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that +** is filled with zeroes. ^A zeroblob uses a fixed amount of memory +** (just an integer to hold its size) while it is being processed. +** Zeroblobs are intended to serve as placeholders for BLOBs whose +** content is later written using +** [sqlite3_blob_open | incremental BLOB I/O] routines. +** ^A negative value for the zeroblob results in a zero-length BLOB. +** +** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer +** for the [prepared statement] or with a prepared statement for which +** [sqlite3_step()] has been called more recently than [sqlite3_reset()], +** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() +** routine is passed a [prepared statement] that has been finalized, the +** result is undefined and probably harmful. +** +** ^Bindings are not cleared by the [sqlite3_reset()] routine. +** ^Unbound parameters are interpreted as NULL. +** +** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an +** [error code] if anything goes wrong. +** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB +** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or +** [SQLITE_MAX_LENGTH]. +** ^[SQLITE_RANGE] is returned if the parameter +** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. +** +** See also: [sqlite3_bind_parameter_count()], +** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*)); +SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); +SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); +SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); +SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*), unsigned char encoding); +SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); +SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); + +/* +** CAPI3REF: Number Of SQL Parameters +** METHOD: sqlite3_stmt +** +** ^This routine can be used to find the number of [SQL parameters] +** in a [prepared statement]. SQL parameters are tokens of the +** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as +** placeholders for values that are [sqlite3_bind_blob | bound] +** to the parameters at a later time. +** +** ^(This routine actually returns the index of the largest (rightmost) +** parameter. For all forms except ?NNN, this will correspond to the +** number of unique parameters. If parameters of the ?NNN form are used, +** there may be gaps in the list.)^ +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_name()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); + +/* +** CAPI3REF: Name Of A Host Parameter +** METHOD: sqlite3_stmt +** +** ^The sqlite3_bind_parameter_name(P,N) interface returns +** the name of the N-th [SQL parameter] in the [prepared statement] P. +** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" +** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" +** respectively. +** In other words, the initial ":" or "$" or "@" or "?" +** is included as part of the name.)^ +** ^Parameters of the form "?" without a following integer have no name +** and are referred to as "nameless" or "anonymous parameters". +** +** ^The first host parameter has an index of 1, not 0. +** +** ^If the value N is out of range or if the N-th parameter is +** nameless, then NULL is returned. ^The returned string is +** always in UTF-8 encoding even if the named parameter was +** originally specified as UTF-16 in [sqlite3_prepare16()] or +** [sqlite3_prepare16_v2()]. +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_count()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); + +/* +** CAPI3REF: Index Of A Parameter With A Given Name +** METHOD: sqlite3_stmt +** +** ^Return the index of an SQL parameter given its name. ^The +** index value returned is suitable for use as the second +** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero +** is returned if no matching parameter is found. ^The parameter +** name must be given in UTF-8 even if the original statement +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_count()], and +** [sqlite3_bind_parameter_name()]. +*/ +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); + +/* +** CAPI3REF: Reset All Bindings On A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset +** the [sqlite3_bind_blob | bindings] on a [prepared statement]. +** ^Use this routine to reset all host parameters to NULL. +*/ +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); + +/* +** CAPI3REF: Number Of Columns In A Result Set +** METHOD: sqlite3_stmt +** +** ^Return the number of columns in the result set returned by the +** [prepared statement]. ^This routine returns 0 if pStmt is an SQL +** statement that does not return data (for example an [UPDATE]). +** +** See also: [sqlite3_data_count()] +*/ +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Column Names In A Result Set +** METHOD: sqlite3_stmt +** +** ^These routines return the name assigned to a particular column +** in the result set of a [SELECT] statement. ^The sqlite3_column_name() +** interface returns a pointer to a zero-terminated UTF-8 string +** and sqlite3_column_name16() returns a pointer to a zero-terminated +** UTF-16 string. ^The first parameter is the [prepared statement] +** that implements the [SELECT] statement. ^The second parameter is the +** column number. ^The leftmost column is number 0. +** +** ^The returned string pointer is valid until either the [prepared statement] +** is destroyed by [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the next call to +** sqlite3_column_name() or sqlite3_column_name16() on the same column. +** +** ^If sqlite3_malloc() fails during the processing of either routine +** (for example during a conversion from UTF-8 to UTF-16) then a +** NULL pointer is returned. +** +** ^The name of a result column is the value of the "AS" clause for +** that column, if there is an AS clause. If there is no AS clause +** then the name of the column is unspecified and may change from +** one release of SQLite to the next. +*/ +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); + +/* +** CAPI3REF: Source Of Data In A Query Result +** METHOD: sqlite3_stmt +** +** ^These routines provide a means to determine the database, table, and +** table column that is the origin of a particular result column in +** [SELECT] statement. +** ^The name of the database or table or column can be returned as +** either a UTF-8 or UTF-16 string. ^The _database_ routines return +** the database name, the _table_ routines return the table name, and +** the origin_ routines return the column name. +** ^The returned string is valid until the [prepared statement] is destroyed +** using [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the same information is requested +** again in a different encoding. +** +** ^The names returned are the original un-aliased names of the +** database, table, and column. +** +** ^The first argument to these interfaces is a [prepared statement]. +** ^These functions return information about the Nth result column returned by +** the statement, where N is the second function argument. +** ^The left-most column is column 0 for these routines. +** +** ^If the Nth column returned by the statement is an expression or +** subquery and is not a column value, then all of these functions return +** NULL. ^These routine might also return NULL if a memory allocation error +** occurs. ^Otherwise, they return the name of the attached database, table, +** or column that query result column was extracted from. +** +** ^As with all other SQLite APIs, those whose names end with "16" return +** UTF-16 encoded strings and the other functions return UTF-8. +** +** ^These APIs are only available if the library was compiled with the +** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. +** +** If two or more threads call one or more of these routines against the same +** prepared statement and column at the same time then the results are +** undefined. +** +** If two or more threads call one or more +** [sqlite3_column_database_name | column metadata interfaces] +** for the same [prepared statement] and result column +** at the same time then the results are undefined. +*/ +SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); + +/* +** CAPI3REF: Declared Datatype Of A Query Result +** METHOD: sqlite3_stmt +** +** ^(The first parameter is a [prepared statement]. +** If this statement is a [SELECT] statement and the Nth column of the +** returned result set of that [SELECT] is a table column (not an +** expression or subquery) then the declared type of the table +** column is returned.)^ ^If the Nth column of the result set is an +** expression or subquery, then a NULL pointer is returned. +** ^The returned string is always UTF-8 encoded. +** +** ^(For example, given the database schema: +** +** CREATE TABLE t1(c1 VARIANT); +** +** and the following statement to be compiled: +** +** SELECT c1 + 1, c1 FROM t1; +** +** this routine would return the string "VARIANT" for the second result +** column (i==1), and a NULL pointer for the first result column (i==0).)^ +** +** ^SQLite uses dynamic run-time typing. ^So just because a column +** is declared to contain a particular type does not mean that the +** data stored in that column is of the declared type. SQLite is +** strongly typed, but the typing is dynamic not static. ^Type +** is associated with individual values, not with the containers +** used to hold those values. +*/ +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); + +/* +** CAPI3REF: Evaluate An SQL Statement +** METHOD: sqlite3_stmt +** +** After a [prepared statement] has been prepared using either +** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function +** must be called one or more times to evaluate the statement. +** +** The details of the behavior of the sqlite3_step() interface depend +** on whether the statement was prepared using the newer "v2" interface +** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy +** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "v2" interface is recommended for new applications but the legacy +** interface will continue to be supported. +** +** ^In the legacy interface, the return value will be either [SQLITE_BUSY], +** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. +** ^With the "v2" interface, any of the other [result codes] or +** [extended result codes] might be returned as well. +** +** ^[SQLITE_BUSY] means that the database engine was unable to acquire the +** database locks it needs to do its job. ^If the statement is a [COMMIT] +** or occurs outside of an explicit transaction, then you can retry the +** statement. If the statement is not a [COMMIT] and occurs within an +** explicit transaction then you should rollback the transaction before +** continuing. +** +** ^[SQLITE_DONE] means that the statement has finished executing +** successfully. sqlite3_step() should not be called again on this virtual +** machine without first calling [sqlite3_reset()] to reset the virtual +** machine back to its initial state. +** +** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] +** is returned each time a new row of data is ready for processing by the +** caller. The values may be accessed using the [column access functions]. +** sqlite3_step() is called again to retrieve the next row of data. +** +** ^[SQLITE_ERROR] means that a run-time error (such as a constraint +** violation) has occurred. sqlite3_step() should not be called again on +** the VM. More information may be found by calling [sqlite3_errmsg()]. +** ^With the legacy interface, a more specific error code (for example, +** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) +** can be obtained by calling [sqlite3_reset()] on the +** [prepared statement]. ^In the "v2" interface, +** the more specific error code is returned directly by sqlite3_step(). +** +** [SQLITE_MISUSE] means that the this routine was called inappropriately. +** Perhaps it was called on a [prepared statement] that has +** already been [sqlite3_finalize | finalized] or on one that had +** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could +** be the case that the same database connection is being used by two or +** more threads at the same moment in time. +** +** For all versions of SQLite up to and including 3.6.23.1, a call to +** [sqlite3_reset()] was required after sqlite3_step() returned anything +** other than [SQLITE_ROW] before any subsequent invocation of +** sqlite3_step(). Failure to reset the prepared statement using +** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step() began +** calling [sqlite3_reset()] automatically in this circumstance rather +** than returning [SQLITE_MISUSE]. This is not considered a compatibility +** break because any application that ever receives an SQLITE_MISUSE error +** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option +** can be used to restore the legacy behavior. +** +** Goofy Interface Alert: In the legacy interface, the sqlite3_step() +** API always returns a generic error code, [SQLITE_ERROR], following any +** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call +** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the +** specific [error codes] that better describes the error. +** We admit that this is a goofy design. The problem has been fixed +** with the "v2" interface. If you prepare all of your SQL statements +** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, +** then the more specific [error codes] are returned directly +** by sqlite3_step(). The use of the "v2" interface is recommended. +*/ +SQLITE_API int sqlite3_step(sqlite3_stmt*); + +/* +** CAPI3REF: Number of columns in a result set +** METHOD: sqlite3_stmt +** +** ^The sqlite3_data_count(P) interface returns the number of columns in the +** current row of the result set of [prepared statement] P. +** ^If prepared statement P does not have results ready to return +** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of +** interfaces) then sqlite3_data_count(P) returns 0. +** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. +** ^The sqlite3_data_count(P) routine returns 0 if the previous call to +** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) +** will return non-zero if previous call to [sqlite3_step](P) returned +** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] +** where it always returns zero since each step of that multi-step +** pragma returns 0 columns of data. +** +** See also: [sqlite3_column_count()] +*/ +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Fundamental Datatypes +** KEYWORDS: SQLITE_TEXT +** +** ^(Every value in SQLite has one of five fundamental datatypes: +** +**
    +**
  • 64-bit signed integer +**
  • 64-bit IEEE floating point number +**
  • string +**
  • BLOB +**
  • NULL +**
)^ +** +** These constants are codes for each of those types. +** +** Note that the SQLITE_TEXT constant was also used in SQLite version 2 +** for a completely different meaning. Software that links against both +** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not +** SQLITE_TEXT. +*/ +#define SQLITE_INTEGER 1 +#define SQLITE_FLOAT 2 +#define SQLITE_BLOB 4 +#define SQLITE_NULL 5 +#ifdef SQLITE_TEXT +# undef SQLITE_TEXT +#else +# define SQLITE_TEXT 3 +#endif +#define SQLITE3_TEXT 3 + +/* +** CAPI3REF: Result Values From A Query +** KEYWORDS: {column access functions} +** METHOD: sqlite3_stmt +** +** ^These routines return information about a single column of the current +** result row of a query. ^In every case the first argument is a pointer +** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] +** that was returned from [sqlite3_prepare_v2()] or one of its variants) +** and the second argument is the index of the column for which information +** should be returned. ^The leftmost column of the result set has the index 0. +** ^The number of columns in the result can be determined using +** [sqlite3_column_count()]. +** +** If the SQL statement does not currently point to a valid row, or if the +** column index is out of range, the result is undefined. +** These routines may only be called when the most recent call to +** [sqlite3_step()] has returned [SQLITE_ROW] and neither +** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. +** If any of these routines are called after [sqlite3_reset()] or +** [sqlite3_finalize()] or after [sqlite3_step()] has returned +** something other than [SQLITE_ROW], the results are undefined. +** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] +** are called from a different thread while any of these routines +** are pending, then the results are undefined. +** +** ^The sqlite3_column_type() routine returns the +** [SQLITE_INTEGER | datatype code] for the initial data type +** of the result column. ^The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value +** returned by sqlite3_column_type() is only meaningful if no type +** conversions have occurred as described below. After a type conversion, +** the value returned by sqlite3_column_type() is undefined. Future +** versions of SQLite may change the behavior of sqlite3_column_type() +** following a type conversion. +** +** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() +** routine returns the number of bytes in that BLOB or string. +** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts +** the string to UTF-8 and then returns the number of bytes. +** ^If the result is a numeric value then sqlite3_column_bytes() uses +** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns +** the number of bytes in that string. +** ^If the result is NULL, then sqlite3_column_bytes() returns zero. +** +** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() +** routine returns the number of bytes in that BLOB or string. +** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts +** the string to UTF-16 and then returns the number of bytes. +** ^If the result is a numeric value then sqlite3_column_bytes16() uses +** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns +** the number of bytes in that string. +** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. +** +** ^The values returned by [sqlite3_column_bytes()] and +** [sqlite3_column_bytes16()] do not include the zero terminators at the end +** of the string. ^For clarity: the values returned by +** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of +** bytes in the string, not the number of characters. +** +** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), +** even empty strings, are always zero-terminated. ^The return +** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. +** +** Warning: ^The object returned by [sqlite3_column_value()] is an +** [unprotected sqlite3_value] object. In a multithreaded environment, +** an unprotected sqlite3_value object may only be used safely with +** [sqlite3_bind_value()] and [sqlite3_result_value()]. +** If the [unprotected sqlite3_value] object returned by +** [sqlite3_column_value()] is used in any other way, including calls +** to routines like [sqlite3_value_int()], [sqlite3_value_text()], +** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** +** These routines attempt to convert the value where appropriate. ^For +** example, if the internal representation is FLOAT and a text result +** is requested, [sqlite3_snprintf()] is used internally to perform the +** conversion automatically. ^(The following table details the conversions +** that are applied: +** +**
+** +**
Internal
Type
Requested
Type
Conversion +** +**
NULL INTEGER Result is 0 +**
NULL FLOAT Result is 0.0 +**
NULL TEXT Result is a NULL pointer +**
NULL BLOB Result is a NULL pointer +**
INTEGER FLOAT Convert from integer to float +**
INTEGER TEXT ASCII rendering of the integer +**
INTEGER BLOB Same as INTEGER->TEXT +**
FLOAT INTEGER [CAST] to INTEGER +**
FLOAT TEXT ASCII rendering of the float +**
FLOAT BLOB [CAST] to BLOB +**
TEXT INTEGER [CAST] to INTEGER +**
TEXT FLOAT [CAST] to REAL +**
TEXT BLOB No change +**
BLOB INTEGER [CAST] to INTEGER +**
BLOB FLOAT [CAST] to REAL +**
BLOB TEXT Add a zero terminator if needed +**
+**
)^ +** +** Note that when type conversions occur, pointers returned by prior +** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or +** sqlite3_column_text16() may be invalidated. +** Type conversions and pointer invalidations might occur +** in the following cases: +** +**
    +**
  • The initial content is a BLOB and sqlite3_column_text() or +** sqlite3_column_text16() is called. A zero-terminator might +** need to be added to the string.
  • +**
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or +** sqlite3_column_text16() is called. The content must be converted +** to UTF-16.
  • +**
  • The initial content is UTF-16 text and sqlite3_column_bytes() or +** sqlite3_column_text() is called. The content must be converted +** to UTF-8.
  • +**
+** +** ^Conversions between UTF-16be and UTF-16le are always done in place and do +** not invalidate a prior pointer, though of course the content of the buffer +** that the prior pointer references will have been modified. Other kinds +** of conversion are done in place when it is possible, but sometimes they +** are not possible and in those cases prior pointers are invalidated. +** +** The safest policy is to invoke these routines +** in one of the following ways: +** +**
    +**
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • +**
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • +**
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • +**
+** +** In other words, you should call sqlite3_column_text(), +** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result +** into the desired format, then invoke sqlite3_column_bytes() or +** sqlite3_column_bytes16() to find the size of the result. Do not mix calls +** to sqlite3_column_text() or sqlite3_column_blob() with calls to +** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() +** with calls to sqlite3_column_bytes(). +** +** ^The pointers returned are valid until a type conversion occurs as +** described above, or until [sqlite3_step()] or [sqlite3_reset()] or +** [sqlite3_finalize()] is called. ^The memory space used to hold strings +** and BLOBs is freed automatically. Do not pass the pointers returned +** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into +** [sqlite3_free()]. +** +** ^(If a memory allocation error occurs during the evaluation of any +** of these routines, a default value is returned. The default value +** is either the integer 0, the floating point number 0.0, or a NULL +** pointer. Subsequent calls to [sqlite3_errcode()] will return +** [SQLITE_NOMEM].)^ +*/ +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); + +/* +** CAPI3REF: Destroy A Prepared Statement Object +** DESTRUCTOR: sqlite3_stmt +** +** ^The sqlite3_finalize() function is called to delete a [prepared statement]. +** ^If the most recent evaluation of the statement encountered no errors +** or if the statement is never been evaluated, then sqlite3_finalize() returns +** SQLITE_OK. ^If the most recent evaluation of statement S failed, then +** sqlite3_finalize(S) returns the appropriate [error code] or +** [extended error code]. +** +** ^The sqlite3_finalize(S) routine can be called at any point during +** the life cycle of [prepared statement] S: +** before statement S is ever evaluated, after +** one or more calls to [sqlite3_reset()], or after any call +** to [sqlite3_step()] regardless of whether or not the statement has +** completed execution. +** +** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. +** +** The application must finalize every [prepared statement] in order to avoid +** resource leaks. It is a grievous error for the application to try to use +** a prepared statement after it has been finalized. Any use of a prepared +** statement after it has been finalized can result in undefined and +** undesirable behavior such as segfaults and heap corruption. +*/ +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Reset A Prepared Statement Object +** METHOD: sqlite3_stmt +** +** The sqlite3_reset() function is called to reset a [prepared statement] +** object back to its initial state, ready to be re-executed. +** ^Any SQL statement variables that had values bound to them using +** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. +** Use [sqlite3_clear_bindings()] to reset the bindings. +** +** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S +** back to the beginning of its program. +** +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], +** or if [sqlite3_step(S)] has never before been called on S, +** then [sqlite3_reset(S)] returns [SQLITE_OK]. +** +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S indicated an error, then +** [sqlite3_reset(S)] returns an appropriate [error code]. +** +** ^The [sqlite3_reset(S)] interface does not change the values +** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. +*/ +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Create Or Redefine SQL Functions +** KEYWORDS: {function creation routines} +** KEYWORDS: {application-defined SQL function} +** KEYWORDS: {application-defined SQL functions} +** METHOD: sqlite3 +** +** ^These functions (collectively known as "function creation routines") +** are used to add SQL functions or aggregates or to redefine the behavior +** of existing SQL functions or aggregates. The only differences between +** these routines are the text encoding expected for +** the second parameter (the name of the function being created) +** and the presence or absence of a destructor callback for +** the application data pointer. +** +** ^The first parameter is the [database connection] to which the SQL +** function is to be added. ^If an application uses more than one database +** connection then application-defined SQL functions must be added +** to each database connection separately. +** +** ^The second parameter is the name of the SQL function to be created or +** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 +** representation, exclusive of the zero-terminator. ^Note that the name +** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. +** ^Any attempt to create a function with a longer name +** will result in [SQLITE_MISUSE] being returned. +** +** ^The third parameter (nArg) +** is the number of arguments that the SQL function or +** aggregate takes. ^If this parameter is -1, then the SQL function or +** aggregate may take any number of arguments between 0 and the limit +** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third +** parameter is less than -1 or greater than 127 then the behavior is +** undefined. +** +** ^The fourth parameter, eTextRep, specifies what +** [SQLITE_UTF8 | text encoding] this SQL function prefers for +** its parameters. The application should set this parameter to +** [SQLITE_UTF16LE] if the function implementation invokes +** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the +** implementation invokes [sqlite3_value_text16be()] on an input, or +** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] +** otherwise. ^The same SQL function may be registered multiple times using +** different preferred text encodings, with different implementations for +** each encoding. +** ^When multiple implementations of the same function are available, SQLite +** will pick the one that involves the least amount of data conversion. +** +** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] +** to signal that the function will always return the same result given +** the same inputs within a single SQL statement. Most SQL functions are +** deterministic. The built-in [random()] SQL function is an example of a +** function that is not deterministic. The SQLite query planner is able to +** perform additional optimizations on deterministic functions, so use +** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. +** +** ^(The fifth parameter is an arbitrary pointer. The implementation of the +** function can gain access to this pointer using [sqlite3_user_data()].)^ +** +** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** pointers to C-language functions that implement the SQL function or +** aggregate. ^A scalar SQL function requires an implementation of the xFunc +** callback only; NULL pointers must be passed as the xStep and xFinal +** parameters. ^An aggregate SQL function requires an implementation of xStep +** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing +** SQL function or aggregate, pass NULL pointers for all three function +** callbacks. +** +** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, +** then it is destructor for the application data pointer. +** The destructor is invoked when the function is deleted, either by being +** overloaded or when the database connection closes.)^ +** ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. +** ^When the destructor callback of the tenth parameter is invoked, it +** is passed a single argument which is a copy of the application data +** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** +** ^It is permitted to register multiple implementations of the same +** functions with the same name but with either differing numbers of +** arguments or differing preferred text encodings. ^SQLite will use +** the implementation that most closely matches the way in which the +** SQL function is used. ^A function implementation with a non-negative +** nArg parameter is a better match than a function implementation with +** a negative nArg. ^A function where the preferred text encoding +** matches the database encoding is a better +** match than a function where the encoding is different. +** ^A function where the encoding difference is between UTF16le and UTF16be +** is a closer match than a function where the encoding difference is +** between UTF8 and UTF16. +** +** ^Built-in functions may be overloaded by new application-defined functions. +** +** ^An application-defined function is permitted to call other +** SQLite interfaces. However, such calls must not +** close the database connection nor finalize or reset the prepared +** statement in which the function is running. +*/ +SQLITE_API int sqlite3_create_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); +SQLITE_API int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); +SQLITE_API int sqlite3_create_function_v2( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*) +); + +/* +** CAPI3REF: Text Encodings +** +** These constant define integer codes that represent the various +** text encodings supported by SQLite. +*/ +#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ +#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ +#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ +#define SQLITE_UTF16 4 /* Use native byte order */ +#define SQLITE_ANY 5 /* Deprecated */ +#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ + +/* +** CAPI3REF: Function Flags +** +** These constants may be ORed together with the +** [SQLITE_UTF8 | preferred text encoding] as the fourth argument +** to [sqlite3_create_function()], [sqlite3_create_function16()], or +** [sqlite3_create_function_v2()]. +*/ +#define SQLITE_DETERMINISTIC 0x800 + +/* +** CAPI3REF: Deprecated Functions +** DEPRECATED +** +** These functions are [deprecated]. In order to maintain +** backwards compatibility with older code, these functions continue +** to be supported. However, new applications should avoid +** the use of these functions. To encourage programmers to avoid +** these functions, we will not explain what they do. +*/ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); +SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), + void*,sqlite3_int64); +#endif + +/* +** CAPI3REF: Obtaining SQL Values +** METHOD: sqlite3_value +** +** The C-language implementation of SQL functions and aggregates uses +** this set of interface routines to access the parameter values on +** the function or aggregate. +** +** The xFunc (for scalar functions) or xStep (for aggregates) parameters +** to [sqlite3_create_function()] and [sqlite3_create_function16()] +** define callbacks that implement the SQL functions and aggregates. +** The 3rd parameter to these callbacks is an array of pointers to +** [protected sqlite3_value] objects. There is one [sqlite3_value] object for +** each parameter to the SQL function. These routines are used to +** extract values from the [sqlite3_value] objects. +** +** These routines work only with [protected sqlite3_value] objects. +** Any attempt to use these routines on an [unprotected sqlite3_value] +** object results in undefined behavior. +** +** ^These routines work just like the corresponding [column access functions] +** except that these routines take a single [protected sqlite3_value] object +** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. +** +** ^The sqlite3_value_text16() interface extracts a UTF-16 string +** in the native byte-order of the host machine. ^The +** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces +** extract UTF-16 strings as big-endian and little-endian respectively. +** +** ^(The sqlite3_value_numeric_type() interface attempts to apply +** numeric affinity to the value. This means that an attempt is +** made to convert the value to an integer or floating point. If +** such a conversion is possible without loss of information (in other +** words, if the value is a string that looks like a number) +** then the conversion is performed. Otherwise no conversion occurs. +** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ +** +** Please pay particular attention to the fact that the pointer returned +** from [sqlite3_value_blob()], [sqlite3_value_text()], or +** [sqlite3_value_text16()] can be invalidated by a subsequent call to +** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], +** or [sqlite3_value_text16()]. +** +** These routines must be called from the same thread as +** the SQL function that supplied the [sqlite3_value*] parameters. +*/ +SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); +SQLITE_API double sqlite3_value_double(sqlite3_value*); +SQLITE_API int sqlite3_value_int(sqlite3_value*); +SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_type(sqlite3_value*); +SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); + +/* +** CAPI3REF: Finding The Subtype Of SQL Values +** METHOD: sqlite3_value +** +** The sqlite3_value_subtype(V) function returns the subtype for +** an [application-defined SQL function] argument V. The subtype +** information can be used to pass a limited amount of context from +** one SQL function to another. Use the [sqlite3_result_subtype()] +** routine to set the subtype for the return value of an SQL function. +** +** SQLite makes no use of subtype itself. It merely passes the subtype +** from the result of one [application-defined SQL function] into the +** input of another. +*/ +SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); + +/* +** CAPI3REF: Copy And Free SQL Values +** METHOD: sqlite3_value +** +** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] +** object D and returns a pointer to that copy. ^The [sqlite3_value] returned +** is a [protected sqlite3_value] object even if the input is not. +** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a +** memory allocation fails. +** +** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object +** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer +** then sqlite3_value_free(V) is a harmless no-op. +*/ +SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*); +SQLITE_API void sqlite3_value_free(sqlite3_value*); + +/* +** CAPI3REF: Obtain Aggregate Function Context +** METHOD: sqlite3_context +** +** Implementations of aggregate SQL functions use this +** routine to allocate memory for storing their state. +** +** ^The first time the sqlite3_aggregate_context(C,N) routine is called +** for a particular aggregate function, SQLite +** allocates N of memory, zeroes out that memory, and returns a pointer +** to the new memory. ^On second and subsequent calls to +** sqlite3_aggregate_context() for the same aggregate function instance, +** the same buffer is returned. Sqlite3_aggregate_context() is normally +** called once for each invocation of the xStep callback and then one +** last time when the xFinal callback is invoked. ^(When no rows match +** an aggregate query, the xStep() callback of the aggregate function +** implementation is never called and xFinal() is called exactly once. +** In those cases, sqlite3_aggregate_context() might be called for the +** first time from within xFinal().)^ +** +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer +** when first called if N is less than or equal to zero or if a memory +** allocate error occurs. +** +** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is +** determined by the N parameter on first successful call. Changing the +** value of N in subsequent call to sqlite3_aggregate_context() within +** the same aggregate function instance will not resize the memory +** allocation.)^ Within the xFinal callback, it is customary to set +** N=0 in calls to sqlite3_aggregate_context(C,N) so that no +** pointless memory allocations occur. +** +** ^SQLite automatically frees the memory allocated by +** sqlite3_aggregate_context() when the aggregate query concludes. +** +** The first parameter must be a copy of the +** [sqlite3_context | SQL function context] that is the first parameter +** to the xStep or xFinal callback routine that implements the aggregate +** function. +** +** This routine must be called from the same thread in which +** the aggregate SQL function is running. +*/ +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); + +/* +** CAPI3REF: User Data For Functions +** METHOD: sqlite3_context +** +** ^The sqlite3_user_data() interface returns a copy of +** the pointer that was the pUserData parameter (the 5th parameter) +** of the [sqlite3_create_function()] +** and [sqlite3_create_function16()] routines that originally +** registered the application defined function. +** +** This routine must be called from the same thread in which +** the application-defined function is running. +*/ +SQLITE_API void *sqlite3_user_data(sqlite3_context*); + +/* +** CAPI3REF: Database Connection For Functions +** METHOD: sqlite3_context +** +** ^The sqlite3_context_db_handle() interface returns a copy of +** the pointer to the [database connection] (the 1st parameter) +** of the [sqlite3_create_function()] +** and [sqlite3_create_function16()] routines that originally +** registered the application defined function. +*/ +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); + +/* +** CAPI3REF: Function Auxiliary Data +** METHOD: sqlite3_context +** +** These functions may be used by (non-aggregate) SQL functions to +** associate metadata with argument values. If the same value is passed to +** multiple invocations of the same SQL function during query execution, under +** some circumstances the associated metadata may be preserved. An example +** of where this might be useful is in a regular-expression matching +** function. The compiled version of the regular expression can be stored as +** metadata associated with the pattern string. +** Then as long as the pattern string remains the same, +** the compiled regular expression can be reused on multiple +** invocations of the same function. +** +** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata() function with the Nth argument +** value to the application-defined function. ^If there is no metadata +** associated with the function argument, this sqlite3_get_auxdata() interface +** returns a NULL pointer. +** +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th +** argument of the application-defined function. ^Subsequent +** calls to sqlite3_get_auxdata(C,N) return P from the most recent +** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or +** NULL if the metadata has been discarded. +** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, +** SQLite will invoke the destructor function X with parameter P exactly +** once, when the metadata is discarded. +** SQLite is free to discard the metadata at any time, including:
    +**
  • ^(when the corresponding function parameter changes)^, or +**
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement)^, or +**
  • ^(when sqlite3_set_auxdata() is invoked again on the same +** parameter)^, or +**
  • ^(during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs.)^
+** +** Note the last bullet in particular. The destructor X in +** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the +** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() +** should be called near the end of the function implementation and the +** function implementation should not make any use of P after +** sqlite3_set_auxdata() has been called. +** +** ^(In practice, metadata is preserved between function calls for +** function parameters that are compile-time constants, including literal +** values and [parameters] and expressions composed from the same.)^ +** +** These routines must be called from the same thread in which +** the SQL function is running. +*/ +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); +SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); + + +/* +** CAPI3REF: Constants Defining Special Destructor Behavior +** +** These are special values for the destructor that is passed in as the +** final argument to routines like [sqlite3_result_blob()]. ^If the destructor +** argument is SQLITE_STATIC, it means that the content pointer is constant +** and will never change. It does not need to be destroyed. ^The +** SQLITE_TRANSIENT value means that the content will likely change in +** the near future and that SQLite should make its own private copy of +** the content before returning. +** +** The typedef is necessary to work around problems in certain +** C++ compilers. +*/ +typedef void (*sqlite3_destructor_type)(void*); +#define SQLITE_STATIC ((sqlite3_destructor_type)0) +#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) + +/* +** CAPI3REF: Setting The Result Of An SQL Function +** METHOD: sqlite3_context +** +** These routines are used by the xFunc or xFinal callbacks that +** implement SQL functions and aggregates. See +** [sqlite3_create_function()] and [sqlite3_create_function16()] +** for additional information. +** +** These functions work very much like the [parameter binding] family of +** functions used to bind values to host parameters in prepared statements. +** Refer to the [SQL parameter] documentation for additional information. +** +** ^The sqlite3_result_blob() interface sets the result from +** an application-defined function to be the BLOB whose content is pointed +** to by the second parameter and which is N bytes long where N is the +** third parameter. +** +** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) +** interfaces set the result of the application-defined function to be +** a BLOB containing all zero bytes and N bytes in size. +** +** ^The sqlite3_result_double() interface sets the result from +** an application-defined function to be a floating point value specified +** by its 2nd argument. +** +** ^The sqlite3_result_error() and sqlite3_result_error16() functions +** cause the implemented SQL function to throw an exception. +** ^SQLite uses the string pointed to by the +** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() +** as the text of an error message. ^SQLite interprets the error +** message string from sqlite3_result_error() as UTF-8. ^SQLite +** interprets the string from sqlite3_result_error16() as UTF-16 in native +** byte order. ^If the third parameter to sqlite3_result_error() +** or sqlite3_result_error16() is negative then SQLite takes as the error +** message all text up through the first zero character. +** ^If the third parameter to sqlite3_result_error() or +** sqlite3_result_error16() is non-negative then SQLite takes that many +** bytes (not characters) from the 2nd parameter as the error message. +** ^The sqlite3_result_error() and sqlite3_result_error16() +** routines make a private copy of the error message text before +** they return. Hence, the calling function can deallocate or +** modify the text after they return without harm. +** ^The sqlite3_result_error_code() function changes the error code +** returned by SQLite as a result of an error in a function. ^By default, +** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() +** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. +** +** ^The sqlite3_result_error_toobig() interface causes SQLite to throw an +** error indicating that a string or BLOB is too long to represent. +** +** ^The sqlite3_result_error_nomem() interface causes SQLite to throw an +** error indicating that a memory allocation failed. +** +** ^The sqlite3_result_int() interface sets the return value +** of the application-defined function to be the 32-bit signed integer +** value given in the 2nd argument. +** ^The sqlite3_result_int64() interface sets the return value +** of the application-defined function to be the 64-bit signed integer +** value given in the 2nd argument. +** +** ^The sqlite3_result_null() interface sets the return value +** of the application-defined function to be NULL. +** +** ^The sqlite3_result_text(), sqlite3_result_text16(), +** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces +** set the return value of the application-defined function to be +** a text string which is represented as UTF-8, UTF-16 native byte order, +** UTF-16 little endian, or UTF-16 big endian, respectively. +** ^The sqlite3_result_text64() interface sets the return value of an +** application-defined function to be a text string in an encoding +** specified by the fifth (and last) parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** ^SQLite takes the text result from the application from +** the 2nd parameter of the sqlite3_result_text* interfaces. +** ^If the 3rd parameter to the sqlite3_result_text* interfaces +** is negative, then SQLite takes result text from the 2nd parameter +** through the first zero character. +** ^If the 3rd parameter to the sqlite3_result_text* interfaces +** is non-negative, then as many bytes (not characters) of the text +** pointed to by the 2nd parameter are taken as the application-defined +** function result. If the 3rd parameter is non-negative, then it +** must be the byte offset into the string where the NUL terminator would +** appear if the string where NUL terminated. If any NUL characters occur +** in the string at a byte offset that is less than the value of the 3rd +** parameter, then the resulting string will contain embedded NULs and the +** result of expressions operating on strings with embedded NULs is undefined. +** ^If the 4th parameter to the sqlite3_result_text* interfaces +** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that +** function as the destructor on the text or BLOB result when it has +** finished using that result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces or to +** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite +** assumes that the text or BLOB result is in constant space and does not +** copy the content of the parameter nor call a destructor on the content +** when it has finished using that result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces +** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT +** then SQLite makes a copy of the result into space obtained from +** from [sqlite3_malloc()] before it returns. +** +** ^The sqlite3_result_value() interface sets the result of +** the application-defined function to be a copy of the +** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The +** sqlite3_result_value() interface makes a copy of the [sqlite3_value] +** so that the [sqlite3_value] specified in the parameter may change or +** be deallocated after sqlite3_result_value() returns without harm. +** ^A [protected sqlite3_value] object may always be used where an +** [unprotected sqlite3_value] object is required, so either +** kind of [sqlite3_value] object can be used with this interface. +** +** If these routines are called from within the different thread +** than the one containing the application-defined function that received +** the [sqlite3_context] pointer, the results are undefined. +*/ +SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, + sqlite3_uint64,void(*)(void*)); +SQLITE_API void sqlite3_result_double(sqlite3_context*, double); +SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); +SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); +SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); +SQLITE_API void sqlite3_result_null(sqlite3_context*); +SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*), unsigned char encoding); +SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); +SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); + + +/* +** CAPI3REF: Setting The Subtype Of An SQL Function +** METHOD: sqlite3_context +** +** The sqlite3_result_subtype(C,T) function causes the subtype of +** the result from the [application-defined SQL function] with +** [sqlite3_context] C to be the value T. Only the lower 8 bits +** of the subtype T are preserved in current versions of SQLite; +** higher order bits are discarded. +** The number of subtype bytes preserved by SQLite might increase +** in future releases of SQLite. +*/ +SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); + +/* +** CAPI3REF: Define New Collating Sequences +** METHOD: sqlite3 +** +** ^These functions add, remove, or modify a [collation] associated +** with the [database connection] specified as the first argument. +** +** ^The name of the collation is a UTF-8 string +** for sqlite3_create_collation() and sqlite3_create_collation_v2() +** and a UTF-16 string in native byte order for sqlite3_create_collation16(). +** ^Collation names that compare equal according to [sqlite3_strnicmp()] are +** considered to be the same name. +** +** ^(The third argument (eTextRep) must be one of the constants: +**
    +**
  • [SQLITE_UTF8], +**
  • [SQLITE_UTF16LE], +**
  • [SQLITE_UTF16BE], +**
  • [SQLITE_UTF16], or +**
  • [SQLITE_UTF16_ALIGNED]. +**
)^ +** ^The eTextRep argument determines the encoding of strings passed +** to the collating function callback, xCallback. +** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep +** force strings to be UTF16 with native byte order. +** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin +** on an even byte address. +** +** ^The fourth argument, pArg, is an application data pointer that is passed +** through as the first argument to the collating function callback. +** +** ^The fifth argument, xCallback, is a pointer to the collating function. +** ^Multiple collating functions can be registered using the same name but +** with different eTextRep parameters and SQLite will use whichever +** function requires the least amount of data transformation. +** ^If the xCallback argument is NULL then the collating function is +** deleted. ^When all collating functions having the same name are deleted, +** that collation is no longer usable. +** +** ^The collating function callback is invoked with a copy of the pArg +** application data pointer and with two strings in the encoding specified +** by the eTextRep argument. The collating function must return an +** integer that is negative, zero, or positive +** if the first string is less than, equal to, or greater than the second, +** respectively. A collating function must always return the same answer +** given the same inputs. If two or more collating functions are registered +** to the same collation name (using different eTextRep values) then all +** must give an equivalent answer when invoked with equivalent strings. +** The collating function must obey the following properties for all +** strings A, B, and C: +** +**
    +**
  1. If A==B then B==A. +**
  2. If A==B and B==C then A==C. +**
  3. If A<B THEN B>A. +**
  4. If A<B and B<C then A<C. +**
+** +** If a collating function fails any of the above constraints and that +** collating function is registered and used, then the behavior of SQLite +** is undefined. +** +** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() +** with the addition that the xDestroy callback is invoked on pArg when +** the collating function is deleted. +** ^Collating functions are deleted when they are overridden by later +** calls to the collation creation functions or when the +** [database connection] is closed using [sqlite3_close()]. +** +** ^The xDestroy callback is not called if the +** sqlite3_create_collation_v2() function fails. Applications that invoke +** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should +** check the return code and dispose of the application data pointer +** themselves rather than expecting SQLite to deal with it for them. +** This is different from every other SQLite interface. The inconsistency +** is unfortunate but cannot be changed without breaking backwards +** compatibility. +** +** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. +*/ +SQLITE_API int sqlite3_create_collation( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); +SQLITE_API int sqlite3_create_collation_v2( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDestroy)(void*) +); +SQLITE_API int sqlite3_create_collation16( + sqlite3*, + const void *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); + +/* +** CAPI3REF: Collation Needed Callbacks +** METHOD: sqlite3 +** +** ^To avoid having to register all collation sequences before a database +** can be used, a single callback function may be registered with the +** [database connection] to be invoked whenever an undefined collation +** sequence is required. +** +** ^If the function is registered using the sqlite3_collation_needed() API, +** then it is passed the names of undefined collation sequences as strings +** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, +** the names are passed as UTF-16 in machine native byte order. +** ^A call to either function replaces the existing collation-needed callback. +** +** ^(When the callback is invoked, the first argument passed is a copy +** of the second argument to sqlite3_collation_needed() or +** sqlite3_collation_needed16(). The second argument is the database +** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE], indicating the most desirable form of the collation +** sequence function required. The fourth parameter is the name of the +** required collation sequence.)^ +** +** The callback function should register the desired collation using +** [sqlite3_create_collation()], [sqlite3_create_collation16()], or +** [sqlite3_create_collation_v2()]. +*/ +SQLITE_API int sqlite3_collation_needed( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const char*) +); +SQLITE_API int sqlite3_collation_needed16( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const void*) +); + +#ifdef SQLITE_HAS_CODEC +/* +** Specify the key for an encrypted database. This routine should be +** called right after sqlite3_open(). +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_key( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The key */ +); +SQLITE_API int sqlite3_key_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The key */ +); + +/* +** Change the key on an open database. If the current database is not +** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the +** database is decrypted. +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_rekey( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The new key */ +); +SQLITE_API int sqlite3_rekey_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The new key */ +); + +/* +** Specify the activation key for a SEE database. Unless +** activated, none of the SEE routines will work. +*/ +SQLITE_API void sqlite3_activate_see( + const char *zPassPhrase /* Activation phrase */ +); +#endif + +#ifdef SQLITE_ENABLE_CEROD +/* +** Specify the activation key for a CEROD database. Unless +** activated, none of the CEROD routines will work. +*/ +SQLITE_API void sqlite3_activate_cerod( + const char *zPassPhrase /* Activation phrase */ +); +#endif + +/* +** CAPI3REF: Suspend Execution For A Short Time +** +** The sqlite3_sleep() function causes the current thread to suspend execution +** for at least a number of milliseconds specified in its parameter. +** +** If the operating system does not support sleep requests with +** millisecond time resolution, then the time will be rounded up to +** the nearest second. The number of milliseconds of sleep actually +** requested from the operating system is returned. +** +** ^SQLite implements this interface by calling the xSleep() +** method of the default [sqlite3_vfs] object. If the xSleep() method +** of the default VFS is not implemented correctly, or not implemented at +** all, then the behavior of sqlite3_sleep() may deviate from the description +** in the previous paragraphs. +*/ +SQLITE_API int sqlite3_sleep(int); + +/* +** CAPI3REF: Name Of The Folder Holding Temporary Files +** +** ^(If this global variable is made to point to a string which is +** the name of a folder (a.k.a. directory), then all temporary files +** created by SQLite when using a built-in [sqlite3_vfs | VFS] +** will be placed in that directory.)^ ^If this variable +** is a NULL pointer, then SQLite performs a search for an appropriate +** temporary file directory. +** +** Applications are strongly discouraged from using this global variable. +** It is required to set a temporary folder on Windows Runtime (WinRT). +** But for all other platforms, it is highly recommended that applications +** neither read nor write this variable. This global variable is a relic +** that exists for backwards compatibility of legacy applications and should +** be avoided in new projects. +** +** It is not safe to read or modify this variable in more than one +** thread at a time. It is not safe to read or modify this variable +** if a [database connection] is being used at the same time in a separate +** thread. +** It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been called and that this variable remain unchanged +** thereafter. +** +** ^The [temp_store_directory pragma] may modify this variable and cause +** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, +** the [temp_store_directory pragma] always assumes that any string +** that this variable points to is held in memory obtained from +** [sqlite3_malloc] and the pragma may attempt to free that memory +** using [sqlite3_free]. +** Hence, if this variable is modified directly, either it should be +** made NULL or made to point to memory obtained from [sqlite3_malloc] +** or else the use of the [temp_store_directory pragma] should be avoided. +** Except when requested by the [temp_store_directory pragma], SQLite +** does not free the memory that sqlite3_temp_directory points to. If +** the application wants that memory to be freed, it must do +** so itself, taking care to only do so after all [database connection] +** objects have been destroyed. +** +** Note to Windows Runtime users: The temporary directory must be set +** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various +** features that require the use of temporary files may fail. Here is an +** example of how to do this using C++ with the Windows Runtime: +** +**
+** LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
+**       TemporaryFolder->Path->Data();
+** char zPathBuf[MAX_PATH + 1];
+** memset(zPathBuf, 0, sizeof(zPathBuf));
+** WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
+**       NULL, NULL);
+** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
+** 
+*/ +SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory; + +/* +** CAPI3REF: Name Of The Folder Holding Database Files +** +** ^(If this global variable is made to point to a string which is +** the name of a folder (a.k.a. directory), then all database files +** specified with a relative pathname and created or accessed by +** SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed +** to be relative to that directory.)^ ^If this variable is a NULL +** pointer, then SQLite assumes that all database files specified +** with a relative pathname are relative to the current directory +** for the process. Only the windows VFS makes use of this global +** variable; it is ignored by the unix VFS. +** +** Changing the value of this variable while a database connection is +** open can result in a corrupt database. +** +** It is not safe to read or modify this variable in more than one +** thread at a time. It is not safe to read or modify this variable +** if a [database connection] is being used at the same time in a separate +** thread. +** It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been called and that this variable remain unchanged +** thereafter. +** +** ^The [data_store_directory pragma] may modify this variable and cause +** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, +** the [data_store_directory pragma] always assumes that any string +** that this variable points to is held in memory obtained from +** [sqlite3_malloc] and the pragma may attempt to free that memory +** using [sqlite3_free]. +** Hence, if this variable is modified directly, either it should be +** made NULL or made to point to memory obtained from [sqlite3_malloc] +** or else the use of the [data_store_directory pragma] should be avoided. +*/ +SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory; + +/* +** CAPI3REF: Test For Auto-Commit Mode +** KEYWORDS: {autocommit mode} +** METHOD: sqlite3 +** +** ^The sqlite3_get_autocommit() interface returns non-zero or +** zero if the given database connection is or is not in autocommit mode, +** respectively. ^Autocommit mode is on by default. +** ^Autocommit mode is disabled by a [BEGIN] statement. +** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. +** +** If certain kinds of errors occur on a statement within a multi-statement +** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], +** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the +** transaction might be rolled back automatically. The only way to +** find out whether SQLite automatically rolled back the transaction after +** an error is to use this function. +** +** If another thread changes the autocommit status of the database +** connection while this routine is running, then the return value +** is undefined. +*/ +SQLITE_API int sqlite3_get_autocommit(sqlite3*); + +/* +** CAPI3REF: Find The Database Handle Of A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_db_handle interface returns the [database connection] handle +** to which a [prepared statement] belongs. ^The [database connection] +** returned by sqlite3_db_handle is the same [database connection] +** that was the first argument +** to the [sqlite3_prepare_v2()] call (or its variants) that was used to +** create the statement in the first place. +*/ +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); + +/* +** CAPI3REF: Return The Filename For A Database Connection +** METHOD: sqlite3 +** +** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename +** associated with database N of connection D. ^The main database file +** has the name "main". If there is no attached database N on the database +** connection D, or if database N is a temporary or in-memory database, then +** a NULL pointer is returned. +** +** ^The filename returned by this function is the output of the +** xFullPathname method of the [VFS]. ^In other words, the filename +** will be an absolute pathname, even if the filename used +** to open the database originally was a URI or relative pathname. +*/ +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); + +/* +** CAPI3REF: Determine if a database is read-only +** METHOD: sqlite3 +** +** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N +** of connection D is read-only, 0 if it is read/write, or -1 if N is not +** the name of a database on connection D. +*/ +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); + +/* +** CAPI3REF: Find the next prepared statement +** METHOD: sqlite3 +** +** ^This interface returns a pointer to the next [prepared statement] after +** pStmt associated with the [database connection] pDb. ^If pStmt is NULL +** then this interface returns a pointer to the first prepared statement +** associated with the database connection pDb. ^If no prepared statement +** satisfies the conditions of this routine, it returns NULL. +** +** The [database connection] pointer D in a call to +** [sqlite3_next_stmt(D,S)] must refer to an open database +** connection and in particular must not be a NULL pointer. +*/ +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Commit And Rollback Notification Callbacks +** METHOD: sqlite3 +** +** ^The sqlite3_commit_hook() interface registers a callback +** function to be invoked whenever a transaction is [COMMIT | committed]. +** ^Any callback set by a previous call to sqlite3_commit_hook() +** for the same database connection is overridden. +** ^The sqlite3_rollback_hook() interface registers a callback +** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. +** ^Any callback set by a previous call to sqlite3_rollback_hook() +** for the same database connection is overridden. +** ^The pArg argument is passed through to the callback. +** ^If the callback on a commit hook function returns non-zero, +** then the commit is converted into a rollback. +** +** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions +** return the P argument from the previous call of the same function +** on the same [database connection] D, or NULL for +** the first call for each function on D. +** +** The commit and rollback hook callbacks are not reentrant. +** The callback implementation must not do anything that will modify +** the database connection that invoked the callback. Any actions +** to modify the database connection must be deferred until after the +** completion of the [sqlite3_step()] call that triggered the commit +** or rollback hook in the first place. +** Note that running any other SQL statements, including SELECT statements, +** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify +** the database connections for the meaning of "modify" in this paragraph. +** +** ^Registering a NULL function disables the callback. +** +** ^When the commit hook callback routine returns zero, the [COMMIT] +** operation is allowed to continue normally. ^If the commit hook +** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. +** ^The rollback hook is invoked on a rollback that results from a commit +** hook returning non-zero, just as it would be with any other rollback. +** +** ^For the purposes of this API, a transaction is said to have been +** rolled back if an explicit "ROLLBACK" statement is executed, or +** an error or constraint causes an implicit rollback to occur. +** ^The rollback callback is not invoked if a transaction is +** automatically rolled back because the database connection is closed. +** +** See also the [sqlite3_update_hook()] interface. +*/ +SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); +SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); + +/* +** CAPI3REF: Data Change Notification Callbacks +** METHOD: sqlite3 +** +** ^The sqlite3_update_hook() interface registers a callback function +** with the [database connection] identified by the first argument +** to be invoked whenever a row is updated, inserted or deleted in +** a [rowid table]. +** ^Any callback set by a previous call to this function +** for the same database connection is overridden. +** +** ^The second argument is a pointer to the function to invoke when a +** row is updated, inserted or deleted in a rowid table. +** ^The first argument to the callback is a copy of the third argument +** to sqlite3_update_hook(). +** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], +** or [SQLITE_UPDATE], depending on the operation that caused the callback +** to be invoked. +** ^The third and fourth arguments to the callback contain pointers to the +** database and table name containing the affected row. +** ^The final callback parameter is the [rowid] of the row. +** ^In the case of an update, this is the [rowid] after the update takes place. +** +** ^(The update hook is not invoked when internal system tables are +** modified (i.e. sqlite_master and sqlite_sequence).)^ +** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. +** +** ^In the current implementation, the update hook +** is not invoked when duplication rows are deleted because of an +** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook +** invoked when rows are deleted using the [truncate optimization]. +** The exceptions defined in this paragraph might change in a future +** release of SQLite. +** +** The update hook implementation must not do anything that will modify +** the database connection that invoked the update hook. Any actions +** to modify the database connection must be deferred until after the +** completion of the [sqlite3_step()] call that triggered the update hook. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^The sqlite3_update_hook(D,C,P) function +** returns the P argument from the previous call +** on the same [database connection] D, or NULL for +** the first call on D. +** +** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], +** and [sqlite3_preupdate_hook()] interfaces. +*/ +SQLITE_API void *sqlite3_update_hook( + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite3_int64), + void* +); + +/* +** CAPI3REF: Enable Or Disable Shared Pager Cache +** +** ^(This routine enables or disables the sharing of the database cache +** and schema data structures between [database connection | connections] +** to the same database. Sharing is enabled if the argument is true +** and disabled if the argument is false.)^ +** +** ^Cache sharing is enabled and disabled for an entire process. +** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). +** In prior versions of SQLite, +** sharing was enabled or disabled for each thread separately. +** +** ^(The cache sharing mode set by this interface effects all subsequent +** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. +** Existing database connections continue use the sharing mode +** that was in effect at the time they were opened.)^ +** +** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled +** successfully. An [error code] is returned otherwise.)^ +** +** ^Shared cache is disabled by default. But this might change in +** future releases of SQLite. Applications that care about shared +** cache setting should set it explicitly. +** +** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 +** and will always return SQLITE_MISUSE. On those systems, +** shared cache mode should be enabled per-database connection via +** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. +** +** This interface is threadsafe on processors where writing a +** 32-bit integer is atomic. +** +** See Also: [SQLite Shared-Cache Mode] +*/ +SQLITE_API int sqlite3_enable_shared_cache(int); + +/* +** CAPI3REF: Attempt To Free Heap Memory +** +** ^The sqlite3_release_memory() interface attempts to free N bytes +** of heap memory by deallocating non-essential memory allocations +** held by the database library. Memory used to cache database +** pages to improve performance is an example of non-essential memory. +** ^sqlite3_release_memory() returns the number of bytes actually freed, +** which might be more or less than the amount requested. +** ^The sqlite3_release_memory() routine is a no-op returning zero +** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +** +** See also: [sqlite3_db_release_memory()] +*/ +SQLITE_API int sqlite3_release_memory(int); + +/* +** CAPI3REF: Free Memory Used By A Database Connection +** METHOD: sqlite3 +** +** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap +** memory as possible from database connection D. Unlike the +** [sqlite3_release_memory()] interface, this interface is in effect even +** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is +** omitted. +** +** See also: [sqlite3_release_memory()] +*/ +SQLITE_API int sqlite3_db_release_memory(sqlite3*); + +/* +** CAPI3REF: Impose A Limit On Heap Size +** +** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the +** soft limit on the amount of heap memory that may be allocated by SQLite. +** ^SQLite strives to keep heap memory utilization below the soft heap +** limit by reducing the number of pages held in the page cache +** as heap memory usages approaches the limit. +** ^The soft heap limit is "soft" because even though SQLite strives to stay +** below the limit, it will exceed the limit rather than generate +** an [SQLITE_NOMEM] error. In other words, the soft heap limit +** is advisory only. +** +** ^The return value from sqlite3_soft_heap_limit64() is the size of +** the soft heap limit prior to the call, or negative in the case of an +** error. ^If the argument N is negative +** then no change is made to the soft heap limit. Hence, the current +** size of the soft heap limit can be determined by invoking +** sqlite3_soft_heap_limit64() with a negative argument. +** +** ^If the argument N is zero then the soft heap limit is disabled. +** +** ^(The soft heap limit is not enforced in the current implementation +** if one or more of following conditions are true: +** +**
    +**
  • The soft heap limit is set to zero. +**
  • Memory accounting is disabled using a combination of the +** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and +** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. +**
  • An alternative page cache implementation is specified using +** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...). +**
  • The page cache allocates from its own memory pool supplied +** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than +** from the heap. +**
)^ +** +** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), +** the soft heap limit is enforced +** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] +** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], +** the soft heap limit is enforced on every memory allocation. Without +** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced +** when memory is allocated by the page cache. Testing suggests that because +** the page cache is the predominate memory user in SQLite, most +** applications will achieve adequate soft heap limit enforcement without +** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +** +** The circumstances under which SQLite will enforce the soft heap limit may +** changes in future releases of SQLite. +*/ +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); + +/* +** CAPI3REF: Deprecated Soft Heap Limit Interface +** DEPRECATED +** +** This is a deprecated version of the [sqlite3_soft_heap_limit64()] +** interface. This routine is provided for historical compatibility +** only. All new applications should use the +** [sqlite3_soft_heap_limit64()] interface rather than this one. +*/ +SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); + + +/* +** CAPI3REF: Extract Metadata About A Column Of A Table +** METHOD: sqlite3 +** +** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns +** information about column C of table T in database D +** on [database connection] X.)^ ^The sqlite3_table_column_metadata() +** interface returns SQLITE_OK and fills in the non-NULL pointers in +** the final five arguments with appropriate values if the specified +** column exists. ^The sqlite3_table_column_metadata() interface returns +** SQLITE_ERROR and if the specified column does not exist. +** ^If the column-name parameter to sqlite3_table_column_metadata() is a +** NULL pointer, then this routine simply checks for the existence of the +** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it +** does not. +** +** ^The column is identified by the second, third and fourth parameters to +** this function. ^(The second parameter is either the name of the database +** (i.e. "main", "temp", or an attached database) containing the specified +** table or NULL.)^ ^If it is NULL, then all attached databases are searched +** for the table using the same algorithm used by the database engine to +** resolve unqualified table references. +** +** ^The third and fourth parameters to this function are the table and column +** name of the desired column, respectively. +** +** ^Metadata is returned by writing to the memory locations passed as the 5th +** and subsequent parameters to this function. ^Any of these arguments may be +** NULL, in which case the corresponding element of metadata is omitted. +** +** ^(
+** +**
Parameter Output
Type
Description +** +**
5th const char* Data type +**
6th const char* Name of default collation sequence +**
7th int True if column has a NOT NULL constraint +**
8th int True if column is part of the PRIMARY KEY +**
9th int True if column is [AUTOINCREMENT] +**
+**
)^ +** +** ^The memory pointed to by the character pointers returned for the +** declaration type and collation sequence is valid until the next +** call to any SQLite API function. +** +** ^If the specified table is actually a view, an [error code] is returned. +** +** ^If the specified column is "rowid", "oid" or "_rowid_" and the table +** is not a [WITHOUT ROWID] table and an +** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output +** parameters are set for the explicitly declared column. ^(If there is no +** [INTEGER PRIMARY KEY] column, then the outputs +** for the [rowid] are set as follows: +** +**
+**     data type: "INTEGER"
+**     collation sequence: "BINARY"
+**     not null: 0
+**     primary key: 1
+**     auto increment: 0
+** 
)^ +** +** ^This function causes all database schemas to be read from disk and +** parsed, if that has not already been done, and returns an error if +** any errors are encountered while loading the schema. +*/ +SQLITE_API int sqlite3_table_column_metadata( + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ +); + +/* +** CAPI3REF: Load An Extension +** METHOD: sqlite3 +** +** ^This interface loads an SQLite extension library from the named file. +** +** ^The sqlite3_load_extension() interface attempts to load an +** [SQLite extension] library contained in the file zFile. If +** the file cannot be loaded directly, attempts are made to load +** with various operating-system specific extensions added. +** So for example, if "samplelib" cannot be loaded, then names like +** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might +** be tried also. +** +** ^The entry point is zProc. +** ^(zProc may be 0, in which case SQLite will try to come up with an +** entry point name on its own. It first tries "sqlite3_extension_init". +** If that does not work, it constructs a name "sqlite3_X_init" where the +** X is consists of the lower-case equivalent of all ASCII alphabetic +** characters in the filename from the last "/" to the first following +** "." and omitting any initial "lib".)^ +** ^The sqlite3_load_extension() interface returns +** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. +** ^If an error occurs and pzErrMsg is not 0, then the +** [sqlite3_load_extension()] interface shall attempt to +** fill *pzErrMsg with error message text stored in memory +** obtained from [sqlite3_malloc()]. The calling function +** should free this memory by calling [sqlite3_free()]. +** +** ^Extension loading must be enabled using +** [sqlite3_enable_load_extension()] or +** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) +** prior to calling this API, +** otherwise an error will be returned. +** +** Security warning: It is recommended that the +** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this +** interface. The use of the [sqlite3_enable_load_extension()] interface +** should be avoided. This will keep the SQL function [load_extension()] +** disabled and prevent SQL injections from giving attackers +** access to extension loading capabilities. +** +** See also the [load_extension() SQL function]. +*/ +SQLITE_API int sqlite3_load_extension( + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Derived from zFile if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ +); + +/* +** CAPI3REF: Enable Or Disable Extension Loading +** METHOD: sqlite3 +** +** ^So as not to open security holes in older applications that are +** unprepared to deal with [extension loading], and as a means of disabling +** [extension loading] while evaluating user-entered SQL, the following API +** is provided to turn the [sqlite3_load_extension()] mechanism on and off. +** +** ^Extension loading is off by default. +** ^Call the sqlite3_enable_load_extension() routine with onoff==1 +** to turn extension loading on and call it with onoff==0 to turn +** it back off again. +** +** ^This interface enables or disables both the C-API +** [sqlite3_load_extension()] and the SQL function [load_extension()]. +** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) +** to enable or disable only the C-API.)^ +** +** Security warning: It is recommended that extension loading +** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method +** rather than this interface, so the [load_extension()] SQL function +** remains disabled. This will prevent SQL injections from giving attackers +** access to extension loading capabilities. +*/ +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); + +/* +** CAPI3REF: Automatically Load Statically Linked Extensions +** +** ^This interface causes the xEntryPoint() function to be invoked for +** each new [database connection] that is created. The idea here is that +** xEntryPoint() is the entry point for a statically linked [SQLite extension] +** that is to be automatically loaded into all new database connections. +** +** ^(Even though the function prototype shows that xEntryPoint() takes +** no arguments and returns void, SQLite invokes xEntryPoint() with three +** arguments and expects an integer result as if the signature of the +** entry point where as follows: +** +**
+**    int xEntryPoint(
+**      sqlite3 *db,
+**      const char **pzErrMsg,
+**      const struct sqlite3_api_routines *pThunk
+**    );
+** 
)^ +** +** If the xEntryPoint routine encounters an error, it should make *pzErrMsg +** point to an appropriate error message (obtained from [sqlite3_mprintf()]) +** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg +** is NULL before calling the xEntryPoint(). ^SQLite will invoke +** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any +** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], +** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. +** +** ^Calling sqlite3_auto_extension(X) with an entry point X that is already +** on the list of automatic extensions is a harmless no-op. ^No entry point +** will be called more than once for each database connection that is opened. +** +** See also: [sqlite3_reset_auto_extension()] +** and [sqlite3_cancel_auto_extension()] +*/ +SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)); + +/* +** CAPI3REF: Cancel Automatic Extension Loading +** +** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the +** initialization routine X that was registered using a prior call to +** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] +** routine returns 1 if initialization routine X was successfully +** unregistered and it returns 0 if X was not on the list of initialization +** routines. +*/ +SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); + +/* +** CAPI3REF: Reset Automatic Extension Loading +** +** ^This interface disables all automatic extensions previously +** registered using [sqlite3_auto_extension()]. +*/ +SQLITE_API void sqlite3_reset_auto_extension(void); + +/* +** The interface to the virtual-table mechanism is currently considered +** to be experimental. The interface might change in incompatible ways. +** If this is a problem for you, do not use the interface at this time. +** +** When the virtual-table mechanism stabilizes, we will declare the +** interface fixed, support it indefinitely, and remove this comment. +*/ + +/* +** Structures used by the virtual table interface +*/ +typedef struct sqlite3_vtab sqlite3_vtab; +typedef struct sqlite3_index_info sqlite3_index_info; +typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; +typedef struct sqlite3_module sqlite3_module; + +/* +** CAPI3REF: Virtual Table Object +** KEYWORDS: sqlite3_module {virtual table module} +** +** This structure, sometimes called a "virtual table module", +** defines the implementation of a [virtual tables]. +** This structure consists mostly of methods for the module. +** +** ^A virtual table module is created by filling in a persistent +** instance of this structure and passing a pointer to that instance +** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. +** ^The registration remains valid until it is replaced by a different +** module or until the [database connection] closes. The content +** of this structure must not change while it is registered with +** any database connection. +*/ +struct sqlite3_module { + int iVersion; + int (*xCreate)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xConnect)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab *pVTab); + int (*xDestroy)(sqlite3_vtab *pVTab); + int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); + int (*xBegin)(sqlite3_vtab *pVTab); + int (*xSync)(sqlite3_vtab *pVTab); + int (*xCommit)(sqlite3_vtab *pVTab); + int (*xRollback)(sqlite3_vtab *pVTab); + int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg); + int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); +}; + +/* +** CAPI3REF: Virtual Table Indexing Information +** KEYWORDS: sqlite3_index_info +** +** The sqlite3_index_info structure and its substructures is used as part +** of the [virtual table] interface to +** pass information into and receive the reply from the [xBestIndex] +** method of a [virtual table module]. The fields under **Inputs** are the +** inputs to xBestIndex and are read-only. xBestIndex inserts its +** results into the **Outputs** fields. +** +** ^(The aConstraint[] array records WHERE clause constraints of the form: +** +**
column OP expr
+** +** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is +** stored in aConstraint[].op using one of the +** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ +** ^(The index of the column is stored in +** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the +** expr on the right-hand side can be evaluated (and thus the constraint +** is usable) and false if it cannot.)^ +** +** ^The optimizer automatically inverts terms of the form "expr OP column" +** and makes other simplifications to the WHERE clause in an attempt to +** get as many WHERE clause terms into the form shown above as possible. +** ^The aConstraint[] array only reports WHERE clause terms that are +** relevant to the particular virtual table being queried. +** +** ^Information about the ORDER BY clause is stored in aOrderBy[]. +** ^Each term of aOrderBy records a column of the ORDER BY clause. +** +** The colUsed field indicates which columns of the virtual table may be +** required by the current scan. Virtual table columns are numbered from +** zero in the order in which they appear within the CREATE TABLE statement +** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62), +** the corresponding bit is set within the colUsed mask if the column may be +** required by SQLite. If the table has at least 64 columns and any column +** to the right of the first 63 is required, then bit 63 of colUsed is also +** set. In other words, column iCol may be required if the expression +** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to +** non-zero. +** +** The [xBestIndex] method must fill aConstraintUsage[] with information +** about what parameters to pass to xFilter. ^If argvIndex>0 then +** the right-hand side of the corresponding aConstraint[] is evaluated +** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit +** is true, then the constraint is assumed to be fully handled by the +** virtual table and is not checked again by SQLite.)^ +** +** ^The idxNum and idxPtr values are recorded and passed into the +** [xFilter] method. +** ^[sqlite3_free()] is used to free idxPtr if and only if +** needToFreeIdxPtr is true. +** +** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in +** the correct order to satisfy the ORDER BY clause so that no separate +** sorting step is required. +** +** ^The estimatedCost value is an estimate of the cost of a particular +** strategy. A cost of N indicates that the cost of the strategy is similar +** to a linear scan of an SQLite table with N rows. A cost of log(N) +** indicates that the expense of the operation is similar to that of a +** binary search on a unique indexed field of an SQLite table with N rows. +** +** ^The estimatedRows value is an estimate of the number of rows that +** will be returned by the strategy. +** +** The xBestIndex method may optionally populate the idxFlags field with a +** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - +** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite +** assumes that the strategy may visit at most one row. +** +** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then +** SQLite also assumes that if a call to the xUpdate() method is made as +** part of the same statement to delete or update a virtual table row and the +** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback +** any database changes. In other words, if the xUpdate() returns +** SQLITE_CONSTRAINT, the database contents must be exactly as they were +** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not +** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by +** the xUpdate method are automatically rolled back by SQLite. +** +** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info +** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). +** If a virtual table extension is +** used with an SQLite version earlier than 3.8.2, the results of attempting +** to read or write the estimatedRows field are undefined (but are likely +** to included crashing the application). The estimatedRows field should +** therefore only be used if [sqlite3_libversion_number()] returns a +** value greater than or equal to 3008002. Similarly, the idxFlags field +** was added for [version 3.9.0] ([dateof:3.9.0]). +** It may therefore only be used if +** sqlite3_libversion_number() returns a value greater than or equal to +** 3009000. +*/ +struct sqlite3_index_info { + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint { + int iColumn; /* Column constrained. -1 for ROWID */ + unsigned char op; /* Constraint operator */ + unsigned char usable; /* True if this constraint is usable */ + int iTermOffset; /* Used internally - xBestIndex should ignore */ + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby { + int iColumn; /* Column number */ + unsigned char desc; /* True for DESC. False for ASC. */ + } *aOrderBy; /* The ORDER BY clause */ + /* Outputs */ + struct sqlite3_index_constraint_usage { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + unsigned char omit; /* Do not code a test for this constraint */ + } *aConstraintUsage; + int idxNum; /* Number used to identify the index */ + char *idxStr; /* String, possibly obtained from sqlite3_malloc */ + int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ + int orderByConsumed; /* True if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ + /* Fields below are only available in SQLite 3.8.2 and later */ + sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ + /* Fields below are only available in SQLite 3.9.0 and later */ + int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ + /* Fields below are only available in SQLite 3.10.0 and later */ + sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ +}; + +/* +** CAPI3REF: Virtual Table Scan Flags +*/ +#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ + +/* +** CAPI3REF: Virtual Table Constraint Operator Codes +** +** These macros defined the allowed values for the +** [sqlite3_index_info].aConstraint[].op field. Each value represents +** an operator that is part of a constraint term in the wHERE clause of +** a query that uses a [virtual table]. +*/ +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 + +/* +** CAPI3REF: Register A Virtual Table Implementation +** METHOD: sqlite3 +** +** ^These routines are used to register a new [virtual table module] name. +** ^Module names must be registered before +** creating a new [virtual table] using the module and before using a +** preexisting [virtual table] for the module. +** +** ^The module name is registered on the [database connection] specified +** by the first parameter. ^The name of the module is given by the +** second parameter. ^The third parameter is a pointer to +** the implementation of the [virtual table module]. ^The fourth +** parameter is an arbitrary client data pointer that is passed through +** into the [xCreate] and [xConnect] methods of the virtual table module +** when a new virtual table is be being created or reinitialized. +** +** ^The sqlite3_create_module_v2() interface has a fifth parameter which +** is a pointer to a destructor for the pClientData. ^SQLite will +** invoke the destructor function (if it is not NULL) when SQLite +** no longer needs the pClientData pointer. ^The destructor will also +** be invoked if the call to sqlite3_create_module_v2() fails. +** ^The sqlite3_create_module() +** interface is equivalent to sqlite3_create_module_v2() with a NULL +** destructor. +*/ +SQLITE_API int sqlite3_create_module( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData /* Client data for xCreate/xConnect */ +); +SQLITE_API int sqlite3_create_module_v2( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData, /* Client data for xCreate/xConnect */ + void(*xDestroy)(void*) /* Module destructor function */ +); + +/* +** CAPI3REF: Virtual Table Instance Object +** KEYWORDS: sqlite3_vtab +** +** Every [virtual table module] implementation uses a subclass +** of this object to describe a particular instance +** of the [virtual table]. Each subclass will +** be tailored to the specific needs of the module implementation. +** The purpose of this superclass is to define certain fields that are +** common to all module implementations. +** +** ^Virtual tables methods can set an error message by assigning a +** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should +** take care that any prior string is freed by a call to [sqlite3_free()] +** prior to assigning a new string to zErrMsg. ^After the error message +** is delivered up to the client application, the string will be automatically +** freed by sqlite3_free() and the zErrMsg field will be zeroed. +*/ +struct sqlite3_vtab { + const sqlite3_module *pModule; /* The module for this virtual table */ + int nRef; /* Number of open cursors */ + char *zErrMsg; /* Error message from sqlite3_mprintf() */ + /* Virtual table implementations will typically add additional fields */ +}; + +/* +** CAPI3REF: Virtual Table Cursor Object +** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} +** +** Every [virtual table module] implementation uses a subclass of the +** following structure to describe cursors that point into the +** [virtual table] and are used +** to loop through the virtual table. Cursors are created using the +** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed +** by the [sqlite3_module.xClose | xClose] method. Cursors are used +** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods +** of the module. Each module implementation will define +** the content of a cursor structure to suit its own needs. +** +** This superclass exists in order to define fields of the cursor that +** are common to all implementations. +*/ +struct sqlite3_vtab_cursor { + sqlite3_vtab *pVtab; /* Virtual table of this cursor */ + /* Virtual table implementations will typically add additional fields */ +}; + +/* +** CAPI3REF: Declare The Schema Of A Virtual Table +** +** ^The [xCreate] and [xConnect] methods of a +** [virtual table module] call this interface +** to declare the format (the names and datatypes of the columns) of +** the virtual tables they implement. +*/ +SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); + +/* +** CAPI3REF: Overload A Function For A Virtual Table +** METHOD: sqlite3 +** +** ^(Virtual tables can provide alternative implementations of functions +** using the [xFindFunction] method of the [virtual table module]. +** But global versions of those functions +** must exist in order to be overloaded.)^ +** +** ^(This API makes sure a global version of a function with a particular +** name and number of parameters exists. If no such function exists +** before this API is called, a new function is created.)^ ^The implementation +** of the new function always causes an exception to be thrown. So +** the new function is not good for anything by itself. Its only +** purpose is to be a placeholder function that can be overloaded +** by a [virtual table]. +*/ +SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); + +/* +** The interface to the virtual-table mechanism defined above (back up +** to a comment remarkably similar to this one) is currently considered +** to be experimental. The interface might change in incompatible ways. +** If this is a problem for you, do not use the interface at this time. +** +** When the virtual-table mechanism stabilizes, we will declare the +** interface fixed, support it indefinitely, and remove this comment. +*/ + +/* +** CAPI3REF: A Handle To An Open BLOB +** KEYWORDS: {BLOB handle} {BLOB handles} +** +** An instance of this object represents an open BLOB on which +** [sqlite3_blob_open | incremental BLOB I/O] can be performed. +** ^Objects of this type are created by [sqlite3_blob_open()] +** and destroyed by [sqlite3_blob_close()]. +** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces +** can be used to read or write small subsections of the BLOB. +** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. +*/ +typedef struct sqlite3_blob sqlite3_blob; + +/* +** CAPI3REF: Open A BLOB For Incremental I/O +** METHOD: sqlite3 +** CONSTRUCTOR: sqlite3_blob +** +** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located +** in row iRow, column zColumn, table zTable in database zDb; +** in other words, the same BLOB that would be selected by: +** +**
+**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
+** 
)^ +** +** ^(Parameter zDb is not the filename that contains the database, but +** rather the symbolic name of the database. For attached databases, this is +** the name that appears after the AS keyword in the [ATTACH] statement. +** For the main database file, the database name is "main". For TEMP +** tables, the database name is "temp".)^ +** +** ^If the flags parameter is non-zero, then the BLOB is opened for read +** and write access. ^If the flags parameter is zero, the BLOB is opened for +** read-only access. +** +** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored +** in *ppBlob. Otherwise an [error code] is returned and, unless the error +** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided +** the API is not misused, it is always safe to call [sqlite3_blob_close()] +** on *ppBlob after this function it returns. +** +** This function fails with SQLITE_ERROR if any of the following are true: +**
    +**
  • ^(Database zDb does not exist)^, +**
  • ^(Table zTable does not exist within database zDb)^, +**
  • ^(Table zTable is a WITHOUT ROWID table)^, +**
  • ^(Column zColumn does not exist)^, +**
  • ^(Row iRow is not present in the table)^, +**
  • ^(The specified column of row iRow contains a value that is not +** a TEXT or BLOB value)^, +**
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE +** constraint and the blob is being opened for read/write access)^, +**
  • ^([foreign key constraints | Foreign key constraints] are enabled, +** column zColumn is part of a [child key] definition and the blob is +** being opened for read/write access)^. +**
+** +** ^Unless it returns SQLITE_MISUSE, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** +** +** ^(If the row that a BLOB handle points to is modified by an +** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects +** then the BLOB handle is marked as "expired". +** This is true if any column of the row is changed, even a column +** other than the one the BLOB handle is open on.)^ +** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for +** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. +** ^(Changes written into a BLOB prior to the BLOB expiring are not +** rolled back by the expiration of the BLOB. Such changes will eventually +** commit if the transaction continues to completion.)^ +** +** ^Use the [sqlite3_blob_bytes()] interface to determine the size of +** the opened blob. ^The size of a blob may not be changed by this +** interface. Use the [UPDATE] SQL command to change the size of a +** blob. +** +** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces +** and the built-in [zeroblob] SQL function may be used to create a +** zero-filled blob to read or write using the incremental-blob interface. +** +** To avoid a resource leak, every open [BLOB handle] should eventually +** be released by a call to [sqlite3_blob_close()]. +*/ +SQLITE_API int sqlite3_blob_open( + sqlite3*, + const char *zDb, + const char *zTable, + const char *zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob **ppBlob +); + +/* +** CAPI3REF: Move a BLOB Handle to a New Row +** METHOD: sqlite3_blob +** +** ^This function is used to move an existing blob handle so that it points +** to a different row of the same database table. ^The new row is identified +** by the rowid value passed as the second argument. Only the row can be +** changed. ^The database, table and column on which the blob handle is open +** remain the same. Moving an existing blob handle to a new row can be +** faster than closing the existing handle and opening a new one. +** +** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - +** it must exist and there must be either a blob or text value stored in +** the nominated column.)^ ^If the new row is not present in the table, or if +** it does not contain a blob or text value, or if another error occurs, an +** SQLite error code is returned and the blob handle is considered aborted. +** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or +** [sqlite3_blob_reopen()] on an aborted blob handle immediately return +** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle +** always returns zero. +** +** ^This function sets the database handle error code and message. +*/ +SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); + +/* +** CAPI3REF: Close A BLOB Handle +** DESTRUCTOR: sqlite3_blob +** +** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed +** unconditionally. Even if this routine returns an error code, the +** handle is still closed.)^ +** +** ^If the blob handle being closed was opened for read-write access, and if +** the database is in auto-commit mode and there are no other open read-write +** blob handles or active write statements, the current transaction is +** committed. ^If an error occurs while committing the transaction, an error +** code is returned and the transaction rolled back. +** +** Calling this function with an argument that is not a NULL pointer or an +** open blob handle results in undefined behaviour. ^Calling this routine +** with a null pointer (such as would be returned by a failed call to +** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function +** is passed a valid open blob handle, the values returned by the +** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. +*/ +SQLITE_API int sqlite3_blob_close(sqlite3_blob *); + +/* +** CAPI3REF: Return The Size Of An Open BLOB +** METHOD: sqlite3_blob +** +** ^Returns the size in bytes of the BLOB accessible via the +** successfully opened [BLOB handle] in its only argument. ^The +** incremental blob I/O routines can only read or overwriting existing +** blob content; they cannot change the size of a blob. +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +*/ +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); + +/* +** CAPI3REF: Read Data From A BLOB Incrementally +** METHOD: sqlite3_blob +** +** ^(This function is used to read data from an open [BLOB handle] into a +** caller-supplied buffer. N bytes of data are copied into buffer Z +** from the open BLOB, starting at offset iOffset.)^ +** +** ^If offset iOffset is less than N bytes from the end of the BLOB, +** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is +** less than zero, [SQLITE_ERROR] is returned and no data is read. +** ^The size of the blob (and hence the maximum value of N+iOffset) +** can be determined using the [sqlite3_blob_bytes()] interface. +** +** ^An attempt to read from an expired [BLOB handle] fails with an +** error code of [SQLITE_ABORT]. +** +** ^(On success, sqlite3_blob_read() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +** +** See also: [sqlite3_blob_write()]. +*/ +SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); + +/* +** CAPI3REF: Write Data Into A BLOB Incrementally +** METHOD: sqlite3_blob +** +** ^(This function is used to write data into an open [BLOB handle] from a +** caller-supplied buffer. N bytes of data are copied from the buffer Z +** into the open BLOB, starting at offset iOffset.)^ +** +** ^(On success, sqlite3_blob_write() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** ^Unless SQLITE_MISUSE is returned, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** +** ^If the [BLOB handle] passed as the first argument was not opened for +** writing (the flags parameter to [sqlite3_blob_open()] was zero), +** this function returns [SQLITE_READONLY]. +** +** This function may only modify the contents of the BLOB; it is +** not possible to increase the size of a BLOB using this API. +** ^If offset iOffset is less than N bytes from the end of the BLOB, +** [SQLITE_ERROR] is returned and no data is written. The size of the +** BLOB (and hence the maximum value of N+iOffset) can be determined +** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less +** than zero [SQLITE_ERROR] is returned and no data is written. +** +** ^An attempt to write to an expired [BLOB handle] fails with an +** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred +** before the [BLOB handle] expired are not rolled back by the +** expiration of the handle, though of course those changes might +** have been overwritten by the statement that expired the BLOB handle +** or by other independent statements. +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +** +** See also: [sqlite3_blob_read()]. +*/ +SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); + +/* +** CAPI3REF: Virtual File System Objects +** +** A virtual filesystem (VFS) is an [sqlite3_vfs] object +** that SQLite uses to interact +** with the underlying operating system. Most SQLite builds come with a +** single default VFS that is appropriate for the host computer. +** New VFSes can be registered and existing VFSes can be unregistered. +** The following interfaces are provided. +** +** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. +** ^Names are case sensitive. +** ^Names are zero-terminated UTF-8 strings. +** ^If there is no match, a NULL pointer is returned. +** ^If zVfsName is NULL then the default VFS is returned. +** +** ^New VFSes are registered with sqlite3_vfs_register(). +** ^Each new VFS becomes the default VFS if the makeDflt flag is set. +** ^The same VFS can be registered multiple times without injury. +** ^To make an existing VFS into the default VFS, register it again +** with the makeDflt flag set. If two different VFSes with the +** same name are registered, the behavior is undefined. If a +** VFS is registered with a name that is NULL or an empty string, +** then the behavior is undefined. +** +** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. +** ^(If the default VFS is unregistered, another VFS is chosen as +** the default. The choice for the new VFS is arbitrary.)^ +*/ +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); + +/* +** CAPI3REF: Mutexes +** +** The SQLite core uses these routines for thread +** synchronization. Though they are intended for internal +** use by SQLite, code that links against SQLite is +** permitted to use any of these routines. +** +** The SQLite source code contains multiple implementations +** of these mutex routines. An appropriate implementation +** is selected automatically at compile-time. The following +** implementations are available in the SQLite core: +** +**
    +**
  • SQLITE_MUTEX_PTHREADS +**
  • SQLITE_MUTEX_W32 +**
  • SQLITE_MUTEX_NOOP +**
+** +** The SQLITE_MUTEX_NOOP implementation is a set of routines +** that does no real locking and is appropriate for use in +** a single-threaded application. The SQLITE_MUTEX_PTHREADS and +** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix +** and Windows. +** +** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor +** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex +** implementation is included with the library. In this case the +** application must supply a custom mutex implementation using the +** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function +** before calling sqlite3_initialize() or any other public sqlite3_ +** function that calls sqlite3_initialize(). +** +** ^The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() +** routine returns NULL if it is unable to allocate the requested +** mutex. The argument to sqlite3_mutex_alloc() must one of these +** integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_OPEN +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 +**
  • SQLITE_MUTEX_STATIC_VFS1 +**
  • SQLITE_MUTEX_STATIC_VFS2 +**
  • SQLITE_MUTEX_STATIC_VFS3 +**
+** +** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) +** cause sqlite3_mutex_alloc() to create +** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other +** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return +** a pointer to a static preexisting mutex. ^Nine static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. ^For the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +** +** ^The sqlite3_mutex_free() routine deallocates a previously +** allocated dynamic mutex. Attempting to deallocate a static +** mutex results in undefined behavior. +** +** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. ^If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] +** upon successful entry. ^(Mutexes created using +** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. +** In such cases, the +** mutex must be exited an equal number of times before another thread +** can enter.)^ If the same thread tries to enter any mutex other +** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. +** +** ^(Some systems (for example, Windows 95) do not support the operation +** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ +** +** ^The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered by the +** calling thread or is not currently allocated. +** +** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or +** sqlite3_mutex_leave() is a NULL pointer, then all three routines +** behave as no-ops. +** +** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. +*/ +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); + +/* +** CAPI3REF: Mutex Methods Object +** +** An instance of this structure defines the low-level routines +** used to allocate and use mutexes. +** +** Usually, the default mutex implementations provided by SQLite are +** sufficient, however the application has the option of substituting a custom +** implementation for specialized deployments or systems for which SQLite +** does not provide a suitable implementation. In this case, the application +** creates and populates an instance of this structure to pass +** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. +** Additionally, an instance of this structure can be used as an +** output variable when querying the system for the current mutex +** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. +** +** ^The xMutexInit method defined by this structure is invoked as +** part of system initialization by the sqlite3_initialize() function. +** ^The xMutexInit routine is called by SQLite exactly once for each +** effective call to [sqlite3_initialize()]. +** +** ^The xMutexEnd method defined by this structure is invoked as +** part of system shutdown by the sqlite3_shutdown() function. The +** implementation of this method is expected to release all outstanding +** resources obtained by the mutex methods implementation, especially +** those obtained by the xMutexInit method. ^The xMutexEnd() +** interface is invoked exactly once for each call to [sqlite3_shutdown()]. +** +** ^(The remaining seven methods defined by this structure (xMutexAlloc, +** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and +** xMutexNotheld) implement the following interfaces (respectively): +** +**
    +**
  • [sqlite3_mutex_alloc()]
  • +**
  • [sqlite3_mutex_free()]
  • +**
  • [sqlite3_mutex_enter()]
  • +**
  • [sqlite3_mutex_try()]
  • +**
  • [sqlite3_mutex_leave()]
  • +**
  • [sqlite3_mutex_held()]
  • +**
  • [sqlite3_mutex_notheld()]
  • +**
)^ +** +** The only difference is that the public sqlite3_XXX functions enumerated +** above silently ignore any invocations that pass a NULL pointer instead +** of a valid mutex handle. The implementations of the methods defined +** by this structure are not required to handle this case, the results +** of passing a NULL pointer instead of a valid mutex handle are undefined +** (i.e. it is acceptable to provide an implementation that segfaults if +** it is passed a NULL pointer). +** +** The xMutexInit() method must be threadsafe. It must be harmless to +** invoke xMutexInit() multiple times within the same process and without +** intervening calls to xMutexEnd(). Second and subsequent calls to +** xMutexInit() must be no-ops. +** +** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] +** and its associates). Similarly, xMutexAlloc() must not use SQLite memory +** allocation for a static mutex. ^However xMutexAlloc() may use SQLite +** memory allocation for a fast or recursive mutex. +** +** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is +** called, but only if the prior call to xMutexInit returned SQLITE_OK. +** If xMutexInit fails in any way, it is expected to clean up after itself +** prior to returning. +*/ +typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; +struct sqlite3_mutex_methods { + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex *(*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex *); + void (*xMutexEnter)(sqlite3_mutex *); + int (*xMutexTry)(sqlite3_mutex *); + void (*xMutexLeave)(sqlite3_mutex *); + int (*xMutexHeld)(sqlite3_mutex *); + int (*xMutexNotheld)(sqlite3_mutex *); +}; + +/* +** CAPI3REF: Mutex Verification Routines +** +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines +** are intended for use inside assert() statements. The SQLite core +** never uses these routines except inside an assert() and applications +** are advised to follow the lead of the core. The SQLite core only +** provides implementations for these routines when it is compiled +** with the SQLITE_DEBUG flag. External mutex implementations +** are only required to provide these routines if SQLITE_DEBUG is +** defined and if NDEBUG is not defined. +** +** These routines should return true if the mutex in their argument +** is held or not held, respectively, by the calling thread. +** +** The implementation is not required to provide versions of these +** routines that actually work. If the implementation does not provide working +** versions of these routines, it should at least provide stubs that always +** return true so that one does not get spurious assertion failures. +** +** If the argument to sqlite3_mutex_held() is a NULL pointer then +** the routine should return 1. This seems counter-intuitive since +** clearly the mutex cannot be held if it does not exist. But +** the reason the mutex does not exist is because the build is not +** using mutexes. And we do not want the assert() containing the +** call to sqlite3_mutex_held() to fail, so a non-zero return is +** the appropriate thing to do. The sqlite3_mutex_notheld() +** interface should also return 1 when given a NULL pointer. +*/ +#ifndef NDEBUG +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); +#endif + +/* +** CAPI3REF: Mutex Types +** +** The [sqlite3_mutex_alloc()] interface takes a single argument +** which is one of these integer constants. +** +** The set of static mutexes may change from one SQLite release to the +** next. Applications that override the built-in mutex logic must be +** prepared to accommodate additional static mutexes. +*/ +#define SQLITE_MUTEX_FAST 0 +#define SQLITE_MUTEX_RECURSIVE 1 +#define SQLITE_MUTEX_STATIC_MASTER 2 +#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ +#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ +#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */ +#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ +#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ +#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */ +#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ +#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ + +/* +** CAPI3REF: Retrieve the mutex for a database connection +** METHOD: sqlite3 +** +** ^This interface returns a pointer the [sqlite3_mutex] object that +** serializes access to the [database connection] given in the argument +** when the [threading mode] is Serialized. +** ^If the [threading mode] is Single-thread or Multi-thread then this +** routine returns a NULL pointer. +*/ +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); + +/* +** CAPI3REF: Low-Level Control Of Database Files +** METHOD: sqlite3 +** +** ^The [sqlite3_file_control()] interface makes a direct call to the +** xFileControl method for the [sqlite3_io_methods] object associated +** with a particular database identified by the second argument. ^The +** name of the database is "main" for the main database or "temp" for the +** TEMP database, or the name that appears after the AS keyword for +** databases that are added using the [ATTACH] SQL command. +** ^A NULL pointer can be used in place of "main" to refer to the +** main database file. +** ^The third and fourth parameters to this routine +** are passed directly through to the second and third parameters of +** the xFileControl method. ^The return value of the xFileControl +** method becomes the return value of this routine. +** +** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes +** a pointer to the underlying [sqlite3_file] object to be written into +** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER +** case is a short-circuit path which does not actually invoke the +** underlying sqlite3_io_methods.xFileControl method. +** +** ^If the second parameter (zDbName) does not match the name of any +** open database file, then SQLITE_ERROR is returned. ^This error +** code is not remembered and will not be recalled by [sqlite3_errcode()] +** or [sqlite3_errmsg()]. The underlying xFileControl method might +** also return SQLITE_ERROR. There is no way to distinguish between +** an incorrect zDbName and an SQLITE_ERROR return from the underlying +** xFileControl method. +** +** See also: [SQLITE_FCNTL_LOCKSTATE] +*/ +SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); + +/* +** CAPI3REF: Testing Interface +** +** ^The sqlite3_test_control() interface is used to read out internal +** state of SQLite and to inject faults into SQLite for testing +** purposes. ^The first parameter is an operation code that determines +** the number, meaning, and operation of all subsequent parameters. +** +** This interface is not for use by applications. It exists solely +** for verifying the correct operation of the SQLite library. Depending +** on how the SQLite library is compiled, this interface might not exist. +** +** The details of the operation codes, their meanings, the parameters +** they take, and what they do are all subject to change without notice. +** Unlike most of the SQLite API, this function is not guaranteed to +** operate consistently from one release to the next. +*/ +SQLITE_API int sqlite3_test_control(int op, ...); + +/* +** CAPI3REF: Testing Interface Operation Codes +** +** These constants are the valid operation code parameters used +** as the first argument to [sqlite3_test_control()]. +** +** These parameters and their meanings are subject to change +** without notice. These values are for testing purposes only. +** Applications should not use any of these parameters or the +** [sqlite3_test_control()] interface. +*/ +#define SQLITE_TESTCTRL_FIRST 5 +#define SQLITE_TESTCTRL_PRNG_SAVE 5 +#define SQLITE_TESTCTRL_PRNG_RESTORE 6 +#define SQLITE_TESTCTRL_PRNG_RESET 7 +#define SQLITE_TESTCTRL_BITVEC_TEST 8 +#define SQLITE_TESTCTRL_FAULT_INSTALL 9 +#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 +#define SQLITE_TESTCTRL_PENDING_BYTE 11 +#define SQLITE_TESTCTRL_ASSERT 12 +#define SQLITE_TESTCTRL_ALWAYS 13 +#define SQLITE_TESTCTRL_RESERVE 14 +#define SQLITE_TESTCTRL_OPTIMIZATIONS 15 +#define SQLITE_TESTCTRL_ISKEYWORD 16 +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 +#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ +#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 +#define SQLITE_TESTCTRL_NEVER_CORRUPT 20 +#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 +#define SQLITE_TESTCTRL_BYTEORDER 22 +#define SQLITE_TESTCTRL_ISINIT 23 +#define SQLITE_TESTCTRL_SORTER_MMAP 24 +#define SQLITE_TESTCTRL_IMPOSTER 25 +#define SQLITE_TESTCTRL_LAST 25 + +/* +** CAPI3REF: SQLite Runtime Status +** +** ^These interfaces are used to retrieve runtime status information +** about the performance of SQLite, and optionally to reset various +** highwater marks. ^The first argument is an integer code for +** the specific parameter to measure. ^(Recognized integer codes +** are of the form [status parameters | SQLITE_STATUS_...].)^ +** ^The current value of the parameter is returned into *pCurrent. +** ^The highest recorded value is returned in *pHighwater. ^If the +** resetFlag is true, then the highest record value is reset after +** *pHighwater is written. ^(Some parameters do not record the highest +** value. For those parameters +** nothing is written into *pHighwater and the resetFlag is ignored.)^ +** ^(Other parameters record only the highwater mark and not the current +** value. For these latter parameters nothing is written into *pCurrent.)^ +** +** ^The sqlite3_status() and sqlite3_status64() routines return +** SQLITE_OK on success and a non-zero [error code] on failure. +** +** If either the current value or the highwater mark is too large to +** be represented by a 32-bit integer, then the values returned by +** sqlite3_status() are undefined. +** +** See also: [sqlite3_db_status()] +*/ +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); +SQLITE_API int sqlite3_status64( + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag +); + + +/* +** CAPI3REF: Status Parameters +** KEYWORDS: {status parameters} +** +** These integer constants designate various run-time status parameters +** that can be returned by [sqlite3_status()]. +** +**
+** [[SQLITE_STATUS_MEMORY_USED]] ^(
SQLITE_STATUS_MEMORY_USED
+**
This parameter is the current amount of memory checked out +** using [sqlite3_malloc()], either directly or indirectly. The +** figure includes calls made to [sqlite3_malloc()] by the application +** and internal memory usage by the SQLite library. Scratch memory +** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in +** this parameter. The amount returned is the sum of the allocation +** sizes as reported by the xSize method in [sqlite3_mem_methods].
)^ +** +** [[SQLITE_STATUS_MALLOC_SIZE]] ^(
SQLITE_STATUS_MALLOC_SIZE
+**
This parameter records the largest memory allocation request +** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their +** internal equivalents). Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
SQLITE_STATUS_MALLOC_COUNT
+**
This parameter records the number of separate memory allocations +** currently checked out.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
SQLITE_STATUS_PAGECACHE_USED
+**
This parameter returns the number of pages used out of the +** [pagecache memory allocator] that was configured using +** [SQLITE_CONFIG_PAGECACHE]. The +** value returned is in pages, not in bytes.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] +** ^(
SQLITE_STATUS_PAGECACHE_OVERFLOW
+**
This parameter returns the number of bytes of page cache +** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] +** buffer and where forced to overflow to [sqlite3_malloc()]. The +** returned value includes allocations that overflowed because they +** where too large (they were larger than the "sz" parameter to +** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because +** no space was left in the page cache.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
SQLITE_STATUS_PAGECACHE_SIZE
+**
This parameter records the largest memory allocation request +** handed to [pagecache memory allocator]. Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_SCRATCH_USED]] ^(
SQLITE_STATUS_SCRATCH_USED
+**
This parameter returns the number of allocations used out of the +** [scratch memory allocator] configured using +** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not +** in bytes. Since a single thread may only have one scratch allocation +** outstanding at time, this parameter also reports the number of threads +** using scratch memory at the same time.
)^ +** +** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
+**
This parameter returns the number of bytes of scratch memory +** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] +** buffer and where forced to overflow to [sqlite3_malloc()]. The values +** returned include overflows because the requested allocation was too +** larger (that is, because the requested allocation was larger than the +** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer +** slots were available. +**
)^ +** +** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
SQLITE_STATUS_SCRATCH_SIZE
+**
This parameter records the largest memory allocation request +** handed to [scratch memory allocator]. Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_PARSER_STACK]] ^(
SQLITE_STATUS_PARSER_STACK
+**
The *pHighwater parameter records the deepest parser stack. +** The *pCurrent value is undefined. The *pHighwater value is only +** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^ +**
+** +** New status parameters may be added from time to time. +*/ +#define SQLITE_STATUS_MEMORY_USED 0 +#define SQLITE_STATUS_PAGECACHE_USED 1 +#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 +#define SQLITE_STATUS_SCRATCH_USED 3 +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_MALLOC_SIZE 5 +#define SQLITE_STATUS_PARSER_STACK 6 +#define SQLITE_STATUS_PAGECACHE_SIZE 7 +#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_MALLOC_COUNT 9 + +/* +** CAPI3REF: Database Connection Status +** METHOD: sqlite3 +** +** ^This interface is used to retrieve runtime status information +** about a single [database connection]. ^The first argument is the +** database connection object to be interrogated. ^The second argument +** is an integer constant, taken from the set of +** [SQLITE_DBSTATUS options], that +** determines the parameter to interrogate. The set of +** [SQLITE_DBSTATUS options] is likely +** to grow in future releases of SQLite. +** +** ^The current value of the requested parameter is written into *pCur +** and the highest instantaneous value is written into *pHiwtr. ^If +** the resetFlg is true, then the highest instantaneous value is +** reset back down to the current value. +** +** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a +** non-zero [error code] on failure. +** +** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. +*/ +SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); + +/* +** CAPI3REF: Status Parameters for database connections +** KEYWORDS: {SQLITE_DBSTATUS options} +** +** These constants are the available integer "verbs" that can be passed as +** the second argument to the [sqlite3_db_status()] interface. +** +** New verbs may be added in future releases of SQLite. Existing verbs +** might be discontinued. Applications should check the return code from +** [sqlite3_db_status()] to make sure that the call worked. +** The [sqlite3_db_status()] interface will return a non-zero error code +** if a discontinued or unsupported verb is invoked. +** +**
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
+**
This parameter returns the number of lookaside memory slots currently +** checked out.
)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
+**
This parameter returns the number malloc attempts that were +** satisfied using lookaside memory. Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] +** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
+**
This parameter returns the number malloc attempts that might have +** been satisfied using lookaside memory but failed due to the amount of +** memory requested being larger than the lookaside slot size. +** Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] +** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
+**
This parameter returns the number malloc attempts that might have +** been satisfied using lookaside memory but failed due to all lookaside +** memory already being in use. +** Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
SQLITE_DBSTATUS_CACHE_USED
+**
This parameter returns the approximate number of bytes of heap +** memory used by all pager caches associated with the database connection.)^ +** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. +** +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** ^(
SQLITE_DBSTATUS_CACHE_USED_SHARED
+**
This parameter is similar to DBSTATUS_CACHE_USED, except that if a +** pager cache is shared between two or more connections the bytes of heap +** memory used by that pager cache is divided evenly between the attached +** connections.)^ In other words, if none of the pager caches associated +** with the database connection are shared, this request returns the same +** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** shared, the value returned by this call will be smaller than that returned +** by DBSTATUS_CACHE_USED. ^The highwater mark associated with +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** +** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
SQLITE_DBSTATUS_SCHEMA_USED
+**
This parameter returns the approximate number of bytes of heap +** memory used to store the schema for all databases associated +** with the connection - main, temp, and any [ATTACH]-ed databases.)^ +** ^The full amount of memory used by the schemas is reported, even if the +** schema memory is shared with other database connections due to +** [shared cache mode] being enabled. +** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. +** +** [[SQLITE_DBSTATUS_STMT_USED]] ^(
SQLITE_DBSTATUS_STMT_USED
+**
This parameter returns the approximate number of bytes of heap +** and lookaside memory used by all prepared statements associated with +** the database connection.)^ +** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
SQLITE_DBSTATUS_CACHE_HIT
+**
This parameter returns the number of pager cache hits that have +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT +** is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
SQLITE_DBSTATUS_CACHE_MISS
+**
This parameter returns the number of pager cache misses that have +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS +** is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(
SQLITE_DBSTATUS_CACHE_WRITE
+**
This parameter returns the number of dirty cache entries that have +** been written to disk. Specifically, the number of pages written to the +** wal file in wal mode databases, or the number of pages written to the +** database file in rollback mode databases. Any pages written as part of +** transaction rollback or database recovery operations are not included. +** If an IO or other error occurs while writing a page to disk, the effect +** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The +** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. +**
+** +** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(
SQLITE_DBSTATUS_DEFERRED_FKS
+**
This parameter returns zero for the current value if and only if +** all foreign key constraints (deferred or immediate) have been +** resolved.)^ ^The highwater mark is always 0. +**
+**
+*/ +#define SQLITE_DBSTATUS_LOOKASIDE_USED 0 +#define SQLITE_DBSTATUS_CACHE_USED 1 +#define SQLITE_DBSTATUS_SCHEMA_USED 2 +#define SQLITE_DBSTATUS_STMT_USED 3 +#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 +#define SQLITE_DBSTATUS_CACHE_HIT 7 +#define SQLITE_DBSTATUS_CACHE_MISS 8 +#define SQLITE_DBSTATUS_CACHE_WRITE 9 +#define SQLITE_DBSTATUS_DEFERRED_FKS 10 +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ + + +/* +** CAPI3REF: Prepared Statement Status +** METHOD: sqlite3_stmt +** +** ^(Each prepared statement maintains various +** [SQLITE_STMTSTATUS counters] that measure the number +** of times it has performed specific operations.)^ These counters can +** be used to monitor the performance characteristics of the prepared +** statements. For example, if the number of table steps greatly exceeds +** the number of table searches or result rows, that would tend to indicate +** that the prepared statement is using a full table scan rather than +** an index. +** +** ^(This interface is used to retrieve and reset counter values from +** a [prepared statement]. The first argument is the prepared statement +** object to be interrogated. The second argument +** is an integer code for a specific [SQLITE_STMTSTATUS counter] +** to be interrogated.)^ +** ^The current value of the requested counter is returned. +** ^If the resetFlg is true, then the counter is reset to zero after this +** interface call returns. +** +** See also: [sqlite3_status()] and [sqlite3_db_status()]. +*/ +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); + +/* +** CAPI3REF: Status Parameters for prepared statements +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} +** +** These preprocessor macros define integer codes that name counter +** values associated with the [sqlite3_stmt_status()] interface. +** The meanings of the various counters are as follows: +** +**
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
SQLITE_STMTSTATUS_FULLSCAN_STEP
+**
^This is the number of times that SQLite has stepped forward in +** a table as part of a full table scan. Large numbers for this counter +** may indicate opportunities for performance improvement through +** careful use of indices.
+** +** [[SQLITE_STMTSTATUS_SORT]]
SQLITE_STMTSTATUS_SORT
+**
^This is the number of sort operations that have occurred. +** A non-zero value in this counter may indicate an opportunity to +** improvement performance through careful use of indices.
+** +** [[SQLITE_STMTSTATUS_AUTOINDEX]]
SQLITE_STMTSTATUS_AUTOINDEX
+**
^This is the number of rows inserted into transient indices that +** were created automatically in order to help joins run faster. +** A non-zero value in this counter may indicate an opportunity to +** improvement performance by adding permanent indices that do not +** need to be reinitialized each time the statement is run.
+** +** [[SQLITE_STMTSTATUS_VM_STEP]]
SQLITE_STMTSTATUS_VM_STEP
+**
^This is the number of virtual machine operations executed +** by the prepared statement if that number is less than or equal +** to 2147483647. The number of virtual machine operations can be +** used as a proxy for the total work done by the prepared statement. +** If the number of virtual machine operations exceeds 2147483647 +** then the value returned by this statement status code is undefined. +**
+**
+*/ +#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 +#define SQLITE_STMTSTATUS_SORT 2 +#define SQLITE_STMTSTATUS_AUTOINDEX 3 +#define SQLITE_STMTSTATUS_VM_STEP 4 + +/* +** CAPI3REF: Custom Page Cache Object +** +** The sqlite3_pcache type is opaque. It is implemented by +** the pluggable module. The SQLite core has no knowledge of +** its size or internal structure and never deals with the +** sqlite3_pcache object except by holding and passing pointers +** to the object. +** +** See [sqlite3_pcache_methods2] for additional information. +*/ +typedef struct sqlite3_pcache sqlite3_pcache; + +/* +** CAPI3REF: Custom Page Cache Object +** +** The sqlite3_pcache_page object represents a single page in the +** page cache. The page cache will allocate instances of this +** object. Various methods of the page cache use pointers to instances +** of this object as parameters or as their return value. +** +** See [sqlite3_pcache_methods2] for additional information. +*/ +typedef struct sqlite3_pcache_page sqlite3_pcache_page; +struct sqlite3_pcache_page { + void *pBuf; /* The content of the page */ + void *pExtra; /* Extra information associated with the page */ +}; + +/* +** CAPI3REF: Application Defined Page Cache. +** KEYWORDS: {page cache} +** +** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can +** register an alternative page cache implementation by passing in an +** instance of the sqlite3_pcache_methods2 structure.)^ +** In many applications, most of the heap memory allocated by +** SQLite is used for the page cache. +** By implementing a +** custom page cache using this API, an application can better control +** the amount of memory consumed by SQLite, the way in which +** that memory is allocated and released, and the policies used to +** determine exactly which parts of a database file are cached and for +** how long. +** +** The alternative page cache mechanism is an +** extreme measure that is only needed by the most demanding applications. +** The built-in page cache is recommended for most uses. +** +** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an +** internal buffer by SQLite within the call to [sqlite3_config]. Hence +** the application may discard the parameter after the call to +** [sqlite3_config()] returns.)^ +** +** [[the xInit() page cache method]] +** ^(The xInit() method is called once for each effective +** call to [sqlite3_initialize()])^ +** (usually only once during the lifetime of the process). ^(The xInit() +** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ +** The intent of the xInit() method is to set up global data structures +** required by the custom page cache implementation. +** ^(If the xInit() method is NULL, then the +** built-in default page cache is used instead of the application defined +** page cache.)^ +** +** [[the xShutdown() page cache method]] +** ^The xShutdown() method is called by [sqlite3_shutdown()]. +** It can be used to clean up +** any outstanding resources before process shutdown, if required. +** ^The xShutdown() method may be NULL. +** +** ^SQLite automatically serializes calls to the xInit method, +** so the xInit method need not be threadsafe. ^The +** xShutdown method is only called from [sqlite3_shutdown()] so it does +** not need to be threadsafe either. All other methods must be threadsafe +** in multithreaded applications. +** +** ^SQLite will never invoke xInit() more than once without an intervening +** call to xShutdown(). +** +** [[the xCreate() page cache methods]] +** ^SQLite invokes the xCreate() method to construct a new cache instance. +** SQLite will typically create one cache instance for each open database file, +** though this is not guaranteed. ^The +** first parameter, szPage, is the size in bytes of the pages that must +** be allocated by the cache. ^szPage will always a power of two. ^The +** second parameter szExtra is a number of bytes of extra storage +** associated with each page cache entry. ^The szExtra parameter will +** a number less than 250. SQLite will use the +** extra szExtra bytes on each page to store metadata about the underlying +** database page on disk. The value passed into szExtra depends +** on the SQLite version, the target platform, and how SQLite was compiled. +** ^The third argument to xCreate(), bPurgeable, is true if the cache being +** created will be used to cache database pages of a file stored on disk, or +** false if it is used for an in-memory database. The cache implementation +** does not have to do anything special based with the value of bPurgeable; +** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will +** never invoke xUnpin() except to deliberately delete a page. +** ^In other words, calls to xUnpin() on a cache with bPurgeable set to +** false will always have the "discard" flag set to true. +** ^Hence, a cache created with bPurgeable false will +** never contain any unpinned pages. +** +** [[the xCachesize() page cache method]] +** ^(The xCachesize() method may be called at any time by SQLite to set the +** suggested maximum cache-size (number of pages stored by) the cache +** instance passed as the first argument. This is the value configured using +** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable +** parameter, the implementation is not required to do anything with this +** value; it is advisory only. +** +** [[the xPagecount() page cache methods]] +** The xPagecount() method must return the number of pages currently +** stored in the cache, both pinned and unpinned. +** +** [[the xFetch() page cache methods]] +** The xFetch() method locates a page in the cache and returns a pointer to +** an sqlite3_pcache_page object associated with that page, or a NULL pointer. +** The pBuf element of the returned sqlite3_pcache_page object will be a +** pointer to a buffer of szPage bytes used to store the content of a +** single database page. The pExtra element of sqlite3_pcache_page will be +** a pointer to the szExtra bytes of extra storage that SQLite has requested +** for each entry in the page cache. +** +** The page to be fetched is determined by the key. ^The minimum key value +** is 1. After it has been retrieved using xFetch, the page is considered +** to be "pinned". +** +** If the requested page is already in the page cache, then the page cache +** implementation must return a pointer to the page buffer with its content +** intact. If the requested page is not already in the cache, then the +** cache implementation should use the value of the createFlag +** parameter to help it determined what action to take: +** +** +**
createFlag Behavior when page is not already in cache +**
0 Do not allocate a new page. Return NULL. +**
1 Allocate a new page if it easy and convenient to do so. +** Otherwise return NULL. +**
2 Make every effort to allocate a new page. Only return +** NULL if allocating a new page is effectively impossible. +**
+** +** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite +** will only use a createFlag of 2 after a prior call with a createFlag of 1 +** failed.)^ In between the to xFetch() calls, SQLite may +** attempt to unpin one or more cache pages by spilling the content of +** pinned pages to disk and synching the operating system disk cache. +** +** [[the xUnpin() page cache method]] +** ^xUnpin() is called by SQLite with a pointer to a currently pinned page +** as its second argument. If the third parameter, discard, is non-zero, +** then the page must be evicted from the cache. +** ^If the discard parameter is +** zero, then the page may be discarded or retained at the discretion of +** page cache implementation. ^The page cache implementation +** may choose to evict unpinned pages at any time. +** +** The cache must not perform any reference counting. A single +** call to xUnpin() unpins the page regardless of the number of prior calls +** to xFetch(). +** +** [[the xRekey() page cache methods]] +** The xRekey() method is used to change the key value associated with the +** page passed as the second argument. If the cache +** previously contains an entry associated with newKey, it must be +** discarded. ^Any prior cache entry associated with newKey is guaranteed not +** to be pinned. +** +** When SQLite calls the xTruncate() method, the cache must discard all +** existing cache entries with page numbers (keys) greater than or equal +** to the value of the iLimit parameter passed to xTruncate(). If any +** of these pages are pinned, they are implicitly unpinned, meaning that +** they can be safely discarded. +** +** [[the xDestroy() page cache method]] +** ^The xDestroy() method is used to delete a cache allocated by xCreate(). +** All resources associated with the specified cache should be freed. ^After +** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] +** handle invalid, and will not use it with any other sqlite3_pcache_methods2 +** functions. +** +** [[the xShrink() page cache method]] +** ^SQLite invokes the xShrink() method when it wants the page cache to +** free up as much of heap memory as possible. The page cache implementation +** is not obligated to free any memory, but well-behaved implementations should +** do their best. +*/ +typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; +struct sqlite3_pcache_methods2 { + int iVersion; + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); +}; + +/* +** This is the obsolete pcache_methods object that has now been replaced +** by sqlite3_pcache_methods2. This object is not used by SQLite. It is +** retained in the header file for backwards compatibility only. +*/ +typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; +struct sqlite3_pcache_methods { + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, void*, int discard); + void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); +}; + + +/* +** CAPI3REF: Online Backup Object +** +** The sqlite3_backup object records state information about an ongoing +** online backup operation. ^The sqlite3_backup object is created by +** a call to [sqlite3_backup_init()] and is destroyed by a call to +** [sqlite3_backup_finish()]. +** +** See Also: [Using the SQLite Online Backup API] +*/ +typedef struct sqlite3_backup sqlite3_backup; + +/* +** CAPI3REF: Online Backup API. +** +** The backup API copies the content of one database into another. +** It is useful either for creating backups of databases or +** for copying in-memory databases to or from persistent files. +** +** See Also: [Using the SQLite Online Backup API] +** +** ^SQLite holds a write transaction open on the destination database file +** for the duration of the backup operation. +** ^The source database is read-locked only while it is being read; +** it is not locked continuously for the entire backup operation. +** ^Thus, the backup may be performed on a live source database without +** preventing other database connections from +** reading or writing to the source database while the backup is underway. +** +** ^(To perform a backup operation: +**
    +**
  1. sqlite3_backup_init() is called once to initialize the +** backup, +**
  2. sqlite3_backup_step() is called one or more times to transfer +** the data between the two databases, and finally +**
  3. sqlite3_backup_finish() is called to release all resources +** associated with the backup operation. +**
)^ +** There should be exactly one call to sqlite3_backup_finish() for each +** successful call to sqlite3_backup_init(). +** +** [[sqlite3_backup_init()]] sqlite3_backup_init() +** +** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the +** [database connection] associated with the destination database +** and the database name, respectively. +** ^The database name is "main" for the main database, "temp" for the +** temporary database, or the name specified after the AS keyword in +** an [ATTACH] statement for an attached database. +** ^The S and M arguments passed to +** sqlite3_backup_init(D,N,S,M) identify the [database connection] +** and database name of the source database, respectively. +** ^The source and destination [database connections] (parameters S and D) +** must be different or else sqlite3_backup_init(D,N,S,M) will fail with +** an error. +** +** ^A call to sqlite3_backup_init() will fail, returning NULL, if +** there is already a read or read-write transaction open on the +** destination database. +** +** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is +** returned and an error code and error message are stored in the +** destination [database connection] D. +** ^The error code and message for the failed call to sqlite3_backup_init() +** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or +** [sqlite3_errmsg16()] functions. +** ^A successful call to sqlite3_backup_init() returns a pointer to an +** [sqlite3_backup] object. +** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and +** sqlite3_backup_finish() functions to perform the specified backup +** operation. +** +** [[sqlite3_backup_step()]] sqlite3_backup_step() +** +** ^Function sqlite3_backup_step(B,N) will copy up to N pages between +** the source and destination databases specified by [sqlite3_backup] object B. +** ^If N is negative, all remaining source pages are copied. +** ^If sqlite3_backup_step(B,N) successfully copies N pages and there +** are still more pages to be copied, then the function returns [SQLITE_OK]. +** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages +** from source to destination, then it returns [SQLITE_DONE]. +** ^If an error occurs while running sqlite3_backup_step(B,N), +** then an [error code] is returned. ^As well as [SQLITE_OK] and +** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], +** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an +** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. +** +** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if +**
    +**
  1. the destination database was opened read-only, or +**
  2. the destination database is using write-ahead-log journaling +** and the destination and source page sizes differ, or +**
  3. the destination database is an in-memory database and the +** destination and source page sizes differ. +**
)^ +** +** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then +** the [sqlite3_busy_handler | busy-handler function] +** is invoked (if one is specified). ^If the +** busy-handler returns non-zero before the lock is available, then +** [SQLITE_BUSY] is returned to the caller. ^In this case the call to +** sqlite3_backup_step() can be retried later. ^If the source +** [database connection] +** is being used to write to the source database when sqlite3_backup_step() +** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this +** case the call to sqlite3_backup_step() can be retried later on. ^(If +** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or +** [SQLITE_READONLY] is returned, then +** there is no point in retrying the call to sqlite3_backup_step(). These +** errors are considered fatal.)^ The application must accept +** that the backup operation has failed and pass the backup operation handle +** to the sqlite3_backup_finish() to release associated resources. +** +** ^The first call to sqlite3_backup_step() obtains an exclusive lock +** on the destination file. ^The exclusive lock is not released until either +** sqlite3_backup_finish() is called or the backup operation is complete +** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to +** sqlite3_backup_step() obtains a [shared lock] on the source database that +** lasts for the duration of the sqlite3_backup_step() call. +** ^Because the source database is not locked between calls to +** sqlite3_backup_step(), the source database may be modified mid-way +** through the backup process. ^If the source database is modified by an +** external process or via a database connection other than the one being +** used by the backup operation, then the backup will be automatically +** restarted by the next call to sqlite3_backup_step(). ^If the source +** database is modified by the using the same database connection as is used +** by the backup operation, then the backup database is automatically +** updated at the same time. +** +** [[sqlite3_backup_finish()]] sqlite3_backup_finish() +** +** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the +** application wishes to abandon the backup operation, the application +** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). +** ^The sqlite3_backup_finish() interfaces releases all +** resources associated with the [sqlite3_backup] object. +** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any +** active write-transaction on the destination database is rolled back. +** The [sqlite3_backup] object is invalid +** and may not be used following a call to sqlite3_backup_finish(). +** +** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no +** sqlite3_backup_step() errors occurred, regardless or whether or not +** sqlite3_backup_step() completed. +** ^If an out-of-memory condition or IO error occurred during any prior +** sqlite3_backup_step() call on the same [sqlite3_backup] object, then +** sqlite3_backup_finish() returns the corresponding [error code]. +** +** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() +** is not a permanent error and does not affect the return value of +** sqlite3_backup_finish(). +** +** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] +** sqlite3_backup_remaining() and sqlite3_backup_pagecount() +** +** ^The sqlite3_backup_remaining() routine returns the number of pages still +** to be backed up at the conclusion of the most recent sqlite3_backup_step(). +** ^The sqlite3_backup_pagecount() routine returns the total number of pages +** in the source database at the conclusion of the most recent +** sqlite3_backup_step(). +** ^(The values returned by these functions are only updated by +** sqlite3_backup_step(). If the source database is modified in a way that +** changes the size of the source database or the number of pages remaining, +** those changes are not reflected in the output of sqlite3_backup_pagecount() +** and sqlite3_backup_remaining() until after the next +** sqlite3_backup_step().)^ +** +** Concurrent Usage of Database Handles +** +** ^The source [database connection] may be used by the application for other +** purposes while a backup operation is underway or being initialized. +** ^If SQLite is compiled and configured to support threadsafe database +** connections, then the source database connection may be used concurrently +** from within other threads. +** +** However, the application must guarantee that the destination +** [database connection] is not passed to any other API (by any thread) after +** sqlite3_backup_init() is called and before the corresponding call to +** sqlite3_backup_finish(). SQLite does not currently check to see +** if the application incorrectly accesses the destination [database connection] +** and so no error code is reported, but the operations may malfunction +** nevertheless. Use of the destination database connection while a +** backup is in progress might also also cause a mutex deadlock. +** +** If running in [shared cache mode], the application must +** guarantee that the shared cache used by the destination database +** is not accessed while the backup is running. In practice this means +** that the application must guarantee that the disk file being +** backed up to is not accessed by any connection within the process, +** not just the specific connection that was passed to sqlite3_backup_init(). +** +** The [sqlite3_backup] object itself is partially threadsafe. Multiple +** threads may safely make multiple concurrent calls to sqlite3_backup_step(). +** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() +** APIs are not strictly speaking threadsafe. If they are invoked at the +** same time as another thread is invoking sqlite3_backup_step() it is +** possible that they return invalid values. +*/ +SQLITE_API sqlite3_backup *sqlite3_backup_init( + sqlite3 *pDest, /* Destination database handle */ + const char *zDestName, /* Destination database name */ + sqlite3 *pSource, /* Source database handle */ + const char *zSourceName /* Source database name */ +); +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); + +/* +** CAPI3REF: Unlock Notification +** METHOD: sqlite3 +** +** ^When running in shared-cache mode, a database operation may fail with +** an [SQLITE_LOCKED] error if the required locks on the shared-cache or +** individual tables within the shared-cache cannot be obtained. See +** [SQLite Shared-Cache Mode] for a description of shared-cache locking. +** ^This API may be used to register a callback that SQLite will invoke +** when the connection currently holding the required lock relinquishes it. +** ^This API is only available if the library was compiled with the +** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. +** +** See Also: [Using the SQLite Unlock Notification Feature]. +** +** ^Shared-cache locks are released when a database connection concludes +** its current transaction, either by committing it or rolling it back. +** +** ^When a connection (known as the blocked connection) fails to obtain a +** shared-cache lock and SQLITE_LOCKED is returned to the caller, the +** identity of the database connection (the blocking connection) that +** has locked the required resource is stored internally. ^After an +** application receives an SQLITE_LOCKED error, it may call the +** sqlite3_unlock_notify() method with the blocked connection handle as +** the first argument to register for a callback that will be invoked +** when the blocking connections current transaction is concluded. ^The +** callback is invoked from within the [sqlite3_step] or [sqlite3_close] +** call that concludes the blocking connections transaction. +** +** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, +** there is a chance that the blocking connection will have already +** concluded its transaction by the time sqlite3_unlock_notify() is invoked. +** If this happens, then the specified callback is invoked immediately, +** from within the call to sqlite3_unlock_notify().)^ +** +** ^If the blocked connection is attempting to obtain a write-lock on a +** shared-cache table, and more than one other connection currently holds +** a read-lock on the same table, then SQLite arbitrarily selects one of +** the other connections to use as the blocking connection. +** +** ^(There may be at most one unlock-notify callback registered by a +** blocked connection. If sqlite3_unlock_notify() is called when the +** blocked connection already has a registered unlock-notify callback, +** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is +** called with a NULL pointer as its second argument, then any existing +** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback may also be canceled by closing the blocked +** connection using [sqlite3_close()]. +** +** The unlock-notify callback is not reentrant. If an application invokes +** any sqlite3_xxx API functions from within an unlock-notify callback, a +** crash or deadlock may be the result. +** +** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always +** returns SQLITE_OK. +** +** Callback Invocation Details +** +** When an unlock-notify callback is registered, the application provides a +** single void* pointer that is passed to the callback when it is invoked. +** However, the signature of the callback function allows SQLite to pass +** it an array of void* context pointers. The first argument passed to +** an unlock-notify callback is a pointer to an array of void* pointers, +** and the second is the number of entries in the array. +** +** When a blocking connections transaction is concluded, there may be +** more than one blocked connection that has registered for an unlock-notify +** callback. ^If two or more such blocked connections have specified the +** same callback function, then instead of invoking the callback function +** multiple times, it is invoked once with the set of void* context pointers +** specified by the blocked connections bundled together into an array. +** This gives the application an opportunity to prioritize any actions +** related to the set of unblocked database connections. +** +** Deadlock Detection +** +** Assuming that after registering for an unlock-notify callback a +** database waits for the callback to be issued before taking any further +** action (a reasonable assumption), then using this API may cause the +** application to deadlock. For example, if connection X is waiting for +** connection Y's transaction to be concluded, and similarly connection +** Y is waiting on connection X's transaction, then neither connection +** will proceed and the system may remain deadlocked indefinitely. +** +** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock +** detection. ^If a given call to sqlite3_unlock_notify() would put the +** system in a deadlocked state, then SQLITE_LOCKED is returned and no +** unlock-notify callback is registered. The system is said to be in +** a deadlocked state if connection A has registered for an unlock-notify +** callback on the conclusion of connection B's transaction, and connection +** B has itself registered for an unlock-notify callback when connection +** A's transaction is concluded. ^Indirect deadlock is also detected, so +** the system is also considered to be deadlocked if connection B has +** registered for an unlock-notify callback on the conclusion of connection +** C's transaction, where connection C is waiting on connection A. ^Any +** number of levels of indirection are allowed. +** +** The "DROP TABLE" Exception +** +** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost +** always appropriate to call sqlite3_unlock_notify(). There is however, +** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, +** SQLite checks if there are any currently executing SELECT statements +** that belong to the same connection. If there are, SQLITE_LOCKED is +** returned. In this case there is no "blocking connection", so invoking +** sqlite3_unlock_notify() results in the unlock-notify callback being +** invoked immediately. If the application then re-attempts the "DROP TABLE" +** or "DROP INDEX" query, an infinite loop might be the result. +** +** One way around this problem is to check the extended error code returned +** by an sqlite3_step() call. ^(If there is a blocking connection, then the +** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in +** the special "DROP TABLE/INDEX" case, the extended error code is just +** SQLITE_LOCKED.)^ +*/ +SQLITE_API int sqlite3_unlock_notify( + sqlite3 *pBlocked, /* Waiting connection */ + void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ + void *pNotifyArg /* Argument to pass to xNotify */ +); + + +/* +** CAPI3REF: String Comparison +** +** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications +** and extensions to compare the contents of two buffers containing UTF-8 +** strings in a case-independent fashion, using the same definition of "case +** independence" that SQLite uses internally when comparing identifiers. +*/ +SQLITE_API int sqlite3_stricmp(const char *, const char *); +SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); + +/* +** CAPI3REF: String Globbing +* +** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if +** string X matches the [GLOB] pattern P. +** ^The definition of [GLOB] pattern matching used in +** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the +** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function +** is case sensitive. +** +** Note that this routine returns zero on a match and non-zero if the strings +** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. +** +** See also: [sqlite3_strlike()]. +*/ +SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); + +/* +** CAPI3REF: String LIKE Matching +* +** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if +** string X matches the [LIKE] pattern P with escape character E. +** ^The definition of [LIKE] pattern matching used in +** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E" +** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without +** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0. +** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case +** insensitive - equivalent upper and lower case ASCII characters match +** one another. +** +** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though +** only ASCII characters are case folded. +** +** Note that this routine returns zero on a match and non-zero if the strings +** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. +** +** See also: [sqlite3_strglob()]. +*/ +SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); + +/* +** CAPI3REF: Error Logging Interface +** +** ^The [sqlite3_log()] interface writes a message into the [error log] +** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. +** ^If logging is enabled, the zFormat string and subsequent arguments are +** used with [sqlite3_snprintf()] to generate the final output string. +** +** The sqlite3_log() interface is intended for use by extensions such as +** virtual tables, collating functions, and SQL functions. While there is +** nothing to prevent an application from calling sqlite3_log(), doing so +** is considered bad form. +** +** The zFormat string must not be NULL. +** +** To avoid deadlocks and other threading problems, the sqlite3_log() routine +** will not use dynamically allocated memory. The log message is stored in +** a fixed-length buffer on the stack. If the log message is longer than +** a few hundred characters, it will be truncated to the length of the +** buffer. +*/ +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); + +/* +** CAPI3REF: Write-Ahead Log Commit Hook +** METHOD: sqlite3 +** +** ^The [sqlite3_wal_hook()] function is used to register a callback that +** is invoked each time data is committed to a database in wal mode. +** +** ^(The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released)^, so the implementation +** may read, write or [checkpoint] the database as required. +** +** ^The first parameter passed to the callback function when it is invoked +** is a copy of the third parameter passed to sqlite3_wal_hook() when +** registering the callback. ^The second is a copy of the database handle. +** ^The third parameter is the name of the database that was written to - +** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter +** is the number of pages currently in the write-ahead log file, +** including those that were just committed. +** +** The callback function should normally return [SQLITE_OK]. ^If an error +** code is returned, that error will propagate back up through the +** SQLite code base to cause the statement that provoked the callback +** to report an error, though the commit will have still occurred. If the +** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value +** that does not correspond to any valid SQLite error code, the results +** are undefined. +** +** A single database handle may have at most a single write-ahead log callback +** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any +** previously registered write-ahead log callback. ^Note that the +** [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will +** overwrite any prior [sqlite3_wal_hook()] settings. +*/ +SQLITE_API void *sqlite3_wal_hook( + sqlite3*, + int(*)(void *,sqlite3*,const char*,int), + void* +); + +/* +** CAPI3REF: Configure an auto-checkpoint +** METHOD: sqlite3 +** +** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around +** [sqlite3_wal_hook()] that causes any database on [database connection] D +** to automatically [checkpoint] +** after committing a transaction if there are N or +** more frames in the [write-ahead log] file. ^Passing zero or +** a negative value as the nFrame parameter disables automatic +** checkpoints entirely. +** +** ^The callback registered by this function replaces any existing callback +** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback +** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism +** configured by this function. +** +** ^The [wal_autocheckpoint pragma] can be used to invoke this interface +** from SQL. +** +** ^Checkpoints initiated by this mechanism are +** [sqlite3_wal_checkpoint_v2|PASSIVE]. +** +** ^Every new [database connection] defaults to having the auto-checkpoint +** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] +** pages. The use of this interface +** is only necessary if the default setting is found to be suboptimal +** for a particular application. +*/ +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); + +/* +** CAPI3REF: Checkpoint a database +** METHOD: sqlite3 +** +** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to +** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ +** +** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the +** [write-ahead log] for database X on [database connection] D to be +** transferred into the database file and for the write-ahead log to +** be reset. See the [checkpointing] documentation for addition +** information. +** +** This interface used to be the only way to cause a checkpoint to +** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()] +** interface was added. This interface is retained for backwards +** compatibility and as a convenience for applications that need to manually +** start a callback but which do not need the full power (and corresponding +** complication) of [sqlite3_wal_checkpoint_v2()]. +*/ +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); + +/* +** CAPI3REF: Checkpoint a database +** METHOD: sqlite3 +** +** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint +** operation on database X of [database connection] D in mode M. Status +** information is written back into integers pointed to by L and C.)^ +** ^(The M parameter must be a valid [checkpoint mode]:)^ +** +**
+**
SQLITE_CHECKPOINT_PASSIVE
+** ^Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish, then sync the database file if all frames +** in the log were checkpointed. ^The [busy-handler callback] +** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. +** ^On the other hand, passive mode might leave the checkpoint unfinished +** if there are concurrent readers or writers. +** +**
SQLITE_CHECKPOINT_FULL
+** ^This mode blocks (it invokes the +** [sqlite3_busy_handler|busy-handler callback]) until there is no +** database writer and all readers are reading from the most recent database +** snapshot. ^It then checkpoints all frames in the log file and syncs the +** database file. ^This mode blocks new database writers while it is pending, +** but new database readers are allowed to continue unimpeded. +** +**
SQLITE_CHECKPOINT_RESTART
+** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition +** that after checkpointing the log file it blocks (calls the +** [busy-handler callback]) +** until all readers are reading from the database file only. ^This ensures +** that the next writer will restart the log file from the beginning. +** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new +** database writer attempts while it is pending, but does not impede readers. +** +**
SQLITE_CHECKPOINT_TRUNCATE
+** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the +** addition that it also truncates the log file to zero bytes just prior +** to a successful return. +**
+** +** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in +** the log file or to -1 if the checkpoint could not run because +** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not +** NULL,then *pnCkpt is set to the total number of checkpointed frames in the +** log file (including any that were already checkpointed before the function +** was called) or to -1 if the checkpoint could not run due to an error or +** because the database is not in WAL mode. ^Note that upon successful +** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been +** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. +** +** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a +** busy-handler configured, it will not be invoked in this case. +** +** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the +** exclusive "writer" lock on the database file. ^If the writer lock cannot be +** obtained immediately, and a busy-handler is configured, it is invoked and +** the writer lock retried until either the busy-handler returns 0 or the lock +** is successfully obtained. ^The busy-handler is also invoked while waiting for +** database readers as described above. ^If the busy-handler returns 0 before +** the writer lock is obtained or while waiting for database readers, the +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** without blocking any further. ^SQLITE_BUSY is returned in this case. +** +** ^If parameter zDb is NULL or points to a zero length string, then the +** specified operation is attempted on all WAL databases [attached] to +** [database connection] db. In this case the +** values written to output parameters *pnLog and *pnCkpt are undefined. ^If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned at the end. ^If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code is returned to the caller immediately. ^If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** databases, SQLITE_OK is returned. +** +** ^If database zDb is the name of an attached database that is not in WAL +** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If +** zDb is not NULL (or a zero length string) and is not the name of any +** attached database, SQLITE_ERROR is returned to the caller. +** +** ^Unless it returns SQLITE_MISUSE, +** the sqlite3_wal_checkpoint_v2() interface +** sets the error information that is queried by +** [sqlite3_errcode()] and [sqlite3_errmsg()]. +** +** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface +** from SQL. +*/ +SQLITE_API int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +); + +/* +** CAPI3REF: Checkpoint Mode Values +** KEYWORDS: {checkpoint mode} +** +** These constants define all valid values for the "checkpoint mode" passed +** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. +** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the +** meaning of each of these checkpoint modes. +*/ +#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ +#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ +#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */ +#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ + +/* +** CAPI3REF: Virtual Table Interface Configuration +** +** This function may be called by either the [xConnect] or [xCreate] method +** of a [virtual table] implementation to configure +** various facets of the virtual table interface. +** +** If this interface is invoked outside the context of an xConnect or +** xCreate virtual table method then the behavior is undefined. +** +** At present, there is only one option that may be configured using +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options +** may be added in the future. +*/ +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Virtual Table Configuration Options +** +** These macros define the various options to the +** [sqlite3_vtab_config()] interface that [virtual table] implementations +** can use to customize and optimize their behavior. +** +**
+**
SQLITE_VTAB_CONSTRAINT_SUPPORT +**
Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, +** where X is an integer. If X is zero, then the [virtual table] whose +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not +** support constraints. In this configuration (which is the default) if +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been +** specified as part of the users SQL statement, regardless of the actual +** ON CONFLICT mode specified. +** +** If X is non-zero, then the virtual table implementation guarantees +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before +** any modifications to internal or persistent data structures have been made. +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** is able to roll back a statement or database transaction, and abandon +** or continue processing the current SQL statement as appropriate. +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode +** had been ABORT. +** +** Virtual table implementations that are required to handle OR REPLACE +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should +** silently replace the appropriate rows within the xUpdate callback and +** return SQLITE_OK. Or, if this is not possible, it may return +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** constraint handling. +**
+*/ +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 + +/* +** CAPI3REF: Determine The Virtual Table Conflict Policy +** +** This function may only be called from within a call to the [xUpdate] method +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode +** of the SQL statement that triggered the call to the [xUpdate] method of the +** [virtual table]. +*/ +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); + +/* +** CAPI3REF: Conflict resolution modes +** KEYWORDS: {conflict resolution mode} +** +** These constants are returned by [sqlite3_vtab_on_conflict()] to +** inform a [virtual table] implementation what the [ON CONFLICT] mode +** is for the SQL statement being evaluated. +** +** Note that the [SQLITE_IGNORE] constant is also used as a potential +** return value from the [sqlite3_set_authorizer()] callback and that +** [SQLITE_ABORT] is also a [result code]. +*/ +#define SQLITE_ROLLBACK 1 +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ +#define SQLITE_FAIL 3 +/* #define SQLITE_ABORT 4 // Also an error code */ +#define SQLITE_REPLACE 5 + +/* +** CAPI3REF: Prepared Statement Scan Status Opcodes +** KEYWORDS: {scanstatus options} +** +** The following constants can be used for the T parameter to the +** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a +** different metric for sqlite3_stmt_scanstatus() to return. +** +** When the value returned to V is a string, space to hold that string is +** managed by the prepared statement S and will be automatically freed when +** S is finalized. +** +**
+** [[SQLITE_SCANSTAT_NLOOP]]
SQLITE_SCANSTAT_NLOOP
+**
^The [sqlite3_int64] variable pointed to by the T parameter will be +** set to the total number of times that the X-th loop has run.
+** +** [[SQLITE_SCANSTAT_NVISIT]]
SQLITE_SCANSTAT_NVISIT
+**
^The [sqlite3_int64] variable pointed to by the T parameter will be set +** to the total number of rows examined by all iterations of the X-th loop.
+** +** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
+**
^The "double" variable pointed to by the T parameter will be set to the +** query planner's estimate for the average number of rows output from each +** iteration of the X-th loop. If the query planner's estimates was accurate, +** then this value will approximate the quotient NVISIT/NLOOP and the +** product of this value for all prior loops with the same SELECTID will +** be the NLOOP value for the current loop. +** +** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
+**
^The "const char *" variable pointed to by the T parameter will be set +** to a zero-terminated UTF-8 string containing the name of the index or table +** used for the X-th loop. +** +** [[SQLITE_SCANSTAT_EXPLAIN]]
SQLITE_SCANSTAT_EXPLAIN
+**
^The "const char *" variable pointed to by the T parameter will be set +** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] +** description for the X-th loop. +** +** [[SQLITE_SCANSTAT_SELECTID]]
SQLITE_SCANSTAT_SELECT
+**
^The "int" variable pointed to by the T parameter will be set to the +** "select-id" for the X-th loop. The select-id identifies which query or +** subquery the loop is part of. The main query has a select-id of zero. +** The select-id is the same value as is output in the first column +** of an [EXPLAIN QUERY PLAN] query. +**
+*/ +#define SQLITE_SCANSTAT_NLOOP 0 +#define SQLITE_SCANSTAT_NVISIT 1 +#define SQLITE_SCANSTAT_EST 2 +#define SQLITE_SCANSTAT_NAME 3 +#define SQLITE_SCANSTAT_EXPLAIN 4 +#define SQLITE_SCANSTAT_SELECTID 5 + +/* +** CAPI3REF: Prepared Statement Scan Status +** METHOD: sqlite3_stmt +** +** This interface returns information about the predicted and measured +** performance for pStmt. Advanced applications can use this +** interface to compare the predicted and the measured performance and +** issue warnings and/or rerun [ANALYZE] if discrepancies are found. +** +** Since this interface is expected to be rarely used, it is only +** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] +** compile-time option. +** +** The "iScanStatusOp" parameter determines which status information to return. +** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior +** of this interface is undefined. +** ^The requested measurement is written into a variable pointed to by +** the "pOut" parameter. +** Parameter "idx" identifies the specific loop to retrieve statistics for. +** Loops are numbered starting from zero. ^If idx is out of range - less than +** zero or greater than or equal to the total number of loops used to implement +** the statement - a non-zero value is returned and the variable that pOut +** points to is unchanged. +** +** ^Statistics might not be available for all loops in all statements. ^In cases +** where there exist loops with no available statistics, this function behaves +** as if the loop did not exist - it returns non-zero and leave the variable +** that pOut points to unchanged. +** +** See also: [sqlite3_stmt_scanstatus_reset()] +*/ +SQLITE_API int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ + void *pOut /* Result written here */ +); + +/* +** CAPI3REF: Zero Scan-Status Counters +** METHOD: sqlite3_stmt +** +** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. +** +** This API is only available if the library is built with pre-processor +** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. +*/ +SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); + +/* +** CAPI3REF: Flush caches to disk mid-transaction +** +** ^If a write-transaction is open on [database connection] D when the +** [sqlite3_db_cacheflush(D)] interface invoked, any dirty +** pages in the pager-cache that are not currently in use are written out +** to disk. A dirty page may be in use if a database cursor created by an +** active SQL statement is reading from it, or if it is page 1 of a database +** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] +** interface flushes caches for all schemas - "main", "temp", and +** any [attached] databases. +** +** ^If this function needs to obtain extra database locks before dirty pages +** can be flushed to disk, it does so. ^If those locks cannot be obtained +** immediately and there is a busy-handler callback configured, it is invoked +** in the usual manner. ^If the required lock still cannot be obtained, then +** the database is skipped and an attempt made to flush any dirty pages +** belonging to the next (if any) database. ^If any databases are skipped +** because locks cannot be obtained, but no other error occurs, this +** function returns SQLITE_BUSY. +** +** ^If any other error occurs while flushing dirty pages to disk (for +** example an IO error or out-of-memory condition), then processing is +** abandoned and an SQLite [error code] is returned to the caller immediately. +** +** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK. +** +** ^This function does not set the database handle error code or message +** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. +*/ +SQLITE_API int sqlite3_db_cacheflush(sqlite3*); + +/* +** CAPI3REF: The pre-update hook. +** +** ^These interfaces are only available if SQLite is compiled using the +** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. +** +** ^The [sqlite3_preupdate_hook()] interface registers a callback function +** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation +** on a [rowid table]. +** ^At most one preupdate hook may be registered at a time on a single +** [database connection]; each call to [sqlite3_preupdate_hook()] overrides +** the previous setting. +** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] +** with a NULL pointer as the second parameter. +** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as +** the first parameter to callbacks. +** +** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate +** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID] +** tables. +** +** ^The second parameter to the preupdate callback is a pointer to +** the [database connection] that registered the preupdate hook. +** ^The third parameter to the preupdate callback is one of the constants +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the +** kind of update operation that is about to occur. +** ^(The fourth parameter to the preupdate callback is the name of the +** database within the database connection that is being modified. This +** will be "main" for the main database or "temp" for TEMP tables or +** the name given after the AS keyword in the [ATTACH] statement for attached +** databases.)^ +** ^The fifth parameter to the preupdate callback is the name of the +** table that is being modified. +** ^The sixth parameter to the preupdate callback is the initial [rowid] of the +** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is +** undefined for SQLITE_INSERT changes. +** ^The seventh parameter to the preupdate callback is the final [rowid] of +** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is +** undefined for SQLITE_DELETE changes. +** +** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], +** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces +** provide additional information about a preupdate event. These routines +** may only be called from within a preupdate callback. Invoking any of +** these routines from outside of a preupdate callback or with a +** [database connection] pointer that is different from the one supplied +** to the preupdate callback results in undefined and probably undesirable +** behavior. +** +** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns +** in the row that is being inserted, updated, or deleted. +** +** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row before it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE +** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row after it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE +** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate +** callback was invoked as a result of a direct insert, update, or delete +** operation; or 1 for inserts, updates, or deletes invoked by top-level +** triggers; or 2 for changes resulting from triggers called by top-level +** triggers; and so forth. +** +** See also: [sqlite3_update_hook()] +*/ +SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook( + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void* +); +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *); +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *); +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); + +/* +** CAPI3REF: Low-level system error code +** +** ^Attempt to return the underlying operating system error code or error +** number that caused the most recent I/O error or failure to open a file. +** The return value is OS-dependent. For example, on unix systems, after +** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be +** called to get back the underlying "errno" that caused the problem, such +** as ENOSPC, EAUTH, EISDIR, and so forth. +*/ +SQLITE_API int sqlite3_system_errno(sqlite3*); + +/* +** CAPI3REF: Database Snapshot +** KEYWORDS: {snapshot} +** EXPERIMENTAL +** +** An instance of the snapshot object records the state of a [WAL mode] +** database for some specific point in history. +** +** In [WAL mode], multiple [database connections] that are open on the +** same database file can each be reading a different historical version +** of the database file. When a [database connection] begins a read +** transaction, that connection sees an unchanging copy of the database +** as it existed for the point in time when the transaction first started. +** Subsequent changes to the database from other connections are not seen +** by the reader until a new read transaction is started. +** +** The sqlite3_snapshot object records state information about an historical +** version of the database file so that it is possible to later open a new read +** transaction that sees that historical version of the database rather than +** the most recent version. +** +** The constructor for this object is [sqlite3_snapshot_get()]. The +** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer +** to an historical snapshot (if possible). The destructor for +** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. +*/ +typedef struct sqlite3_snapshot sqlite3_snapshot; + +/* +** CAPI3REF: Record A Database Snapshot +** EXPERIMENTAL +** +** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a +** new [sqlite3_snapshot] object that records the current state of +** schema S in database connection D. ^On success, the +** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly +** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. +** ^If schema S of [database connection] D is not a [WAL mode] database +** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)] +** leaves the *P value unchanged and returns an appropriate [error code]. +** +** The [sqlite3_snapshot] object returned from a successful call to +** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] +** to avoid a memory leak. +** +** The [sqlite3_snapshot_get()] interface is only available when the +** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot **ppSnapshot +); + +/* +** CAPI3REF: Start a read transaction on an historical snapshot +** EXPERIMENTAL +** +** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a +** read transaction for schema S of +** [database connection] D such that the read transaction +** refers to historical [snapshot] P, rather than the most +** recent change to the database. +** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success +** or an appropriate [error code] if it fails. +** +** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be +** the first operation following the [BEGIN] that takes the schema S +** out of [autocommit mode]. +** ^In other words, schema S must not currently be in +** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the +** database connection D must be out of [autocommit mode]. +** ^A [snapshot] will fail to open if it has been overwritten by a +** [checkpoint]. +** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the +** database connection D does not know that the database file for +** schema S is in [WAL mode]. A database connection might not know +** that the database file is in [WAL mode] if there has been no prior +** I/O on that database connection, or if the database entered [WAL mode] +** after the most recent I/O on the database connection.)^ +** (Hint: Run "[PRAGMA application_id]" against a newly opened +** database connection in order to make it ready to use snapshots.) +** +** The [sqlite3_snapshot_open()] interface is only available when the +** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot *pSnapshot +); + +/* +** CAPI3REF: Destroy a snapshot +** EXPERIMENTAL +** +** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. +** The application must eventually free every [sqlite3_snapshot] object +** using this routine to avoid a memory leak. +** +** The [sqlite3_snapshot_free()] interface is only available when the +** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +*/ +SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); + +/* +** CAPI3REF: Compare the ages of two snapshot handles. +** EXPERIMENTAL +** +** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages +** of two valid snapshot handles. +** +** If the two snapshot handles are not associated with the same database +** file, the result of the comparison is undefined. +** +** Additionally, the result of the comparison is only valid if both of the +** snapshot handles were obtained by calling sqlite3_snapshot_get() since the +** last time the wal file was deleted. The wal file is deleted when the +** database is changed back to rollback mode or when the number of database +** clients drops to zero. If either snapshot handle was obtained before the +** wal file was last deleted, the value returned by this function +** is undefined. +** +** Otherwise, this API returns a negative value if P1 refers to an older +** snapshot than P2, zero if the two handles refer to the same database +** snapshot, and a positive value if P1 is a newer snapshot than P2. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 +); + +/* +** Undo the hack that converts floating point types to integer for +** builds on processors without floating point support. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# undef double +#endif + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif +#endif /* SQLITE3_H */ + +/******** Begin file sqlite3rtree.h *********/ +/* +** 2010 August 30 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + +#ifndef _SQLITE3RTREE_H_ +#define _SQLITE3RTREE_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; +typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; + +/* The double-precision datatype used by RTree depends on the +** SQLITE_RTREE_INT_ONLY compile-time option. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 sqlite3_rtree_dbl; +#else + typedef double sqlite3_rtree_dbl; +#endif + +/* +** Register a geometry callback named zGeom that can be used as part of an +** R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zGeom(... params ...) +*/ +SQLITE_API int sqlite3_rtree_geometry_callback( + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), + void *pContext +); + + +/* +** A pointer to a structure of the following type is passed as the first +** argument to callbacks registered using rtree_geometry_callback(). +*/ +struct sqlite3_rtree_geometry { + void *pContext; /* Copy of pContext passed to s_r_g_c() */ + int nParam; /* Size of array aParam[] */ + sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ + void *pUser; /* Callback implementation user data */ + void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ +}; + +/* +** Register a 2nd-generation geometry callback named zScore that can be +** used as part of an R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) +*/ +SQLITE_API int sqlite3_rtree_query_callback( + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) +); + + +/* +** A pointer to a structure of the following type is passed as the +** argument to scored geometry callback registered using +** sqlite3_rtree_query_callback(). +** +** Note that the first 5 fields of this structure are identical to +** sqlite3_rtree_geometry. This structure is a subclass of +** sqlite3_rtree_geometry. +*/ +struct sqlite3_rtree_query_info { + void *pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl *aParam; /* value of function parameters */ + void *pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ + unsigned int *anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visiblity */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ + /* The following fields are only available in 3.8.11 and later */ + sqlite3_value **apSqlParam; /* Original SQL values of parameters */ +}; + +/* +** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. +*/ +#define NOT_WITHIN 0 /* Object completely outside of query region */ +#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ +#define FULLY_WITHIN 2 /* Object fully contained within query region */ + + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* ifndef _SQLITE3RTREE_H_ */ + +/******** End of sqlite3rtree.h *********/ +/******** Begin file sqlite3session.h *********/ + +#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) +#define __SQLITESESSION_H_ 1 + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + + +/* +** CAPI3REF: Session Object Handle +*/ +typedef struct sqlite3_session sqlite3_session; + +/* +** CAPI3REF: Changeset Iterator Handle +*/ +typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; + +/* +** CAPI3REF: Create A New Session Object +** +** Create a new session object attached to database handle db. If successful, +** a pointer to the new object is written to *ppSession and SQLITE_OK is +** returned. If an error occurs, *ppSession is set to NULL and an SQLite +** error code (e.g. SQLITE_NOMEM) is returned. +** +** It is possible to create multiple session objects attached to a single +** database handle. +** +** Session objects created using this function should be deleted using the +** [sqlite3session_delete()] function before the database handle that they +** are attached to is itself closed. If the database handle is closed before +** the session object is deleted, then the results of calling any session +** module function, including [sqlite3session_delete()] on the session object +** are undefined. +** +** Because the session module uses the [sqlite3_preupdate_hook()] API, it +** is not possible for an application to register a pre-update hook on a +** database handle that has one or more session objects attached. Nor is +** it possible to create a session object attached to a database handle for +** which a pre-update hook is already defined. The results of attempting +** either of these things are undefined. +** +** The session object will be used to create changesets for tables in +** database zDb, where zDb is either "main", or "temp", or the name of an +** attached database. It is not an error if database zDb is not attached +** to the database when the session object is created. +*/ +int sqlite3session_create( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (e.g. "main") */ + sqlite3_session **ppSession /* OUT: New session object */ +); + +/* +** CAPI3REF: Delete A Session Object +** +** Delete a session object previously allocated using +** [sqlite3session_create()]. Once a session object has been deleted, the +** results of attempting to use pSession with any other session module +** function are undefined. +** +** Session objects must be deleted before the database handle to which they +** are attached is closed. Refer to the documentation for +** [sqlite3session_create()] for details. +*/ +void sqlite3session_delete(sqlite3_session *pSession); + + +/* +** CAPI3REF: Enable Or Disable A Session Object +** +** Enable or disable the recording of changes by a session object. When +** enabled, a session object records changes made to the database. When +** disabled - it does not. A newly created session object is enabled. +** Refer to the documentation for [sqlite3session_changeset()] for further +** details regarding how enabling and disabling a session object affects +** the eventual changesets. +** +** Passing zero to this function disables the session. Passing a value +** greater than zero enables it. Passing a value less than zero is a +** no-op, and may be used to query the current state of the session. +** +** The return value indicates the final state of the session object: 0 if +** the session is disabled, or 1 if it is enabled. +*/ +int sqlite3session_enable(sqlite3_session *pSession, int bEnable); + +/* +** CAPI3REF: Set Or Clear the Indirect Change Flag +** +** Each change recorded by a session object is marked as either direct or +** indirect. A change is marked as indirect if either: +** +**
    +**
  • The session object "indirect" flag is set when the change is +** made, or +**
  • The change is made by an SQL trigger or foreign key action +** instead of directly as a result of a users SQL statement. +**
+** +** If a single row is affected by more than one operation within a session, +** then the change is considered indirect if all operations meet the criteria +** for an indirect change above, or direct otherwise. +** +** This function is used to set, clear or query the session object indirect +** flag. If the second argument passed to this function is zero, then the +** indirect flag is cleared. If it is greater than zero, the indirect flag +** is set. Passing a value less than zero does not modify the current value +** of the indirect flag, and may be used to query the current state of the +** indirect flag for the specified session object. +** +** The return value indicates the final state of the indirect flag: 0 if +** it is clear, or 1 if it is set. +*/ +int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); + +/* +** CAPI3REF: Attach A Table To A Session Object +** +** If argument zTab is not NULL, then it is the name of a table to attach +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See +** documentation for [sqlite3session_changeset()] for further details. +** +** Or, if argument zTab is NULL, then changes are recorded for all tables +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for +** the new tables are also recorded. +** +** Changes can only be recorded for tables that have a PRIMARY KEY explicitly +** defined as part of their CREATE TABLE statement. It does not matter if the +** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY +** KEY may consist of a single column, or may be a composite key. +** +** It is not an error if the named table does not exist in the database. Nor +** is it an error if the named table does not have a PRIMARY KEY. However, +** no changes will be recorded in either of these scenarios. +** +** Changes are not recorded for individual rows that have NULL values stored +** in one or more of their PRIMARY KEY columns. +** +** SQLITE_OK is returned if the call completes without error. Or, if an error +** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. +*/ +int sqlite3session_attach( + sqlite3_session *pSession, /* Session object */ + const char *zTab /* Table name */ +); + +/* +** CAPI3REF: Set a table filter on a Session Object. +** +** The second argument (xFilter) is the "filter callback". For changes to rows +** in tables that are not attached to the Session object, the filter is called +** to determine whether changes to the table's rows should be tracked or not. +** If xFilter returns 0, changes is not tracked. Note that once a table is +** attached, xFilter will not be called again. +*/ +void sqlite3session_table_filter( + sqlite3_session *pSession, /* Session object */ + int(*xFilter)( + void *pCtx, /* Copy of third arg to _filter_table() */ + const char *zTab /* Table name */ + ), + void *pCtx /* First argument passed to xFilter */ +); + +/* +** CAPI3REF: Generate A Changeset From A Session Object +** +** Obtain a changeset containing changes to the tables attached to the +** session object passed as the first argument. If successful, +** set *ppChangeset to point to a buffer containing the changeset +** and *pnChangeset to the size of the changeset in bytes before returning +** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to +** zero and return an SQLite error code. +** +** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, +** each representing a change to a single row of an attached table. An INSERT +** change contains the values of each field of a new database row. A DELETE +** contains the original values of each field of a deleted database row. An +** UPDATE change contains the original values of each field of an updated +** database row along with the updated values for each updated non-primary-key +** column. It is not possible for an UPDATE change to represent a change that +** modifies the values of primary key columns. If such a change is made, it +** is represented in a changeset as a DELETE followed by an INSERT. +** +** Changes are not recorded for rows that have NULL values stored in one or +** more of their PRIMARY KEY columns. If such a row is inserted or deleted, +** no corresponding change is present in the changesets returned by this +** function. If an existing row with one or more NULL values stored in +** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, +** only an INSERT is appears in the changeset. Similarly, if an existing row +** with non-NULL PRIMARY KEY values is updated so that one or more of its +** PRIMARY KEY columns are set to NULL, the resulting changeset contains a +** DELETE change only. +** +** The contents of a changeset may be traversed using an iterator created +** using the [sqlite3changeset_start()] API. A changeset may be applied to +** a database with a compatible schema using the [sqlite3changeset_apply()] +** API. +** +** Within a changeset generated by this function, all changes related to a +** single table are grouped together. In other words, when iterating through +** a changeset or when applying a changeset to a database, all changes related +** to a single table are processed before moving on to the next table. Tables +** are sorted in the same order in which they were attached (or auto-attached) +** to the sqlite3_session object. The order in which the changes related to +** a single table are stored is undefined. +** +** Following a successful call to this function, it is the responsibility of +** the caller to eventually free the buffer that *ppChangeset points to using +** [sqlite3_free()]. +** +**

Changeset Generation

+** +** Once a table has been attached to a session object, the session object +** records the primary key values of all new rows inserted into the table. +** It also records the original primary key and other column values of any +** deleted or updated rows. For each unique primary key value, data is only +** recorded once - the first time a row with said primary key is inserted, +** updated or deleted in the lifetime of the session. +** +** There is one exception to the previous paragraph: when a row is inserted, +** updated or deleted, if one or more of its primary key columns contain a +** NULL value, no record of the change is made. +** +** The session object therefore accumulates two types of records - those +** that consist of primary key values only (created when the user inserts +** a new record) and those that consist of the primary key values and the +** original values of other table columns (created when the users deletes +** or updates a record). +** +** When this function is called, the requested changeset is created using +** both the accumulated records and the current contents of the database +** file. Specifically: +** +**
    +**
  • For each record generated by an insert, the database is queried +** for a row with a matching primary key. If one is found, an INSERT +** change is added to the changeset. If no such row is found, no change +** is added to the changeset. +** +**
  • For each record generated by an update or delete, the database is +** queried for a row with a matching primary key. If such a row is +** found and one or more of the non-primary key fields have been +** modified from their original values, an UPDATE change is added to +** the changeset. Or, if no such row is found in the table, a DELETE +** change is added to the changeset. If there is a row with a matching +** primary key in the database, but all fields contain their original +** values, no change is added to the changeset. +**
+** +** This means, amongst other things, that if a row is inserted and then later +** deleted while a session object is active, neither the insert nor the delete +** will be present in the changeset. Or if a row is deleted and then later a +** row with the same primary key values inserted while a session object is +** active, the resulting changeset will contain an UPDATE change instead of +** a DELETE and an INSERT. +** +** When a session object is disabled (see the [sqlite3session_enable()] API), +** it does not accumulate records when rows are inserted, updated or deleted. +** This may appear to have some counter-intuitive effects if a single row +** is written to more than once during a session. For example, if a row +** is inserted while a session object is enabled, then later deleted while +** the same session object is disabled, no INSERT record will appear in the +** changeset, even though the delete took place while the session was disabled. +** Or, if one field of a row is updated while a session is disabled, and +** another field of the same row is updated while the session is enabled, the +** resulting changeset will contain an UPDATE change that updates both fields. +*/ +int sqlite3session_changeset( + sqlite3_session *pSession, /* Session object */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ +); + +/* +** CAPI3REF: Load The Difference Between Tables Into A Session +** +** If it is not already attached to the session object passed as the first +** argument, this function attaches table zTbl in the same manner as the +** [sqlite3session_attach()] function. If zTbl does not exist, or if it +** does not have a primary key, this function is a no-op (but does not return +** an error). +** +** Argument zFromDb must be the name of a database ("main", "temp" etc.) +** attached to the same database handle as the session object that contains +** a table compatible with the table attached to the session by this function. +** A table is considered compatible if it: +** +**
    +**
  • Has the same name, +**
  • Has the same set of columns declared in the same order, and +**
  • Has the same PRIMARY KEY definition. +**
+** +** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables +** are compatible but do not have any PRIMARY KEY columns, it is not an error +** but no changes are added to the session object. As with other session +** APIs, tables without PRIMARY KEYs are simply ignored. +** +** This function adds a set of changes to the session object that could be +** used to update the table in database zFrom (call this the "from-table") +** so that its content is the same as the table attached to the session +** object (call this the "to-table"). Specifically: +** +**
    +**
  • For each row (primary key) that exists in the to-table but not in +** the from-table, an INSERT record is added to the session object. +** +**
  • For each row (primary key) that exists in the to-table but not in +** the from-table, a DELETE record is added to the session object. +** +**
  • For each row (primary key) that exists in both tables, but features +** different in each, an UPDATE record is added to the session. +**
+** +** To clarify, if this function is called and then a changeset constructed +** using [sqlite3session_changeset()], then after applying that changeset to +** database zFrom the contents of the two compatible tables would be +** identical. +** +** It an error if database zFrom does not exist or does not contain the +** required compatible table. +** +** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite +** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to free this buffer using +** sqlite3_free(). +*/ +int sqlite3session_diff( + sqlite3_session *pSession, + const char *zFromDb, + const char *zTbl, + char **pzErrMsg +); + + +/* +** CAPI3REF: Generate A Patchset From A Session Object +** +** The differences between a patchset and a changeset are that: +** +**
    +**
  • DELETE records consist of the primary key fields only. The +** original values of other fields are omitted. +**
  • The original values of any modified fields are omitted from +** UPDATE records. +**
+** +** A patchset blob may be used with up to date versions of all +** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), +** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, +** attempting to use a patchset blob with old versions of the +** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. +** +** Because the non-primary key "old.*" fields are omitted, no +** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset +** is passed to the sqlite3changeset_apply() API. Other conflict types work +** in the same way as for changesets. +** +** Changes within a patchset are ordered in the same way as for changesets +** generated by the sqlite3session_changeset() function (i.e. all changes for +** a single table are grouped together, tables appear in the order in which +** they were attached to the session object). +*/ +int sqlite3session_patchset( + sqlite3_session *pSession, /* Session object */ + int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ + void **ppPatchset /* OUT: Buffer containing changeset */ +); + +/* +** CAPI3REF: Test if a changeset has recorded any changes. +** +** Return non-zero if no changes to attached tables have been recorded by +** the session object passed as the first argument. Otherwise, if one or +** more changes have been recorded, return zero. +** +** Even if this function returns zero, it is possible that calling +** [sqlite3session_changeset()] on the session handle may still return a +** changeset that contains no changes. This can happen when a row in +** an attached table is modified and then later on the original values +** are restored. However, if this function returns non-zero, then it is +** guaranteed that a call to sqlite3session_changeset() will return a +** changeset containing zero changes. +*/ +int sqlite3session_isempty(sqlite3_session *pSession); + +/* +** CAPI3REF: Create An Iterator To Traverse A Changeset +** +** Create an iterator used to iterate through the contents of a changeset. +** If successful, *pp is set to point to the iterator handle and SQLITE_OK +** is returned. Otherwise, if an error occurs, *pp is set to zero and an +** SQLite error code is returned. +** +** The following functions can be used to advance and query a changeset +** iterator created by this function: +** +**
    +**
  • [sqlite3changeset_next()] +**
  • [sqlite3changeset_op()] +**
  • [sqlite3changeset_new()] +**
  • [sqlite3changeset_old()] +**
+** +** It is the responsibility of the caller to eventually destroy the iterator +** by passing it to [sqlite3changeset_finalize()]. The buffer containing the +** changeset (pChangeset) must remain valid until after the iterator is +** destroyed. +** +** Assuming the changeset blob was created by one of the +** [sqlite3session_changeset()], [sqlite3changeset_concat()] or +** [sqlite3changeset_invert()] functions, all changes within the changeset +** that apply to a single table are grouped together. This means that when +** an application iterates through a changeset using an iterator created by +** this function, all changes that relate to a single table are visited +** consecutively. There is no chance that the iterator will visit a change +** the applies to table X, then one for table Y, and then later on visit +** another change for table X. +*/ +int sqlite3changeset_start( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset /* Pointer to blob containing changeset */ +); + + +/* +** CAPI3REF: Advance A Changeset Iterator +** +** This function may only be used with iterators created by function +** [sqlite3changeset_start()]. If it is called on an iterator passed to +** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE +** is returned and the call has no effect. +** +** Immediately after an iterator is created by sqlite3changeset_start(), it +** does not point to any change in the changeset. Assuming the changeset +** is not empty, the first call to this function advances the iterator to +** point to the first change in the changeset. Each subsequent call advances +** the iterator to point to the next change in the changeset (if any). If +** no error occurs and the iterator points to a valid change after a call +** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. +** Otherwise, if all changes in the changeset have already been visited, +** SQLITE_DONE is returned. +** +** If an error occurs, an SQLite error code is returned. Possible error +** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or +** SQLITE_NOMEM. +*/ +int sqlite3changeset_next(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Obtain The Current Operation From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this +** is not the case, this function returns [SQLITE_MISUSE]. +** +** If argument pzTab is not NULL, then *pzTab is set to point to a +** nul-terminated utf-8 encoded string containing the name of the table +** affected by the current change. The buffer remains valid until either +** sqlite3changeset_next() is called on the iterator or until the +** conflict-handler function returns. If pnCol is not NULL, then *pnCol is +** set to the number of columns in the table affected by the change. If +** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change +** is an indirect change, or false (0) otherwise. See the documentation for +** [sqlite3session_indirect()] for a description of direct and indirect +** changes. Finally, if pOp is not NULL, then *pOp is set to one of +** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the +** type of change that the iterator currently points to. +** +** If no error occurs, SQLITE_OK is returned. If an error does occur, an +** SQLite error code is returned. The values of the output variables may not +** be trusted in this case. +*/ +int sqlite3changeset_op( + sqlite3_changeset_iter *pIter, /* Iterator object */ + const char **pzTab, /* OUT: Pointer to table name */ + int *pnCol, /* OUT: Number of columns in table */ + int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int *pbIndirect /* OUT: True for an 'indirect' change */ +); + +/* +** CAPI3REF: Obtain The Primary Key Definition Of A Table +** +** For each modified table, a changeset includes the following: +** +**
    +**
  • The number of columns in the table, and +**
  • Which of those columns make up the tables PRIMARY KEY. +**
+** +** This function is used to find which columns comprise the PRIMARY KEY of +** the table modified by the change that iterator pIter currently points to. +** If successful, *pabPK is set to point to an array of nCol entries, where +** nCol is the number of columns in the table. Elements of *pabPK are set to +** 0x01 if the corresponding column is part of the tables primary key, or +** 0x00 if it is not. +** +** If argument pnCol is not NULL, then *pnCol is set to the number of columns +** in the table. +** +** If this function is called when the iterator does not point to a valid +** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, +** SQLITE_OK is returned and the output variables populated as described +** above. +*/ +int sqlite3changeset_pk( + sqlite3_changeset_iter *pIter, /* Iterator object */ + unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ + int *pnCol /* OUT: Number of entries in output array */ +); + +/* +** CAPI3REF: Obtain old.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** original row values stored as part of the UPDATE or DELETE change and +** returns SQLITE_OK. The name of the function comes from the fact that this +** is similar to the "old.*" columns available to update or delete triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +int sqlite3changeset_old( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain new.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** new row values stored as part of the UPDATE or INSERT change and +** returns SQLITE_OK. If the change is an UPDATE and does not include +** a new value for the requested column, *ppValue is set to NULL and +** SQLITE_OK returned. The name of the function comes from the fact that +** this is similar to the "new.*" columns available to update or delete +** triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +int sqlite3changeset_new( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator +** +** This function should only be used with iterator objects passed to a +** conflict-handler callback by [sqlite3changeset_apply()] with either +** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function +** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue +** is set to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the +** "conflicting row" associated with the current conflict-handler callback +** and returns SQLITE_OK. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +int sqlite3changeset_conflict( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Value from conflicting row */ +); + +/* +** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations +** +** This function may only be called with an iterator passed to an +** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case +** it sets the output variable to the total number of known foreign key +** violations in the destination database and returns SQLITE_OK. +** +** In all other cases this function returns SQLITE_MISUSE. +*/ +int sqlite3changeset_fk_conflicts( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int *pnOut /* OUT: Number of FK violations */ +); + + +/* +** CAPI3REF: Finalize A Changeset Iterator +** +** This function is used to finalize an iterator allocated with +** [sqlite3changeset_start()]. +** +** This function should only be called on iterators created using the +** [sqlite3changeset_start()] function. If an application calls this +** function with an iterator passed to a conflict-handler by +** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the +** call has no effect. +** +** If an error was encountered within a call to an sqlite3changeset_xxx() +** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an +** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding +** to that error is returned by this function. Otherwise, SQLITE_OK is +** returned. This is to allow the following pattern (pseudo-code): +** +** sqlite3changeset_start(); +** while( SQLITE_ROW==sqlite3changeset_next() ){ +** // Do something with change. +** } +** rc = sqlite3changeset_finalize(); +** if( rc!=SQLITE_OK ){ +** // An error has occurred +** } +*/ +int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Invert A Changeset +** +** This function is used to "invert" a changeset object. Applying an inverted +** changeset to a database reverses the effects of applying the uninverted +** changeset. Specifically: +** +**
    +**
  • Each DELETE change is changed to an INSERT, and +**
  • Each INSERT change is changed to a DELETE, and +**
  • For each UPDATE change, the old.* and new.* values are exchanged. +**
+** +** This function does not change the order in which changes appear within +** the changeset. It merely reverses the sense of each individual change. +** +** If successful, a pointer to a buffer containing the inverted changeset +** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and +** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are +** zeroed and an SQLite error code returned. +** +** It is the responsibility of the caller to eventually call sqlite3_free() +** on the *ppOut pointer to free the buffer allocation following a successful +** call to this function. +** +** WARNING/TODO: This function currently assumes that the input is a valid +** changeset. If it is not, the results are undefined. +*/ +int sqlite3changeset_invert( + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ +); + +/* +** CAPI3REF: Concatenate Two Changeset Objects +** +** This function is used to concatenate two changesets, A and B, into a +** single changeset. The result is a changeset equivalent to applying +** changeset A followed by changeset B. +** +** This function combines the two input changesets using an +** sqlite3_changegroup object. Calling it produces similar results as the +** following code fragment: +** +** sqlite3_changegroup *pGrp; +** rc = sqlite3_changegroup_new(&pGrp); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB); +** if( rc==SQLITE_OK ){ +** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); +** }else{ +** *ppOut = 0; +** *pnOut = 0; +** } +** +** Refer to the sqlite3_changegroup documentation below for details. +*/ +int sqlite3changeset_concat( + int nA, /* Number of bytes in buffer pA */ + void *pA, /* Pointer to buffer containing changeset A */ + int nB, /* Number of bytes in buffer pB */ + void *pB, /* Pointer to buffer containing changeset B */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: Buffer containing output changeset */ +); + + +/* +** CAPI3REF: Changegroup Handle +*/ +typedef struct sqlite3_changegroup sqlite3_changegroup; + +/* +** CAPI3REF: Create A New Changegroup Object +** +** An sqlite3_changegroup object is used to combine two or more changesets +** (or patchsets) into a single changeset (or patchset). A single changegroup +** object may combine changesets or patchsets, but not both. The output is +** always in the same format as the input. +** +** If successful, this function returns SQLITE_OK and populates (*pp) with +** a pointer to a new sqlite3_changegroup object before returning. The caller +** should eventually free the returned object using a call to +** sqlite3changegroup_delete(). If an error occurs, an SQLite error code +** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. +** +** The usual usage pattern for an sqlite3_changegroup object is as follows: +** +**
    +**
  • It is created using a call to sqlite3changegroup_new(). +** +**
  • Zero or more changesets (or patchsets) are added to the object +** by calling sqlite3changegroup_add(). +** +**
  • The result of combining all input changesets together is obtained +** by the application via a call to sqlite3changegroup_output(). +** +**
  • The object is deleted using a call to sqlite3changegroup_delete(). +**
+** +** Any number of calls to add() and output() may be made between the calls to +** new() and delete(), and in any order. +** +** As well as the regular sqlite3changegroup_add() and +** sqlite3changegroup_output() functions, also available are the streaming +** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). +*/ +int sqlite3changegroup_new(sqlite3_changegroup **pp); + +/* +** CAPI3REF: Add A Changeset To A Changegroup +** +** Add all changes within the changeset (or patchset) in buffer pData (size +** nData bytes) to the changegroup. +** +** If the buffer contains a patchset, then all prior calls to this function +** on the same changegroup object must also have specified patchsets. Or, if +** the buffer contains a changeset, so must have the earlier calls to this +** function. Otherwise, SQLITE_ERROR is returned and no changes are added +** to the changegroup. +** +** Rows within the changeset and changegroup are identified by the values in +** their PRIMARY KEY columns. A change in the changeset is considered to +** apply to the same row as a change already present in the changegroup if +** the two rows have the same primary key. +** +** Changes to rows that do not already appear in the changegroup are +** simply copied into it. Or, if both the new changeset and the changegroup +** contain changes that apply to a single row, the final contents of the +** changegroup depends on the type of each change, as follows: +** +** +** +** +**
Existing Change New Change Output Change +**
INSERT INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
INSERT UPDATE +** The INSERT change remains in the changegroup. The values in the +** INSERT change are modified as if the row was inserted by the +** existing change and then updated according to the new change. +**
INSERT DELETE +** The existing INSERT is removed from the changegroup. The DELETE is +** not added. +**
UPDATE INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
UPDATE UPDATE +** The existing UPDATE remains within the changegroup. It is amended +** so that the accompanying values are as if the row was updated once +** by the existing change and then again by the new change. +**
UPDATE DELETE +** The existing UPDATE is replaced by the new DELETE within the +** changegroup. +**
DELETE INSERT +** If one or more of the column values in the row inserted by the +** new change differ from those in the row deleted by the existing +** change, the existing DELETE is replaced by an UPDATE within the +** changegroup. Otherwise, if the inserted row is exactly the same +** as the deleted row, the existing DELETE is simply discarded. +**
DELETE UPDATE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
DELETE DELETE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
+** +** If the new changeset contains changes to a table that is already present +** in the changegroup, then the number of columns and the position of the +** primary key columns for the table must be consistent. If this is not the +** case, this function fails with SQLITE_SCHEMA. If the input changeset +** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is +** returned. Or, if an out-of-memory condition occurs during processing, this +** function returns SQLITE_NOMEM. In all cases, if an error occurs the +** final contents of the changegroup is undefined. +** +** If no error occurs, SQLITE_OK is returned. +*/ +int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); + +/* +** CAPI3REF: Obtain A Composite Changeset From A Changegroup +** +** Obtain a buffer containing a changeset (or patchset) representing the +** current contents of the changegroup. If the inputs to the changegroup +** were themselves changesets, the output is a changeset. Or, if the +** inputs were patchsets, the output is also a patchset. +** +** As with the output of the sqlite3session_changeset() and +** sqlite3session_patchset() functions, all changes related to a single +** table are grouped together in the output of this function. Tables appear +** in the same order as for the very first changeset added to the changegroup. +** If the second or subsequent changesets added to the changegroup contain +** changes for tables that do not appear in the first changeset, they are +** appended onto the end of the output changeset, again in the order in +** which they are first encountered. +** +** If an error occurs, an SQLite error code is returned and the output +** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK +** is returned and the output variables are set to the size of and a +** pointer to the output buffer, respectively. In this case it is the +** responsibility of the caller to eventually free the buffer using a +** call to sqlite3_free(). +*/ +int sqlite3changegroup_output( + sqlite3_changegroup*, + int *pnData, /* OUT: Size of output buffer in bytes */ + void **ppData /* OUT: Pointer to output buffer */ +); + +/* +** CAPI3REF: Delete A Changegroup Object +*/ +void sqlite3changegroup_delete(sqlite3_changegroup*); + +/* +** CAPI3REF: Apply A Changeset To A Database +** +** Apply a changeset to a database. This function attempts to update the +** "main" database attached to handle db with the changes found in the +** changeset passed via the second and third arguments. +** +** The fourth argument (xFilter) passed to this function is the "filter +** callback". If it is not NULL, then for each table affected by at least one +** change in the changeset, the filter callback is invoked with +** the table name as the second argument, and a copy of the context pointer +** passed as the sixth argument to this function as the first. If the "filter +** callback" returns zero, then no attempt is made to apply any changes to +** the table. Otherwise, if the return value is non-zero or the xFilter +** argument to this function is NULL, all changes related to the table are +** attempted. +** +** For each table that is not excluded by the filter callback, this function +** tests that the target database contains a compatible table. A table is +** considered compatible if all of the following are true: +** +**
    +**
  • The table has the same name as the name recorded in the +** changeset, and +**
  • The table has the same number of columns as recorded in the +** changeset, and +**
  • The table has primary key columns in the same position as +** recorded in the changeset. +**
+** +** If there is no compatible table, it is not an error, but none of the +** changes associated with the table are applied. A warning message is issued +** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most +** one such warning is issued for each table in the changeset. +** +** For each change for which there is a compatible table, an attempt is made +** to modify the table contents according to the UPDATE, INSERT or DELETE +** change. If a change cannot be applied cleanly, the conflict handler +** function passed as the fifth argument to sqlite3changeset_apply() may be +** invoked. A description of exactly when the conflict handler is invoked for +** each type of change is below. +** +** Unlike the xFilter argument, xConflict may not be passed NULL. The results +** of passing anything other than a valid function pointer as the xConflict +** argument are undefined. +** +** Each time the conflict handler function is invoked, it must return one +** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or +** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned +** if the second argument passed to the conflict handler is either +** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler +** returns an illegal value, any changes already made are rolled back and +** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different +** actions are taken by sqlite3changeset_apply() depending on the value +** returned by each invocation of the conflict-handler function. Refer to +** the documentation for the three +** [SQLITE_CHANGESET_OMIT|available return values] for details. +** +**
+**
DELETE Changes
+** For each DELETE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in +** the changeset the row is deleted from the target database. +** +** If a row with matching primary key values is found, but one or more of +** the non-primary key fields contains a value different from the original +** row value stored in the changeset, the conflict-handler function is +** invoked with [SQLITE_CHANGESET_DATA] as the second argument. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT +** (which can only happen if a foreign key constraint is violated), the +** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] +** passed as the second argument. This includes the case where the DELETE +** operation is attempted because an earlier call to the conflict handler +** function returned [SQLITE_CHANGESET_REPLACE]. +** +**
INSERT Changes
+** For each INSERT change, an attempt is made to insert the new row into +** the database. +** +** If the attempt to insert the row fails because the database already +** contains a row with the same primary key values, the conflict handler +** function is invoked with the second argument set to +** [SQLITE_CHANGESET_CONFLICT]. +** +** If the attempt to insert the row fails because of some other constraint +** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is +** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. +** This includes the case where the INSERT operation is re-attempted because +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +** +**
UPDATE Changes
+** For each UPDATE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in +** the changeset the row is updated within the target database. +** +** If a row with matching primary key values is found, but one or more of +** the non-primary key fields contains a value different from an original +** row value stored in the changeset, the conflict-handler function is +** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since +** UPDATE changes only contain values for non-primary key fields that are +** to be modified, only those fields need to match the original values to +** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the UPDATE operation is attempted, but SQLite returns +** SQLITE_CONSTRAINT, the conflict-handler function is invoked with +** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. +** This includes the case where the UPDATE operation is attempted after +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +**
+** +** It is safe to execute SQL statements, including those that write to the +** table that the callback related to, from within the xConflict callback. +** This can be used to further customize the applications conflict +** resolution strategy. +** +** All changes made by this function are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. +*/ +int sqlite3changeset_apply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); + +/* +** CAPI3REF: Constants Passed To The Conflict Handler +** +** Values that may be passed as the second argument to a conflict-handler. +** +**
+**
SQLITE_CHANGESET_DATA
+** The conflict handler is invoked with CHANGESET_DATA as the second argument +** when processing a DELETE or UPDATE change if a row with the required +** PRIMARY KEY fields is present in the database, but one or more other +** (non primary-key) fields modified by the update do not contain the +** expected "before" values. +** +** The conflicting row, in this case, is the database row with the matching +** primary key. +** +**
SQLITE_CHANGESET_NOTFOUND
+** The conflict handler is invoked with CHANGESET_NOTFOUND as the second +** argument when processing a DELETE or UPDATE change if a row with the +** required PRIMARY KEY fields is not present in the database. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
SQLITE_CHANGESET_CONFLICT
+** CHANGESET_CONFLICT is passed as the second argument to the conflict +** handler while processing an INSERT change if the operation would result +** in duplicate primary key values. +** +** The conflicting row in this case is the database row with the matching +** primary key. +** +**
SQLITE_CHANGESET_FOREIGN_KEY
+** If foreign key handling is enabled, and applying a changeset leaves the +** database in a state containing foreign key violations, the conflict +** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument +** exactly once before the changeset is committed. If the conflict handler +** returns CHANGESET_OMIT, the changes, including those that caused the +** foreign key constraint violation, are committed. Or, if it returns +** CHANGESET_ABORT, the changeset is rolled back. +** +** No current or conflicting row information is provided. The only function +** it is possible to call on the supplied sqlite3_changeset_iter handle +** is sqlite3changeset_fk_conflicts(). +** +**
SQLITE_CHANGESET_CONSTRAINT
+** If any other constraint violation occurs while applying a change (i.e. +** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is +** invoked with CHANGESET_CONSTRAINT as the second argument. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
+*/ +#define SQLITE_CHANGESET_DATA 1 +#define SQLITE_CHANGESET_NOTFOUND 2 +#define SQLITE_CHANGESET_CONFLICT 3 +#define SQLITE_CHANGESET_CONSTRAINT 4 +#define SQLITE_CHANGESET_FOREIGN_KEY 5 + +/* +** CAPI3REF: Constants Returned By The Conflict Handler +** +** A conflict handler callback must return one of the following three values. +** +**
+**
SQLITE_CHANGESET_OMIT
+** If a conflict handler returns this value no special action is taken. The +** change that caused the conflict is not applied. The session module +** continues to the next change in the changeset. +** +**
SQLITE_CHANGESET_REPLACE
+** This value may only be returned if the second argument to the conflict +** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this +** is not the case, any changes applied so far are rolled back and the +** call to sqlite3changeset_apply() returns SQLITE_MISUSE. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict +** handler, then the conflicting row is either updated or deleted, depending +** on the type of change. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict +** handler, then the conflicting row is removed from the database and a +** second attempt to apply the change is made. If this second attempt fails, +** the original row is restored to the database before continuing. +** +**
SQLITE_CHANGESET_ABORT
+** If this value is returned, any changes applied so far are rolled back +** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. +**
+*/ +#define SQLITE_CHANGESET_OMIT 0 +#define SQLITE_CHANGESET_REPLACE 1 +#define SQLITE_CHANGESET_ABORT 2 + +/* +** CAPI3REF: Streaming Versions of API functions. +** +** The six streaming API xxx_strm() functions serve similar purposes to the +** corresponding non-streaming API functions: +** +** +** +**
Streaming functionNon-streaming equivalent
sqlite3changeset_apply_str[sqlite3changeset_apply] +**
sqlite3changeset_concat_str[sqlite3changeset_concat] +**
sqlite3changeset_invert_str[sqlite3changeset_invert] +**
sqlite3changeset_start_str[sqlite3changeset_start] +**
sqlite3session_changeset_str[sqlite3session_changeset] +**
sqlite3session_patchset_str[sqlite3session_patchset] +**
+** +** Non-streaming functions that accept changesets (or patchsets) as input +** require that the entire changeset be stored in a single buffer in memory. +** Similarly, those that return a changeset or patchset do so by returning +** a pointer to a single large buffer allocated using sqlite3_malloc(). +** Normally this is convenient. However, if an application running in a +** low-memory environment is required to handle very large changesets, the +** large contiguous memory allocations required can become onerous. +** +** In order to avoid this problem, instead of a single large buffer, input +** is passed to a streaming API functions by way of a callback function that +** the sessions module invokes to incrementally request input data as it is +** required. In all cases, a pair of API function parameters such as +** +**
+**        int nChangeset,
+**        void *pChangeset,
+**  
+** +** Is replaced by: +** +**
+**        int (*xInput)(void *pIn, void *pData, int *pnData),
+**        void *pIn,
+**  
+** +** Each time the xInput callback is invoked by the sessions module, the first +** argument passed is a copy of the supplied pIn context pointer. The second +** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no +** error occurs the xInput method should copy up to (*pnData) bytes of data +** into the buffer and set (*pnData) to the actual number of bytes copied +** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) +** should be set to zero to indicate this. Or, if an error occurs, an SQLite +** error code should be returned. In all cases, if an xInput callback returns +** an error, all processing is abandoned and the streaming API function +** returns a copy of the error code to the caller. +** +** In the case of sqlite3changeset_start_strm(), the xInput callback may be +** invoked by the sessions module at any point during the lifetime of the +** iterator. If such an xInput callback returns an error, the iterator enters +** an error state, whereby all subsequent calls to iterator functions +** immediately fail with the same error code as returned by xInput. +** +** Similarly, streaming API functions that return changesets (or patchsets) +** return them in chunks by way of a callback function instead of via a +** pointer to a single large buffer. In this case, a pair of parameters such +** as: +** +**
+**        int *pnChangeset,
+**        void **ppChangeset,
+**  
+** +** Is replaced by: +** +**
+**        int (*xOutput)(void *pOut, const void *pData, int nData),
+**        void *pOut
+**  
+** +** The xOutput callback is invoked zero or more times to return data to +** the application. The first parameter passed to each call is a copy of the +** pOut pointer supplied by the application. The second parameter, pData, +** points to a buffer nData bytes in size containing the chunk of output +** data being returned. If the xOutput callback successfully processes the +** supplied data, it should return SQLITE_OK to indicate success. Otherwise, +** it should return some other SQLite error code. In this case processing +** is immediately abandoned and the streaming API function returns a copy +** of the xOutput error code to the application. +** +** The sessions module never invokes an xOutput callback with the third +** parameter set to a value less than or equal to zero. Other than this, +** no guarantees are made as to the size of the chunks of data returned. +*/ +int sqlite3changeset_apply_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); +int sqlite3changeset_concat_strm( + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +int sqlite3changeset_invert_strm( + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +int sqlite3changeset_start_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +int sqlite3session_changeset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +int sqlite3session_patchset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +int sqlite3changegroup_add_strm(sqlite3_changegroup*, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); + + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ + +/******** End of sqlite3session.h *********/ +/******** Begin file fts5.h *********/ +/* +** 2014 May 31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Interfaces to extend FTS5. Using the interfaces defined in this file, +** FTS5 may be extended with: +** +** * custom tokenizers, and +** * custom auxiliary functions. +*/ + + +#ifndef _FTS5_H +#define _FTS5_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************* +** CUSTOM AUXILIARY FUNCTIONS +** +** Virtual table implementations may overload SQL functions by implementing +** the sqlite3_module.xFindFunction() method. +*/ + +typedef struct Fts5ExtensionApi Fts5ExtensionApi; +typedef struct Fts5Context Fts5Context; +typedef struct Fts5PhraseIter Fts5PhraseIter; + +typedef void (*fts5_extension_function)( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +); + +struct Fts5PhraseIter { + const unsigned char *a; + const unsigned char *b; +}; + +/* +** EXTENSION API FUNCTIONS +** +** xUserData(pFts): +** Return a copy of the context pointer the extension function was +** registered with. +** +** xColumnTotalSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the FTS5 table. Or, if iCol is +** non-negative but less than the number of columns in the table, return +** the total number of tokens in column iCol, considering all rows in +** the FTS5 table. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** xColumnCount(pFts): +** Return the number of columns in the table. +** +** xColumnSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the current row. Or, if iCol is +** non-negative but less than the number of columns in the table, set +** *pnToken to the number of tokens in column iCol of the current row. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** +** xColumnText: +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer +** containing the text in utf-8 encoding, (*pn) is set to the size in bytes +** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, +** if an error occurs, an SQLite error code is returned and the final values +** of (*pz) and (*pn) are undefined. +** +** xPhraseCount: +** Returns the number of phrases in the current query expression. +** +** xPhraseSize: +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. +** +** xInstCount: +** Set *pnInst to the total number of occurrences of all phrases within +** the query within the current row. Return SQLITE_OK if successful, or +** an error code (i.e. SQLITE_NOMEM) if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** +** xInst: +** Query for the details of phrase match iIdx within the current row. +** Phrase matches are numbered starting from zero, so the iIdx argument +** should be greater than or equal to zero and smaller than the value +** output by xInstCount(). +** +** Usually, output parameter *piPhrase is set to the phrase number, *piCol +** to the column in which it occurs and *piOff the token offset of the +** first token of the phrase. The exception is if the table was created +** with the offsets=0 option specified. In this case *piOff is always +** set to -1. +** +** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) +** if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** +** xRowid: +** Returns the rowid of the current row. +** +** xTokenize: +** Tokenize text using the tokenizer belonging to the FTS5 table. +** +** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): +** This API function is used to query the FTS table for phrase iPhrase +** of the current query. Specifically, a query equivalent to: +** +** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid +** +** with $p set to a phrase equivalent to the phrase iPhrase of the +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. +** +** If the callback function returns any value other than SQLITE_OK, the +** query is abandoned and the xQueryPhrase function returns immediately. +** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. +** Otherwise, the error code is propagated upwards. +** +** If the query runs to completion without incident, SQLITE_OK is returned. +** Or, if some error occurs before the query completes or is aborted by +** the callback, an SQLite error code is returned. +** +** +** xSetAuxdata(pFts5, pAux, xDelete) +** +** Save the pointer passed as the second argument as the extension functions +** "auxiliary data". The pointer may then be retrieved by the current or any +** future invocation of the same fts5 extension function made as part of +** of the same MATCH query using the xGetAuxdata() API. +** +** Each extension function is allocated a single auxiliary data slot for +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a +** single auxiliary data context. +** +** If there is already an auxiliary data pointer when this function is +** invoked, then it is replaced by the new pointer. If an xDelete callback +** was specified along with the original pointer, it is invoked at this +** point. +** +** The xDelete callback, if one is specified, is also invoked on the +** auxiliary data pointer after the FTS5 query has finished. +** +** If an error (e.g. an OOM condition) occurs within this function, an +** the auxiliary data is set to NULL and an error code returned. If the +** xDelete parameter was not NULL, it is invoked on the auxiliary data +** pointer before returning. +** +** +** xGetAuxdata(pFts5, bClear) +** +** Returns the current auxiliary data pointer for the fts5 extension +** function. See the xSetAuxdata() method for details. +** +** If the bClear argument is non-zero, then the auxiliary data is cleared +** (set to NULL) before this function returns. In this case the xDelete, +** if any, is not invoked. +** +** +** xRowCount(pFts5, pnRow) +** +** This function is used to retrieve the total number of rows in the table. +** In other words, the same value that would be returned by: +** +** SELECT count(*) FROM ftstable; +** +** xPhraseFirst() +** This function is used, along with type Fts5PhraseIter and the xPhraseNext +** method, to iterate through all instances of a single query phrase within +** the current row. This is the same information as is accessible via the +** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient +** to use, this API may be faster under some circumstances. To iterate +** through instances of phrase iPhrase, use the following code: +** +** Fts5PhraseIter iter; +** int iCol, iOff; +** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); +** iCol>=0; +** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) +** ){ +** // An instance of phrase iPhrase at offset iOff of column iCol +** } +** +** The Fts5PhraseIter structure is defined above. Applications should not +** modify this structure directly - it should only be used as shown above +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). +** +** xPhraseNext() +** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. +*/ +struct Fts5ExtensionApi { + int iVersion; /* Currently always set to 3 */ + + void *(*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); +}; + +/* +** CUSTOM AUXILIARY FUNCTIONS +*************************************************************************/ + +/************************************************************************* +** CUSTOM TOKENIZERS +** +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the +** following structure. All structure methods must be defined, setting +** any member of the fts5_tokenizer struct to NULL leads to undefined +** behaviour. The structure methods are expected to function as follows: +** +** xCreate: +** This function is used to allocate and initialize a tokenizer instance. +** A tokenizer instance is required to actually tokenize text. +** +** The first argument passed to this function is a copy of the (void*) +** pointer provided by the application when the fts5_tokenizer object +** was registered with FTS5 (the third argument to xCreateTokenizer()). +** The second and third arguments are an array of nul-terminated strings +** containing the tokenizer arguments, if any, specified following the +** tokenizer name as part of the CREATE VIRTUAL TABLE statement used +** to create the FTS5 table. +** +** The final argument is an output variable. If successful, (*ppOut) +** should be set to point to the new tokenizer handle and SQLITE_OK +** returned. If an error occurs, some value other than SQLITE_OK should +** be returned. In this case, fts5 assumes that the final value of *ppOut +** is undefined. +** +** xDelete: +** This function is invoked to delete a tokenizer handle previously +** allocated using xCreate(). Fts5 guarantees that this function will +** be invoked exactly once for each successful call to xCreate(). +** +** xTokenize: +** This function is expected to tokenize the nText byte string indicated +** by argument pText. pText may or may not be nul-terminated. The first +** argument passed to this function is a pointer to an Fts5Tokenizer object +** returned by an earlier call to xCreate(). +** +** The second argument indicates the reason that FTS5 is requesting +** tokenization of the supplied text. This is always one of the following +** four values: +** +**
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into +** or removed from the FTS table. The tokenizer is being invoked to +** determine the set of tokens to add to (or delete from) the +** FTS index. +** +**
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize +** a bareword or quoted string specified as part of the query. +** +**
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as +** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is +** followed by a "*" character, indicating that the last token +** returned by the tokenizer will be treated as a token prefix. +** +**
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +** satisfy an fts5_api.xTokenize() request made by an auxiliary +** function. Or an fts5_api.xColumnSize() request made by the same +** on a columnsize=0 database. +**
+** +** For each token in the input string, the supplied callback xToken() must +** be invoked. The first argument to it should be a copy of the pointer +** passed as the second argument to xTokenize(). The third and fourth +** arguments are a pointer to a buffer containing the token text, and the +** size of the token in bytes. The 4th and 5th arguments are the byte offsets +** of the first byte of and first byte immediately following the text from +** which the token is derived within the input. +** +** The second argument passed to the xToken() callback ("tflags") should +** normally be set to 0. The exception is if the tokenizer supports +** synonyms. In this case see the discussion below for details. +** +** FTS5 assumes the xToken() callback is invoked for each token in the +** order that they occur within the input text. +** +** If an xToken() callback returns any value other than SQLITE_OK, then +** the tokenization should be abandoned and the xTokenize() method should +** immediately return a copy of the xToken() return value. Or, if the +** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, +** if an error occurs with the xTokenize() implementation itself, it +** may abandon the tokenization and return any error code other than +** SQLITE_OK or SQLITE_DONE. +** +** SYNONYM SUPPORT +** +** Custom tokenizers may also support synonyms. Consider a case in which a +** user wishes to query for a phrase such as "first place". Using the +** built-in tokenizers, the FTS5 query 'first + place' will match instances +** of "first place" within the document set, but not alternative forms +** such as "1st place". In some applications, it would be better to match +** all instances of "first place" or "1st place" regardless of which form +** the user specified in the MATCH query text. +** +** There are several ways to approach this in FTS5: +** +**
  1. By mapping all synonyms to a single token. In this case, the +** In the above example, this means that the tokenizer returns the +** same token for inputs "first" and "1st". Say that token is in +** fact "first", so that when the user inserts the document "I won +** 1st place" entries are added to the index for tokens "i", "won", +** "first" and "place". If the user then queries for '1st + place', +** the tokenizer substitutes "first" for "1st" and the query works +** as expected. +** +**
  2. By adding multiple synonyms for a single term to the FTS index. +** In this case, when tokenizing query text, the tokenizer may +** provide multiple synonyms for a single term within the document. +** FTS5 then queries the index for each synonym individually. For +** example, faced with the query: +** +** +** ... MATCH 'first place' +** +** the tokenizer offers both "1st" and "first" as synonyms for the +** first token in the MATCH query and FTS5 effectively runs a query +** similar to: +** +** +** ... MATCH '(first OR 1st) place' +** +** except that, for the purposes of auxiliary functions, the query +** still appears to contain just two phrases - "(first OR 1st)" +** being treated as a single phrase. +** +**
  3. By adding multiple synonyms for a single term to the FTS index. +** Using this method, when tokenizing document text, the tokenizer +** provides multiple synonyms for each token. So that when a +** document such as "I won first place" is tokenized, entries are +** added to the FTS index for "i", "won", "first", "1st" and +** "place". +** +** This way, even if the tokenizer does not provide synonyms +** when tokenizing query text (it should not - to do would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entires in the +** FTS index corresponding to both forms of the first token. +**
+** +** Whether it is parsing document or query text, any call to xToken that +** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit +** is considered to supply a synonym for the previous token. For example, +** when parsing the document "I won first place", a tokenizer that supports +** synonyms would call xToken() 5 times, as follows: +** +** +** xToken(pCtx, 0, "i", 1, 0, 1); +** xToken(pCtx, 0, "won", 3, 2, 5); +** xToken(pCtx, 0, "first", 5, 6, 11); +** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); +** xToken(pCtx, 0, "place", 5, 12, 17); +** +** +** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time +** xToken() is called. Multiple synonyms may be specified for a single token +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** There is no limit to the number of synonyms that may be provided for a +** single token. +** +** In many cases, method (1) above is the best approach. It does not add +** extra data to the FTS index or require FTS5 to query for multiple terms, +** so it is efficient in terms of disk space and query speed. However, it +** does not support prefix queries very well. If, as suggested above, the +** token "first" is subsituted for "1st" by the tokenizer, then the query: +** +** +** ... MATCH '1s*' +** +** will not match documents that contain the token "1st" (as the tokenizer +** will probably not map "1s" to any prefix of "first"). +** +** For full prefix support, method (3) may be preferred. In this case, +** because the index contains entries for both "first" and "1st", prefix +** queries such as 'fi*' or '1s*' will match correctly. However, because +** extra entries are added to the FTS index, this method uses more space +** within the database. +** +** Method (2) offers a midpoint between (1) and (3). Using this method, +** a query such as '1s*' will match documents that contain the literal +** token "1st", but not "first" (assuming the tokenizer is not able to +** provide synonyms for prefixes). However, a non-prefix query like '1st' +** will match against "1st" and "first". This method does not require +** extra disk space, as no extra entries are added to the FTS index. +** On the other hand, it may require more CPU cycles to run MATCH queries, +** as separate queries of the FTS index are required for each synonym. +** +** When using methods (2) or (3), it is important that the tokenizer only +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is +** inefficient. +*/ +typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer fts5_tokenizer; +struct fts5_tokenizer { + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* Flags that may be passed as the third argument to xTokenize() */ +#define FTS5_TOKENIZE_QUERY 0x0001 +#define FTS5_TOKENIZE_PREFIX 0x0002 +#define FTS5_TOKENIZE_DOCUMENT 0x0004 +#define FTS5_TOKENIZE_AUX 0x0008 + +/* Flags that may be passed by the tokenizer implementation back to FTS5 +** as the third argument to the supplied xToken callback. */ +#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ + +/* +** END OF CUSTOM TOKENIZERS +*************************************************************************/ + +/************************************************************************* +** FTS5 EXTENSION REGISTRATION API +*/ +typedef struct fts5_api fts5_api; +struct fts5_api { + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + /* Create a new auxiliary function */ + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); +}; + +/* +** END OF REGISTRATION API +*************************************************************************/ + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* _FTS5_H */ + +/******** End of fts5.h *********/