diff --git a/sqlite/PKGBUILD b/sqlite/PKGBUILD index 7a575b41..a08493e1 100644 --- a/sqlite/PKGBUILD +++ b/sqlite/PKGBUILD @@ -3,9 +3,9 @@ pkgbase="sqlite" pkgname=('sqlite' 'libsqlite' 'libsqlite-devel' 'sqlite-doc') -_amalgamationver=3080802 +_amalgamationver=3100000 _docver=${_amalgamationver} -pkgver=3.8.8.2 +pkgver=3.10.0.0 pkgrel=1 pkgdesc="A C library that implements an SQL database engine" arch=('i686' 'x86_64') @@ -14,24 +14,24 @@ url="http://www.sqlite.org/" depends=('libreadline' 'icu' 'zlib') makedepends=('libreadline-devel' 'icu-devel' 'zlib-devel') source=( # tarball containing the amalgamation for SQLite >= 3.7.5 together with a configure script and makefile for building it; includes now also the Tcl Extension Architecture (TEA) - http://www.sqlite.org/2015/sqlite-autoconf-$_amalgamationver.tar.gz - http://www.sqlite.org/2015/sqlite-doc-${_docver}.zip + http://www.sqlite.org/2016/sqlite-autoconf-${_amalgamationver}.tar.gz + http://www.sqlite.org/2016/sqlite-doc-${_docver}.zip LICENSE 'sqlite-3.8.0.1-msys2.patch' - 'sqlite3-3.8.8.2-1.src.patch' + 'sqlite3-3.10.0-1.src.patch' 'sqlite3-cygwin-msys.patch') options=('!libtool' '!emptydirs' '!debug' 'strip') -sha1sums=('1db237523419af7110e1d92c6b766e965f9322e4' - 'a11a6ea95d3d4a88b8d7d4e0cb6fcc3e5f4bf887' +sha1sums=('7be6e6869d0d2d9fe3df71b5c65f065dd2325f58' + '8bb827722301c485ac0526e20c015f1b76f32542' 'e2aa07adae13aed713860b74165d3325a18c6792' 'f357145f11da54b3dfd9c45e594d93960af87105' - '10bb572e806e93fe9bfd2e4c024415778880180c' - '69b3f261aae4990d23daa14ca0d2f0c8b53fb423') + 'a9d1462add4526fa59f7dfb09f1d02b63530e764' + '6896eb02d51375cc000e845f7c5504935ce082ce') prepare() { - cd "$srcdir"/sqlite-autoconf-$_amalgamationver + cd "${srcdir}"/sqlite-autoconf-${_amalgamationver} - patch -p2 -i ${srcdir}/sqlite3-3.8.8.2-1.src.patch + patch -p2 -i ${srcdir}/sqlite3-3.10.0-1.src.patch patch -p1 -i ${srcdir}/sqlite3-cygwin-msys.patch patch -p1 -i ${srcdir}/sqlite-3.8.0.1-msys2.patch @@ -42,23 +42,20 @@ build() { export CPPFLAGS="$CPPFLAGS \ -DHAVE_MALLOC_H \ -DHAVE_MALLOC_USABLE_SIZE \ - -DSQLITE_ENABLE_COLUMN_METADATA=1 \ - -DSQLITE_ENABLE_FTS4=1 \ - -DSQLITE_ENABLE_RTREE=1 \ - -DSQLITE_ENABLE_SQLLOG=1 \ + -DSQLITE_ENABLE_DBSTAT_VTAB=1 \ -DSQLITE_ENABLE_STAT4=1 \ -DSQLITE_ENABLE_UNLOCK_NOTIFY=1 \ - -DSQLITE_MAX_MMAP_SIZE=0x7fff0000 \ - -DSQLITE_MAX_PATH_BYTES=4096 \ + -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 \ + -DSQLITE_OMIT_LOOKASIDE \ -DSQLITE_OS_UNIX=1 \ -DSQLITE_OS_WIN=1 \ + -DSQLITE_SECURE_DELETE \ -DSQLITE_SOUNDEX=1 \ + -DSQLITE_TEMP_STORE=1 \ -DSQLITE_USE_FCNTL_TRACE=1 \ - -DSQLITE_WIN32_NO_ANSI=1 \ - -DSQLITE_WIN32_MAX_PATH_BYTES=4096 \ -DUSE_SYSTEM_SQLITE=1" - cd "$srcdir"/sqlite-autoconf-$_amalgamationver + cd "${srcdir}"/sqlite-autoconf-$_amalgamationver ./configure \ --prefix=/usr \ --sysconfdir=/etc \ @@ -78,7 +75,7 @@ _install_license() { package_sqlite() { pkgdesc="A C library that implements an SQL database engine" depends=('libreadline' 'libsqlite') - provides=("sqlite3=$pkgver") + provides=("sqlite3=${pkgver}") replaces=("sqlite3") mkdir -p ${pkgdir}/usr/bin diff --git a/sqlite/sqlite3-3.10.0-1.src.patch b/sqlite/sqlite3-3.10.0-1.src.patch new file mode 100644 index 00000000..23ddd4c5 --- /dev/null +++ b/sqlite/sqlite3-3.10.0-1.src.patch @@ -0,0 +1,28728 @@ +--- origsrc/sqlite-autoconf-3100000/Makefile.am 2016-01-06 13:03:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/Makefile.am 2016-01-06 16:30:03.315880000 +0100 +@@ -1,16 +1,75 @@ + +-AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE ++AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ -DUSE_SYSTEM_SQLITE=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_OMIT_LOOKASIDE=1 -DSQLITE_SECURE_DELETE=1 + +-lib_LTLIBRARIES = libsqlite3.la ++lib_LTLIBRARIES = libsqlite3.la libsqlite3amatch.la libsqlite3closure.la \ ++ libsqlite3compress.la libsqlite3eval.la libsqlite3fileio.la \ ++ libsqlite3fuzzer.la libsqlite3icu.la \ ++ libsqlite3ieee754.la libsqlite3nextchar.la \ ++ libsqlite3percentile.la libsqlite3rbu.la libsqlite3regexp.la \ ++ libsqlite3rot13.la libsqlite3series.la libsqlite3showauth.la \ ++ libsqlite3spellfix.la libsqlite3totype.la libsqlite3vfslog.la \ ++ libsqlite3vtshim.la libsqlite3wholenumber.la + libsqlite3_la_SOURCES = sqlite3.c +-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 ++libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3amatch_la_SOURCES = amatch.c ++libsqlite3amatch_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3closure_la_SOURCES = closure.c ++libsqlite3closure_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3compress_la_SOURCES = compress.c ++libsqlite3compress_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc -lz ++libsqlite3eval_la_SOURCES = eval.c ++libsqlite3eval_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3fileio_la_SOURCES = fileio.c ++libsqlite3fileio_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3fuzzer_la_SOURCES = fuzzer.c ++libsqlite3fuzzer_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3icu_la_SOURCES = icu.c ++libsqlite3icu_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc -licui18n -licuuc ++libsqlite3ieee754_la_SOURCES = ieee754.c ++libsqlite3ieee754_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3nextchar_la_SOURCES = nextchar.c ++libsqlite3nextchar_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3percentile_la_SOURCES = percentile.c ++libsqlite3percentile_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3rbu_la_SOURCES = sqlite3rbu.c ++libsqlite3rbu_la_LIBADD = $(top_builddir)/libsqlite3.la ++libsqlite3rbu_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3rbu_la_DEPENDENCIES = $(top_builddir)/libsqlite3.la ++libsqlite3regexp_la_SOURCES = regexp.c ++libsqlite3regexp_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3rot13_la_SOURCES = rot13.c ++libsqlite3rot13_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3series_la_SOURCES = series.c ++libsqlite3series_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3showauth_la_SOURCES = showauth.c ++libsqlite3showauth_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3spellfix_la_SOURCES = spellfix.c ++libsqlite3spellfix_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3totype_la_SOURCES = totype.c ++libsqlite3totype_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3vfslog_la_SOURCES = vfslog.c ++libsqlite3vfslog_la_LIBADD = $(top_builddir)/libsqlite3.la ++libsqlite3vfslog_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3vfslog_la_DEPENDENCIES = $(top_builddir)/libsqlite3.la ++libsqlite3vtshim_la_SOURCES = vtshim.c ++libsqlite3vtshim_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc ++libsqlite3wholenumber_la_SOURCES = wholenumber.c ++libsqlite3wholenumber_la_LDFLAGS = -no-undefined -version-info 8:6:8 -static-libgcc + +-bin_PROGRAMS = sqlite3 ++bin_PROGRAMS = sqlite3 sqldiff rbu + sqlite3_SOURCES = shell.c sqlite3.h + EXTRA_sqlite3_SOURCES = sqlite3.c +-sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ +-sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ ++sqlite3_LDADD = $(top_builddir)/libsqlite3vfslog.la @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ ++sqlite3_DEPENDENCIES = $(top_builddir)/libsqlite3vfslog.la @EXTRA_SHELL_OBJ@ + sqlite3_CFLAGS = $(AM_CFLAGS) ++sqldiff_SOURCES = sqldiff.c sqlite3.h ++sqldiff_LDADD = @EXTRA_SHELL_OBJ@ ++sqldiff_DEPENDENCIES = @EXTRA_SHELL_OBJ@ ++sqldiff_CFLAGS = $(AM_CFLAGS) ++rbu_SOURCES = rbu.c sqlite3.h ++rbu_LDADD = $(top_builddir)/libsqlite3rbu.la @EXTRA_SHELL_OBJ@ ++rbu_DEPENDENCIES = $(top_builddir)/libsqlite3rbu.la @EXTRA_SHELL_OBJ@ ++rbu_CFLAGS = $(AM_CFLAGS) + + include_HEADERS = sqlite3.h sqlite3ext.h + +--- origsrc/sqlite-autoconf-3100000/amatch.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/amatch.c 2016-01-06 16:30:42.469119500 +0100 +@@ -0,0 +1,1520 @@ ++/* ++** 2013-03-14 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++************************************************************************* ++** ++** This file contains code for a demonstration virtual table that finds ++** "approximate matches" - strings from a finite set that are nearly the ++** same as a single input string. The virtual table is called "amatch". ++** ++** A amatch virtual table is created like this: ++** ++** CREATE VIRTUAL TABLE f USING approximate_match( ++** vocabulary_table=, -- V ++** vocabulary_word=, -- W ++** vocabulary_language=, -- L ++** edit_distances= ++** ); ++** ++** When it is created, the new amatch table must be supplied with the ++** the name of a table V and columns V.W and V.L such that ++** ++** SELECT W FROM V WHERE L=$language ++** ++** returns the allowed vocabulary for the match. If the "vocabulary_language" ++** or L columnname is left unspecified or is an empty string, then no ++** filtering of the vocabulary by language is performed. ++** ++** For efficiency, it is essential that the vocabulary table be indexed: ++** ++** CREATE vocab_index ON V(W) ++** ++** A separate edit-cost-table provides scoring information that defines ++** what it means for one string to be "close" to another. ++** ++** The edit-cost-table must contain exactly four columns (more precisely, ++** the statement "SELECT * FROM " must return records ++** that consist of four columns). It does not matter what the columns are ++** named. ++** ++** Each row in the edit-cost-table represents a single character ++** transformation going from user input to the vocabulary. The leftmost ++** column of the row (column 0) contains an integer identifier of the ++** language to which the transformation rule belongs (see "MULTIPLE LANGUAGES" ++** below). The second column of the row (column 1) contains the input ++** character or characters - the characters of user input. The third ++** column contains characters as they appear in the vocabulary table. ++** And the fourth column contains the integer cost of making the ++** transformation. For example: ++** ++** CREATE TABLE f_data(iLang, cFrom, cTo, Cost); ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '', 'a', 100); ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'b', '', 87); ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'o', 'oe', 38); ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'oe', 'o', 40); ++** ++** The first row inserted into the edit-cost-table by the SQL script ++** above indicates that the cost of having an extra 'a' in the vocabulary ++** table that is missing in the user input 100. (All costs are integers. ++** Overall cost must not exceed 16777216.) The second INSERT statement ++** creates a rule saying that the cost of having a single letter 'b' in ++** user input which is missing in the vocabulary table is 87. The third ++** INSERT statement mean that the cost of matching an 'o' in user input ++** against an 'oe' in the vocabulary table is 38. And so forth. ++** ++** The following rules are special: ++** ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '?', '', 97); ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '', '?', 98); ++** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '?', '?', 99); ++** ++** The '?' to '' rule is the cost of having any single character in the input ++** that is not found in the vocabular. The '' to '?' rule is the cost of ++** having a character in the vocabulary table that is missing from input. ++** And the '?' to '?' rule is the cost of doing an arbitrary character ++** substitution. These three generic rules apply across all languages. ++** In other words, the iLang field is ignored for the generic substitution ++** rules. If more than one cost is given for a generic substitution rule, ++** then the lowest cost is used. ++** ++** Once it has been created, the amatch virtual table can be queried ++** as follows: ++** ++** SELECT word, distance FROM f ++** WHERE word MATCH 'abcdefg' ++** AND distance<200; ++** ++** This query outputs the strings contained in the T(F) field that ++** are close to "abcdefg" and in order of increasing distance. No string ++** is output more than once. If there are multiple ways to transform the ++** target string ("abcdefg") into a string in the vocabulary table then ++** the lowest cost transform is the one that is returned. In this example, ++** the search is limited to strings with a total distance of less than 200. ++** ++** For efficiency, it is important to put tight bounds on the distance. ++** The time and memory space needed to perform this query is exponential ++** in the maximum distance. A good rule of thumb is to limit the distance ++** to no more than 1.5 or 2 times the maximum cost of any rule in the ++** edit-cost-table. ++** ++** The amatch is a read-only table. Any attempt to DELETE, INSERT, or ++** UPDATE on a amatch table will throw an error. ++** ++** It is important to put some kind of a limit on the amatch output. This ++** can be either in the form of a LIMIT clause at the end of the query, ++** or better, a "distance ++#include ++#include ++#include ++#include ++ ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ ++/* ++** Forward declaration of objects used by this implementation ++*/ ++typedef struct amatch_vtab amatch_vtab; ++typedef struct amatch_cursor amatch_cursor; ++typedef struct amatch_rule amatch_rule; ++typedef struct amatch_word amatch_word; ++typedef struct amatch_avl amatch_avl; ++ ++ ++/***************************************************************************** ++** AVL Tree implementation ++*/ ++/* ++** Objects that want to be members of the AVL tree should embedded an ++** instance of this structure. ++*/ ++struct amatch_avl { ++ amatch_word *pWord; /* Points to the object being stored in the tree */ ++ char *zKey; /* Key. zero-terminated string. Must be unique */ ++ amatch_avl *pBefore; /* Other elements less than zKey */ ++ amatch_avl *pAfter; /* Other elements greater than zKey */ ++ amatch_avl *pUp; /* Parent element */ ++ short int height; /* Height of this node. Leaf==1 */ ++ short int imbalance; /* Height difference between pBefore and pAfter */ ++}; ++ ++/* Recompute the amatch_avl.height and amatch_avl.imbalance fields for p. ++** Assume that the children of p have correct heights. ++*/ ++static void amatchAvlRecomputeHeight(amatch_avl *p){ ++ short int hBefore = p->pBefore ? p->pBefore->height : 0; ++ short int hAfter = p->pAfter ? p->pAfter->height : 0; ++ p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */ ++ p->height = (hBefore>hAfter ? hBefore : hAfter)+1; ++} ++ ++/* ++** P B ++** / \ / \ ++** B Z ==> X P ++** / \ / \ ++** X Y Y Z ++** ++*/ ++static amatch_avl *amatchAvlRotateBefore(amatch_avl *pP){ ++ amatch_avl *pB = pP->pBefore; ++ amatch_avl *pY = pB->pAfter; ++ pB->pUp = pP->pUp; ++ pB->pAfter = pP; ++ pP->pUp = pB; ++ pP->pBefore = pY; ++ if( pY ) pY->pUp = pP; ++ amatchAvlRecomputeHeight(pP); ++ amatchAvlRecomputeHeight(pB); ++ return pB; ++} ++ ++/* ++** P A ++** / \ / \ ++** X A ==> P Z ++** / \ / \ ++** Y Z X Y ++** ++*/ ++static amatch_avl *amatchAvlRotateAfter(amatch_avl *pP){ ++ amatch_avl *pA = pP->pAfter; ++ amatch_avl *pY = pA->pBefore; ++ pA->pUp = pP->pUp; ++ pA->pBefore = pP; ++ pP->pUp = pA; ++ pP->pAfter = pY; ++ if( pY ) pY->pUp = pP; ++ amatchAvlRecomputeHeight(pP); ++ amatchAvlRecomputeHeight(pA); ++ return pA; ++} ++ ++/* ++** Return a pointer to the pBefore or pAfter pointer in the parent ++** of p that points to p. Or if p is the root node, return pp. ++*/ ++static amatch_avl **amatchAvlFromPtr(amatch_avl *p, amatch_avl **pp){ ++ amatch_avl *pUp = p->pUp; ++ if( pUp==0 ) return pp; ++ if( pUp->pAfter==p ) return &pUp->pAfter; ++ return &pUp->pBefore; ++} ++ ++/* ++** Rebalance all nodes starting with p and working up to the root. ++** Return the new root. ++*/ ++static amatch_avl *amatchAvlBalance(amatch_avl *p){ ++ amatch_avl *pTop = p; ++ amatch_avl **pp; ++ while( p ){ ++ amatchAvlRecomputeHeight(p); ++ if( p->imbalance>=2 ){ ++ amatch_avl *pB = p->pBefore; ++ if( pB->imbalance<0 ) p->pBefore = amatchAvlRotateAfter(pB); ++ pp = amatchAvlFromPtr(p,&p); ++ p = *pp = amatchAvlRotateBefore(p); ++ }else if( p->imbalance<=(-2) ){ ++ amatch_avl *pA = p->pAfter; ++ if( pA->imbalance>0 ) p->pAfter = amatchAvlRotateBefore(pA); ++ pp = amatchAvlFromPtr(p,&p); ++ p = *pp = amatchAvlRotateAfter(p); ++ } ++ pTop = p; ++ p = p->pUp; ++ } ++ return pTop; ++} ++ ++/* Search the tree rooted at p for an entry with zKey. Return a pointer ++** to the entry or return NULL. ++*/ ++static amatch_avl *amatchAvlSearch(amatch_avl *p, const char *zKey){ ++ int c; ++ while( p && (c = strcmp(zKey, p->zKey))!=0 ){ ++ p = (c<0) ? p->pBefore : p->pAfter; ++ } ++ return p; ++} ++ ++/* Find the first node (the one with the smallest key). ++*/ ++static amatch_avl *amatchAvlFirst(amatch_avl *p){ ++ if( p ) while( p->pBefore ) p = p->pBefore; ++ return p; ++} ++ ++#if 0 /* NOT USED */ ++/* Return the node with the next larger key after p. ++*/ ++static amatch_avl *amatchAvlNext(amatch_avl *p){ ++ amatch_avl *pPrev = 0; ++ while( p && p->pAfter==pPrev ){ ++ pPrev = p; ++ p = p->pUp; ++ } ++ if( p && pPrev==0 ){ ++ p = amatchAvlFirst(p->pAfter); ++ } ++ return p; ++} ++#endif ++ ++#if 0 /* NOT USED */ ++/* Verify AVL tree integrity ++*/ ++static int amatchAvlIntegrity(amatch_avl *pHead){ ++ amatch_avl *p; ++ if( pHead==0 ) return 1; ++ if( (p = pHead->pBefore)!=0 ){ ++ assert( p->pUp==pHead ); ++ assert( amatchAvlIntegrity(p) ); ++ assert( strcmp(p->zKey, pHead->zKey)<0 ); ++ while( p->pAfter ) p = p->pAfter; ++ assert( strcmp(p->zKey, pHead->zKey)<0 ); ++ } ++ if( (p = pHead->pAfter)!=0 ){ ++ assert( p->pUp==pHead ); ++ assert( amatchAvlIntegrity(p) ); ++ assert( strcmp(p->zKey, pHead->zKey)>0 ); ++ p = amatchAvlFirst(p); ++ assert( strcmp(p->zKey, pHead->zKey)>0 ); ++ } ++ return 1; ++} ++static int amatchAvlIntegrity2(amatch_avl *pHead){ ++ amatch_avl *p, *pNext; ++ for(p=amatchAvlFirst(pHead); p; p=pNext){ ++ pNext = amatchAvlNext(p); ++ if( pNext==0 ) break; ++ assert( strcmp(p->zKey, pNext->zKey)<0 ); ++ } ++ return 1; ++} ++#endif ++ ++/* Insert a new node pNew. Return NULL on success. If the key is not ++** unique, then do not perform the insert but instead leave pNew unchanged ++** and return a pointer to an existing node with the same key. ++*/ ++static amatch_avl *amatchAvlInsert(amatch_avl **ppHead, amatch_avl *pNew){ ++ int c; ++ amatch_avl *p = *ppHead; ++ if( p==0 ){ ++ p = pNew; ++ pNew->pUp = 0; ++ }else{ ++ while( p ){ ++ c = strcmp(pNew->zKey, p->zKey); ++ if( c<0 ){ ++ if( p->pBefore ){ ++ p = p->pBefore; ++ }else{ ++ p->pBefore = pNew; ++ pNew->pUp = p; ++ break; ++ } ++ }else if( c>0 ){ ++ if( p->pAfter ){ ++ p = p->pAfter; ++ }else{ ++ p->pAfter = pNew; ++ pNew->pUp = p; ++ break; ++ } ++ }else{ ++ return p; ++ } ++ } ++ } ++ pNew->pBefore = 0; ++ pNew->pAfter = 0; ++ pNew->height = 1; ++ pNew->imbalance = 0; ++ *ppHead = amatchAvlBalance(p); ++ /* assert( amatchAvlIntegrity(*ppHead) ); */ ++ /* assert( amatchAvlIntegrity2(*ppHead) ); */ ++ return 0; ++} ++ ++/* Remove node pOld from the tree. pOld must be an element of the tree or ++** the AVL tree will become corrupt. ++*/ ++static void amatchAvlRemove(amatch_avl **ppHead, amatch_avl *pOld){ ++ amatch_avl **ppParent; ++ amatch_avl *pBalance = 0; ++ /* assert( amatchAvlSearch(*ppHead, pOld->zKey)==pOld ); */ ++ ppParent = amatchAvlFromPtr(pOld, ppHead); ++ if( pOld->pBefore==0 && pOld->pAfter==0 ){ ++ *ppParent = 0; ++ pBalance = pOld->pUp; ++ }else if( pOld->pBefore && pOld->pAfter ){ ++ amatch_avl *pX, *pY; ++ pX = amatchAvlFirst(pOld->pAfter); ++ *amatchAvlFromPtr(pX, 0) = pX->pAfter; ++ if( pX->pAfter ) pX->pAfter->pUp = pX->pUp; ++ pBalance = pX->pUp; ++ pX->pAfter = pOld->pAfter; ++ if( pX->pAfter ){ ++ pX->pAfter->pUp = pX; ++ }else{ ++ assert( pBalance==pOld ); ++ pBalance = pX; ++ } ++ pX->pBefore = pY = pOld->pBefore; ++ if( pY ) pY->pUp = pX; ++ pX->pUp = pOld->pUp; ++ *ppParent = pX; ++ }else if( pOld->pBefore==0 ){ ++ *ppParent = pBalance = pOld->pAfter; ++ pBalance->pUp = pOld->pUp; ++ }else if( pOld->pAfter==0 ){ ++ *ppParent = pBalance = pOld->pBefore; ++ pBalance->pUp = pOld->pUp; ++ } ++ *ppHead = amatchAvlBalance(pBalance); ++ pOld->pUp = 0; ++ pOld->pBefore = 0; ++ pOld->pAfter = 0; ++ /* assert( amatchAvlIntegrity(*ppHead) ); */ ++ /* assert( amatchAvlIntegrity2(*ppHead) ); */ ++} ++/* ++** End of the AVL Tree implementation ++******************************************************************************/ ++ ++ ++/* ++** Various types. ++** ++** amatch_cost is the "cost" of an edit operation. ++** ++** amatch_len is the length of a matching string. ++** ++** amatch_langid is an ruleset identifier. ++*/ ++typedef int amatch_cost; ++typedef signed char amatch_len; ++typedef int amatch_langid; ++ ++/* ++** Limits ++*/ ++#define AMATCH_MX_LENGTH 50 /* Maximum length of a rule string */ ++#define AMATCH_MX_LANGID 2147483647 /* Maximum rule ID */ ++#define AMATCH_MX_COST 1000 /* Maximum single-rule cost */ ++ ++/* ++** A match or partial match ++*/ ++struct amatch_word { ++ amatch_word *pNext; /* Next on a list of all amatch_words */ ++ amatch_avl sCost; /* Linkage of this node into the cost tree */ ++ amatch_avl sWord; /* Linkage of this node into the word tree */ ++ amatch_cost rCost; /* Cost of the match so far */ ++ int iSeq; /* Sequence number */ ++ char zCost[10]; /* Cost key (text rendering of rCost) */ ++ short int nMatch; /* Input characters matched */ ++ char zWord[4]; /* Text of the word. Extra space appended as needed */ ++}; ++ ++/* ++** Each transformation rule is stored as an instance of this object. ++** All rules are kept on a linked list sorted by rCost. ++*/ ++struct amatch_rule { ++ amatch_rule *pNext; /* Next rule in order of increasing rCost */ ++ char *zFrom; /* Transform from (a string from user input) */ ++ amatch_cost rCost; /* Cost of this transformation */ ++ amatch_langid iLang; /* The langauge to which this rule belongs */ ++ amatch_len nFrom, nTo; /* Length of the zFrom and zTo strings */ ++ char zTo[4]; /* Tranform to V.W value (extra space appended) */ ++}; ++ ++/* ++** A amatch virtual-table object ++*/ ++struct amatch_vtab { ++ sqlite3_vtab base; /* Base class - must be first */ ++ char *zClassName; /* Name of this class. Default: "amatch" */ ++ char *zDb; /* Name of database. (ex: "main") */ ++ char *zSelf; /* Name of this virtual table */ ++ char *zCostTab; /* Name of edit-cost-table */ ++ char *zVocabTab; /* Name of vocabulary table */ ++ char *zVocabWord; /* Name of vocabulary table word column */ ++ char *zVocabLang; /* Name of vocabulary table language column */ ++ amatch_rule *pRule; /* All active rules in this amatch */ ++ amatch_cost rIns; /* Generic insertion cost '' -> ? */ ++ amatch_cost rDel; /* Generic deletion cost ? -> '' */ ++ amatch_cost rSub; /* Generic substitution cost ? -> ? */ ++ sqlite3 *db; /* The database connection */ ++ sqlite3_stmt *pVCheck; /* Query to check zVocabTab */ ++ int nCursor; /* Number of active cursors */ ++}; ++ ++/* A amatch cursor object */ ++struct amatch_cursor { ++ sqlite3_vtab_cursor base; /* Base class - must be first */ ++ sqlite3_int64 iRowid; /* The rowid of the current word */ ++ amatch_langid iLang; /* Use this language ID */ ++ amatch_cost rLimit; /* Maximum cost of any term */ ++ int nBuf; /* Space allocated for zBuf */ ++ int oomErr; /* True following an OOM error */ ++ int nWord; /* Number of amatch_word objects */ ++ char *zBuf; /* Temp-use buffer space */ ++ char *zInput; /* Input word to match against */ ++ amatch_vtab *pVtab; /* The virtual table this cursor belongs to */ ++ amatch_word *pAllWords; /* List of all amatch_word objects */ ++ amatch_word *pCurrent; /* Most recent solution */ ++ amatch_avl *pCost; /* amatch_word objects keyed by iCost */ ++ amatch_avl *pWord; /* amatch_word objects keyed by zWord */ ++}; ++ ++/* ++** The two input rule lists are both sorted in order of increasing ++** cost. Merge them together into a single list, sorted by cost, and ++** return a pointer to the head of that list. ++*/ ++static amatch_rule *amatchMergeRules(amatch_rule *pA, amatch_rule *pB){ ++ amatch_rule head; ++ amatch_rule *pTail; ++ ++ pTail = &head; ++ while( pA && pB ){ ++ if( pA->rCost<=pB->rCost ){ ++ pTail->pNext = pA; ++ pTail = pA; ++ pA = pA->pNext; ++ }else{ ++ pTail->pNext = pB; ++ pTail = pB; ++ pB = pB->pNext; ++ } ++ } ++ if( pA==0 ){ ++ pTail->pNext = pB; ++ }else{ ++ pTail->pNext = pA; ++ } ++ return head.pNext; ++} ++ ++/* ++** Statement pStmt currently points to a row in the amatch data table. This ++** function allocates and populates a amatch_rule structure according to ++** the content of the row. ++** ++** If successful, *ppRule is set to point to the new object and SQLITE_OK ++** is returned. Otherwise, *ppRule is zeroed, *pzErr may be set to point ++** to an error message and an SQLite error code returned. ++*/ ++static int amatchLoadOneRule( ++ amatch_vtab *p, /* Fuzzer virtual table handle */ ++ sqlite3_stmt *pStmt, /* Base rule on statements current row */ ++ amatch_rule **ppRule, /* OUT: New rule object */ ++ char **pzErr /* OUT: Error message */ ++){ ++ sqlite3_int64 iLang = sqlite3_column_int64(pStmt, 0); ++ const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1); ++ const char *zTo = (const char *)sqlite3_column_text(pStmt, 2); ++ amatch_cost rCost = sqlite3_column_int(pStmt, 3); ++ ++ int rc = SQLITE_OK; /* Return code */ ++ int nFrom; /* Size of string zFrom, in bytes */ ++ int nTo; /* Size of string zTo, in bytes */ ++ amatch_rule *pRule = 0; /* New rule object to return */ ++ ++ if( zFrom==0 ) zFrom = ""; ++ if( zTo==0 ) zTo = ""; ++ nFrom = (int)strlen(zFrom); ++ nTo = (int)strlen(zTo); ++ ++ /* Silently ignore null transformations */ ++ if( strcmp(zFrom, zTo)==0 ){ ++ if( zFrom[0]=='?' && zFrom[1]==0 ){ ++ if( p->rSub==0 || p->rSub>rCost ) p->rSub = rCost; ++ } ++ *ppRule = 0; ++ return SQLITE_OK; ++ } ++ ++ if( rCost<=0 || rCost>AMATCH_MX_COST ){ ++ *pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d", ++ p->zClassName, AMATCH_MX_COST ++ ); ++ rc = SQLITE_ERROR; ++ }else ++ if( nFrom>AMATCH_MX_LENGTH || nTo>AMATCH_MX_LENGTH ){ ++ *pzErr = sqlite3_mprintf("%s: maximum string length is %d", ++ p->zClassName, AMATCH_MX_LENGTH ++ ); ++ rc = SQLITE_ERROR; ++ }else ++ if( iLang<0 || iLang>AMATCH_MX_LANGID ){ ++ *pzErr = sqlite3_mprintf("%s: iLang must be between 0 and %d", ++ p->zClassName, AMATCH_MX_LANGID ++ ); ++ rc = SQLITE_ERROR; ++ }else ++ if( strcmp(zFrom,"")==0 && strcmp(zTo,"?")==0 ){ ++ if( p->rIns==0 || p->rIns>rCost ) p->rIns = rCost; ++ }else ++ if( strcmp(zFrom,"?")==0 && strcmp(zTo,"")==0 ){ ++ if( p->rDel==0 || p->rDel>rCost ) p->rDel = rCost; ++ }else ++ { ++ pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo ); ++ if( pRule==0 ){ ++ rc = SQLITE_NOMEM; ++ }else{ ++ memset(pRule, 0, sizeof(*pRule)); ++ pRule->zFrom = &pRule->zTo[nTo+1]; ++ pRule->nFrom = nFrom; ++ memcpy(pRule->zFrom, zFrom, nFrom+1); ++ memcpy(pRule->zTo, zTo, nTo+1); ++ pRule->nTo = nTo; ++ pRule->rCost = rCost; ++ pRule->iLang = (int)iLang; ++ } ++ } ++ ++ *ppRule = pRule; ++ return rc; ++} ++ ++/* ++** Free all the content in the edit-cost-table ++*/ ++static void amatchFreeRules(amatch_vtab *p){ ++ while( p->pRule ){ ++ amatch_rule *pRule = p->pRule; ++ p->pRule = pRule->pNext; ++ sqlite3_free(pRule); ++ } ++ p->pRule = 0; ++} ++ ++/* ++** Load the content of the amatch data table into memory. ++*/ ++static int amatchLoadRules( ++ sqlite3 *db, /* Database handle */ ++ amatch_vtab *p, /* Virtual amatch table to configure */ ++ char **pzErr /* OUT: Error message */ ++){ ++ int rc = SQLITE_OK; /* Return code */ ++ char *zSql; /* SELECT used to read from rules table */ ++ amatch_rule *pHead = 0; ++ ++ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zCostTab); ++ if( zSql==0 ){ ++ rc = SQLITE_NOMEM; ++ }else{ ++ int rc2; /* finalize() return code */ ++ sqlite3_stmt *pStmt = 0; ++ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); ++ if( rc!=SQLITE_OK ){ ++ *pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db)); ++ }else if( sqlite3_column_count(pStmt)!=4 ){ ++ *pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4", ++ p->zClassName, p->zCostTab, sqlite3_column_count(pStmt) ++ ); ++ rc = SQLITE_ERROR; ++ }else{ ++ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ ++ amatch_rule *pRule = 0; ++ rc = amatchLoadOneRule(p, pStmt, &pRule, pzErr); ++ if( pRule ){ ++ pRule->pNext = pHead; ++ pHead = pRule; ++ } ++ } ++ } ++ rc2 = sqlite3_finalize(pStmt); ++ if( rc==SQLITE_OK ) rc = rc2; ++ } ++ sqlite3_free(zSql); ++ ++ /* All rules are now in a singly linked list starting at pHead. This ++ ** block sorts them by cost and then sets amatch_vtab.pRule to point to ++ ** point to the head of the sorted list. ++ */ ++ if( rc==SQLITE_OK ){ ++ unsigned int i; ++ amatch_rule *pX; ++ amatch_rule *a[15]; ++ for(i=0; ipNext; ++ pX->pNext = 0; ++ for(i=0; a[i] && ipRule = amatchMergeRules(p->pRule, pX); ++ }else{ ++ /* An error has occurred. Setting p->pRule to point to the head of the ++ ** allocated list ensures that the list will be cleaned up in this case. ++ */ ++ assert( p->pRule==0 ); ++ p->pRule = pHead; ++ } ++ ++ return rc; ++} ++ ++/* ++** This function converts an SQL quoted string into an unquoted string ++** and returns a pointer to a buffer allocated using sqlite3_malloc() ++** containing the result. The caller should eventually free this buffer ++** using sqlite3_free. ++** ++** Examples: ++** ++** "abc" becomes abc ++** 'xyz' becomes xyz ++** [pqr] becomes pqr ++** `mno` becomes mno ++*/ ++static char *amatchDequote(const char *zIn){ ++ int nIn; /* Size of input string, in bytes */ ++ char *zOut; /* Output (dequoted) string */ ++ ++ nIn = (int)strlen(zIn); ++ zOut = sqlite3_malloc(nIn+1); ++ if( zOut ){ ++ char q = zIn[0]; /* Quote character (if any ) */ ++ ++ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ ++ memcpy(zOut, zIn, nIn+1); ++ }else{ ++ int iOut = 0; /* Index of next byte to write to output */ ++ int iIn; /* Index of next byte to read from input */ ++ ++ if( q=='[' ) q = ']'; ++ for(iIn=1; iInpVCheck ){ ++ sqlite3_finalize(p->pVCheck); ++ p->pVCheck = 0; ++ } ++} ++ ++/* ++** Deallocate an amatch_vtab object ++*/ ++static void amatchFree(amatch_vtab *p){ ++ if( p ){ ++ amatchFreeRules(p); ++ amatchVCheckClear(p); ++ sqlite3_free(p->zClassName); ++ sqlite3_free(p->zDb); ++ sqlite3_free(p->zCostTab); ++ sqlite3_free(p->zVocabTab); ++ sqlite3_free(p->zVocabWord); ++ sqlite3_free(p->zVocabLang); ++ sqlite3_free(p->zSelf); ++ memset(p, 0, sizeof(*p)); ++ sqlite3_free(p); ++ } ++} ++ ++/* ++** xDisconnect/xDestroy method for the amatch module. ++*/ ++static int amatchDisconnect(sqlite3_vtab *pVtab){ ++ amatch_vtab *p = (amatch_vtab*)pVtab; ++ assert( p->nCursor==0 ); ++ amatchFree(p); ++ return SQLITE_OK; ++} ++ ++/* ++** Check to see if the argument is of the form: ++** ++** KEY = VALUE ++** ++** If it is, return a pointer to the first character of VALUE. ++** If not, return NULL. Spaces around the = are ignored. ++*/ ++static const char *amatchValueOfKey(const char *zKey, const char *zStr){ ++ int nKey = (int)strlen(zKey); ++ int nStr = (int)strlen(zStr); ++ int i; ++ if( nStr module name ("approximate_match") ++** argv[1] -> database name ++** argv[2] -> table name ++** argv[3...] -> arguments ++*/ ++static int amatchConnect( ++ sqlite3 *db, ++ void *pAux, ++ int argc, const char *const*argv, ++ sqlite3_vtab **ppVtab, ++ char **pzErr ++){ ++ int rc = SQLITE_OK; /* Return code */ ++ amatch_vtab *pNew = 0; /* New virtual table */ ++ const char *zModule = argv[0]; ++ const char *zDb = argv[1]; ++ const char *zVal; ++ int i; ++ ++ (void)pAux; ++ *ppVtab = 0; ++ pNew = sqlite3_malloc( sizeof(*pNew) ); ++ if( pNew==0 ) return SQLITE_NOMEM; ++ rc = SQLITE_NOMEM; ++ memset(pNew, 0, sizeof(*pNew)); ++ pNew->db = db; ++ pNew->zClassName = sqlite3_mprintf("%s", zModule); ++ if( pNew->zClassName==0 ) goto amatchConnectError; ++ pNew->zDb = sqlite3_mprintf("%s", zDb); ++ if( pNew->zDb==0 ) goto amatchConnectError; ++ pNew->zSelf = sqlite3_mprintf("%s", argv[2]); ++ if( pNew->zSelf==0 ) goto amatchConnectError; ++ for(i=3; izVocabTab); ++ pNew->zVocabTab = amatchDequote(zVal); ++ if( pNew->zVocabTab==0 ) goto amatchConnectError; ++ continue; ++ } ++ zVal = amatchValueOfKey("vocabulary_word", argv[i]); ++ if( zVal ){ ++ sqlite3_free(pNew->zVocabWord); ++ pNew->zVocabWord = amatchDequote(zVal); ++ if( pNew->zVocabWord==0 ) goto amatchConnectError; ++ continue; ++ } ++ zVal = amatchValueOfKey("vocabulary_language", argv[i]); ++ if( zVal ){ ++ sqlite3_free(pNew->zVocabLang); ++ pNew->zVocabLang = amatchDequote(zVal); ++ if( pNew->zVocabLang==0 ) goto amatchConnectError; ++ continue; ++ } ++ zVal = amatchValueOfKey("edit_distances", argv[i]); ++ if( zVal ){ ++ sqlite3_free(pNew->zCostTab); ++ pNew->zCostTab = amatchDequote(zVal); ++ if( pNew->zCostTab==0 ) goto amatchConnectError; ++ continue; ++ } ++ *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]); ++ amatchFree(pNew); ++ *ppVtab = 0; ++ return SQLITE_ERROR; ++ } ++ rc = SQLITE_OK; ++ if( pNew->zCostTab==0 ){ ++ *pzErr = sqlite3_mprintf("no edit_distances table specified"); ++ rc = SQLITE_ERROR; ++ }else{ ++ rc = amatchLoadRules(db, pNew, pzErr); ++ } ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_declare_vtab(db, ++ "CREATE TABLE x(word,distance,language," ++ "command HIDDEN,nword HIDDEN)" ++ ); ++#define AMATCH_COL_WORD 0 ++#define AMATCH_COL_DISTANCE 1 ++#define AMATCH_COL_LANGUAGE 2 ++#define AMATCH_COL_COMMAND 3 ++#define AMATCH_COL_NWORD 4 ++ } ++ if( rc!=SQLITE_OK ){ ++ amatchFree(pNew); ++ } ++ *ppVtab = &pNew->base; ++ return rc; ++ ++amatchConnectError: ++ amatchFree(pNew); ++ return rc; ++} ++ ++/* ++** Open a new amatch cursor. ++*/ ++static int amatchOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ ++ amatch_vtab *p = (amatch_vtab*)pVTab; ++ amatch_cursor *pCur; ++ pCur = sqlite3_malloc( sizeof(*pCur) ); ++ if( pCur==0 ) return SQLITE_NOMEM; ++ memset(pCur, 0, sizeof(*pCur)); ++ pCur->pVtab = p; ++ *ppCursor = &pCur->base; ++ p->nCursor++; ++ return SQLITE_OK; ++} ++ ++/* ++** Free up all the memory allocated by a cursor. Set it rLimit to 0 ++** to indicate that it is at EOF. ++*/ ++static void amatchClearCursor(amatch_cursor *pCur){ ++ amatch_word *pWord, *pNextWord; ++ for(pWord=pCur->pAllWords; pWord; pWord=pNextWord){ ++ pNextWord = pWord->pNext; ++ sqlite3_free(pWord); ++ } ++ pCur->pAllWords = 0; ++ sqlite3_free(pCur->zInput); ++ pCur->zInput = 0; ++ sqlite3_free(pCur->zBuf); ++ pCur->zBuf = 0; ++ pCur->nBuf = 0; ++ pCur->pCost = 0; ++ pCur->pWord = 0; ++ pCur->pCurrent = 0; ++ pCur->rLimit = 1000000; ++ pCur->iLang = 0; ++ pCur->nWord = 0; ++} ++ ++/* ++** Close a amatch cursor. ++*/ ++static int amatchClose(sqlite3_vtab_cursor *cur){ ++ amatch_cursor *pCur = (amatch_cursor *)cur; ++ amatchClearCursor(pCur); ++ pCur->pVtab->nCursor--; ++ sqlite3_free(pCur); ++ return SQLITE_OK; ++} ++ ++/* ++** Render a 24-bit unsigned integer as a 4-byte base-64 number. ++*/ ++static void amatchEncodeInt(int x, char *z){ ++ static const char a[] = ++ "0123456789" ++ "ABCDEFGHIJ" ++ "KLMNOPQRST" ++ "UVWXYZ^abc" ++ "defghijklm" ++ "nopqrstuvw" ++ "xyz~"; ++ z[0] = a[(x>>18)&0x3f]; ++ z[1] = a[(x>>12)&0x3f]; ++ z[2] = a[(x>>6)&0x3f]; ++ z[3] = a[x&0x3f]; ++} ++ ++/* ++** Write the zCost[] field for a amatch_word object ++*/ ++static void amatchWriteCost(amatch_word *pWord){ ++ amatchEncodeInt(pWord->rCost, pWord->zCost); ++ amatchEncodeInt(pWord->iSeq, pWord->zCost+4); ++ pWord->zCost[8] = 0; ++} ++ ++/* Circumvent compiler warnings about the use of strcpy() by supplying ++** our own implementation. ++*/ ++#if defined(__OpenBSD__) ++static void amatchStrcpy(char *dest, const char *src){ ++ while( (*(dest++) = *(src++))!=0 ){} ++} ++static void amatchStrcat(char *dest, const char *src){ ++ while( *dest ) dest++; ++ amatchStrcpy(dest, src); ++} ++#else ++# define amatchStrcpy strcpy ++# define amatchStrcat strcat ++#endif ++ ++ ++/* ++** Add a new amatch_word object to the queue. ++** ++** If a prior amatch_word object with the same zWord, and nMatch ++** already exists, update its rCost (if the new rCost is less) but ++** otherwise leave it unchanged. Do not add a duplicate. ++** ++** Do nothing if the cost exceeds threshold. ++*/ ++static void amatchAddWord( ++ amatch_cursor *pCur, ++ amatch_cost rCost, ++ int nMatch, ++ const char *zWordBase, ++ const char *zWordTail ++){ ++ amatch_word *pWord; ++ amatch_avl *pNode; ++ amatch_avl *pOther; ++ int nBase, nTail; ++ char zBuf[4]; ++ ++ if( rCost>pCur->rLimit ){ ++ return; ++ } ++ nBase = (int)strlen(zWordBase); ++ nTail = (int)strlen(zWordTail); ++ if( nBase+nTail+3>pCur->nBuf ){ ++ pCur->nBuf = nBase+nTail+100; ++ pCur->zBuf = sqlite3_realloc(pCur->zBuf, pCur->nBuf); ++ if( pCur->zBuf==0 ){ ++ pCur->nBuf = 0; ++ return; ++ } ++ } ++ amatchEncodeInt(nMatch, zBuf); ++ memcpy(pCur->zBuf, zBuf+2, 2); ++ memcpy(pCur->zBuf+2, zWordBase, nBase); ++ memcpy(pCur->zBuf+2+nBase, zWordTail, nTail+1); ++ pNode = amatchAvlSearch(pCur->pWord, pCur->zBuf); ++ if( pNode ){ ++ pWord = pNode->pWord; ++ if( pWord->rCost>rCost ){ ++#ifdef AMATCH_TRACE_1 ++ printf("UPDATE [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", ++ pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput, ++ pWord->rCost, pWord->zWord, pWord->zCost); ++#endif ++ amatchAvlRemove(&pCur->pCost, &pWord->sCost); ++ pWord->rCost = rCost; ++ amatchWriteCost(pWord); ++#ifdef AMATCH_TRACE_1 ++ printf(" ---> %d (\"%s\" \"%s\")\n", ++ pWord->rCost, pWord->zWord, pWord->zCost); ++#endif ++ pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost); ++ assert( pOther==0 ); (void)pOther; ++ } ++ return; ++ } ++ pWord = sqlite3_malloc( sizeof(*pWord) + nBase + nTail - 1 ); ++ if( pWord==0 ) return; ++ memset(pWord, 0, sizeof(*pWord)); ++ pWord->rCost = rCost; ++ pWord->iSeq = pCur->nWord++; ++ amatchWriteCost(pWord); ++ pWord->nMatch = nMatch; ++ pWord->pNext = pCur->pAllWords; ++ pCur->pAllWords = pWord; ++ pWord->sCost.zKey = pWord->zCost; ++ pWord->sCost.pWord = pWord; ++ pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost); ++ assert( pOther==0 ); (void)pOther; ++ pWord->sWord.zKey = pWord->zWord; ++ pWord->sWord.pWord = pWord; ++ amatchStrcpy(pWord->zWord, pCur->zBuf); ++ pOther = amatchAvlInsert(&pCur->pWord, &pWord->sWord); ++ assert( pOther==0 ); (void)pOther; ++#ifdef AMATCH_TRACE_1 ++ printf("INSERT [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", pWord->zWord+2, ++ pWord->nMatch, pCur->zInput, pCur->zInput+pWord->nMatch, rCost, ++ pWord->zWord, pWord->zCost); ++#endif ++} ++ ++ ++/* ++** Advance a cursor to its next row of output ++*/ ++static int amatchNext(sqlite3_vtab_cursor *cur){ ++ amatch_cursor *pCur = (amatch_cursor*)cur; ++ amatch_word *pWord = 0; ++ amatch_avl *pNode; ++ int isMatch = 0; ++ amatch_vtab *p = pCur->pVtab; ++ int nWord; ++ int rc; ++ int i; ++ const char *zW; ++ amatch_rule *pRule; ++ char *zBuf = 0; ++ char nBuf = 0; ++ char zNext[8]; ++ char zNextIn[8]; ++ int nNextIn; ++ ++ if( p->pVCheck==0 ){ ++ char *zSql; ++ if( p->zVocabLang && p->zVocabLang[0] ){ ++ zSql = sqlite3_mprintf( ++ "SELECT \"%w\" FROM \"%w\"", ++ " WHERE \"%w\">=?1 AND \"%w\"=?2" ++ " ORDER BY 1", ++ p->zVocabWord, p->zVocabTab, ++ p->zVocabWord, p->zVocabLang ++ ); ++ }else{ ++ zSql = sqlite3_mprintf( ++ "SELECT \"%w\" FROM \"%w\"" ++ " WHERE \"%w\">=?1" ++ " ORDER BY 1", ++ p->zVocabWord, p->zVocabTab, ++ p->zVocabWord ++ ); ++ } ++ rc = sqlite3_prepare_v2(p->db, zSql, -1, &p->pVCheck, 0); ++ sqlite3_free(zSql); ++ if( rc ) return rc; ++ } ++ sqlite3_bind_int(p->pVCheck, 2, pCur->iLang); ++ ++ do{ ++ pNode = amatchAvlFirst(pCur->pCost); ++ if( pNode==0 ){ ++ pWord = 0; ++ break; ++ } ++ pWord = pNode->pWord; ++ amatchAvlRemove(&pCur->pCost, &pWord->sCost); ++ ++#ifdef AMATCH_TRACE_1 ++ printf("PROCESS [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", ++ pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput+pWord->nMatch, ++ pWord->rCost, pWord->zWord, pWord->zCost); ++#endif ++ nWord = (int)strlen(pWord->zWord+2); ++ if( nWord+20>nBuf ){ ++ nBuf = nWord+100; ++ zBuf = sqlite3_realloc(zBuf, nBuf); ++ if( zBuf==0 ) return SQLITE_NOMEM; ++ } ++ amatchStrcpy(zBuf, pWord->zWord+2); ++ zNext[0] = 0; ++ zNextIn[0] = pCur->zInput[pWord->nMatch]; ++ if( zNextIn[0] ){ ++ for(i=1; i<=4 && (pCur->zInput[pWord->nMatch+i]&0xc0)==0x80; i++){ ++ zNextIn[i] = pCur->zInput[pWord->nMatch+i]; ++ } ++ zNextIn[i] = 0; ++ nNextIn = i; ++ }else{ ++ nNextIn = 0; ++ } ++ ++ if( zNextIn[0] && zNextIn[0]!='*' ){ ++ sqlite3_reset(p->pVCheck); ++ amatchStrcat(zBuf, zNextIn); ++ sqlite3_bind_text(p->pVCheck, 1, zBuf, nWord+nNextIn, SQLITE_STATIC); ++ rc = sqlite3_step(p->pVCheck); ++ if( rc==SQLITE_ROW ){ ++ zW = (const char*)sqlite3_column_text(p->pVCheck, 0); ++ if( strncmp(zBuf, zW, nWord+nNextIn)==0 ){ ++ amatchAddWord(pCur, pWord->rCost, pWord->nMatch+nNextIn, zBuf, ""); ++ } ++ } ++ zBuf[nWord] = 0; ++ } ++ ++ while( 1 ){ ++ amatchStrcpy(zBuf+nWord, zNext); ++ sqlite3_reset(p->pVCheck); ++ sqlite3_bind_text(p->pVCheck, 1, zBuf, -1, SQLITE_TRANSIENT); ++ rc = sqlite3_step(p->pVCheck); ++ if( rc!=SQLITE_ROW ) break; ++ zW = (const char*)sqlite3_column_text(p->pVCheck, 0); ++ amatchStrcpy(zBuf+nWord, zNext); ++ if( strncmp(zW, zBuf, nWord)!=0 ) break; ++ if( (zNextIn[0]=='*' && zNextIn[1]==0) ++ || (zNextIn[0]==0 && zW[nWord]==0) ++ ){ ++ isMatch = 1; ++ zNextIn[0] = 0; ++ nNextIn = 0; ++ break; ++ } ++ zNext[0] = zW[nWord]; ++ for(i=1; i<=4 && (zW[nWord+i]&0xc0)==0x80; i++){ ++ zNext[i] = zW[nWord+i]; ++ } ++ zNext[i] = 0; ++ zBuf[nWord] = 0; ++ if( p->rIns>0 ){ ++ amatchAddWord(pCur, pWord->rCost+p->rIns, pWord->nMatch, ++ zBuf, zNext); ++ } ++ if( p->rSub>0 ){ ++ amatchAddWord(pCur, pWord->rCost+p->rSub, pWord->nMatch+nNextIn, ++ zBuf, zNext); ++ } ++ if( p->rIns<0 && p->rSub<0 ) break; ++ zNext[i-1]++; /* FIX ME */ ++ } ++ sqlite3_reset(p->pVCheck); ++ ++ if( p->rDel>0 ){ ++ zBuf[nWord] = 0; ++ amatchAddWord(pCur, pWord->rCost+p->rDel, pWord->nMatch+nNextIn, ++ zBuf, ""); ++ } ++ ++ for(pRule=p->pRule; pRule; pRule=pRule->pNext){ ++ if( pRule->iLang!=pCur->iLang ) continue; ++ if( strncmp(pRule->zFrom, pCur->zInput+pWord->nMatch, pRule->nFrom)==0 ){ ++ amatchAddWord(pCur, pWord->rCost+pRule->rCost, ++ pWord->nMatch+pRule->nFrom, pWord->zWord+2, pRule->zTo); ++ } ++ } ++ }while( !isMatch ); ++ pCur->pCurrent = pWord; ++ sqlite3_free(zBuf); ++ return SQLITE_OK; ++} ++ ++/* ++** Called to "rewind" a cursor back to the beginning so that ++** it starts its output over again. Always called at least once ++** prior to any amatchColumn, amatchRowid, or amatchEof call. ++*/ ++static int amatchFilter( ++ sqlite3_vtab_cursor *pVtabCursor, ++ int idxNum, const char *idxStr, ++ int argc, sqlite3_value **argv ++){ ++ amatch_cursor *pCur = (amatch_cursor *)pVtabCursor; ++ const char *zWord = "*"; ++ int idx; ++ ++ amatchClearCursor(pCur); ++ idx = 0; ++ if( idxNum & 1 ){ ++ zWord = (const char*)sqlite3_value_text(argv[0]); ++ idx++; ++ } ++ if( idxNum & 2 ){ ++ pCur->rLimit = (amatch_cost)sqlite3_value_int(argv[idx]); ++ idx++; ++ } ++ if( idxNum & 4 ){ ++ pCur->iLang = (amatch_cost)sqlite3_value_int(argv[idx]); ++ idx++; ++ } ++ pCur->zInput = sqlite3_mprintf("%s", zWord); ++ if( pCur->zInput==0 ) return SQLITE_NOMEM; ++ amatchAddWord(pCur, 0, 0, "", ""); ++ amatchNext(pVtabCursor); ++ ++ return SQLITE_OK; ++} ++ ++/* ++** Only the word and distance columns have values. All other columns ++** return NULL ++*/ ++static int amatchColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ ++ amatch_cursor *pCur = (amatch_cursor*)cur; ++ switch( i ){ ++ case AMATCH_COL_WORD: { ++ sqlite3_result_text(ctx, pCur->pCurrent->zWord+2, -1, SQLITE_STATIC); ++ break; ++ } ++ case AMATCH_COL_DISTANCE: { ++ sqlite3_result_int(ctx, pCur->pCurrent->rCost); ++ break; ++ } ++ case AMATCH_COL_LANGUAGE: { ++ sqlite3_result_int(ctx, pCur->iLang); ++ break; ++ } ++ case AMATCH_COL_NWORD: { ++ sqlite3_result_int(ctx, pCur->nWord); ++ break; ++ } ++ default: { ++ sqlite3_result_null(ctx); ++ break; ++ } ++ } ++ return SQLITE_OK; ++} ++ ++/* ++** The rowid. ++*/ ++static int amatchRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ++ amatch_cursor *pCur = (amatch_cursor*)cur; ++ *pRowid = pCur->iRowid; ++ return SQLITE_OK; ++} ++ ++/* ++** EOF indicator ++*/ ++static int amatchEof(sqlite3_vtab_cursor *cur){ ++ amatch_cursor *pCur = (amatch_cursor*)cur; ++ return pCur->pCurrent==0; ++} ++ ++/* ++** Search for terms of these forms: ++** ++** (A) word MATCH $str ++** (B1) distance < $value ++** (B2) distance <= $value ++** (C) language == $language ++** ++** The distance< and distance<= are both treated as distance<=. ++** The query plan number is a bit vector: ++** ++** bit 1: Term of the form (A) found ++** bit 2: Term like (B1) or (B2) found ++** bit 3: Term like (C) found ++** ++** If bit-1 is set, $str is always in filter.argv[0]. If bit-2 is set ++** then $value is in filter.argv[0] if bit-1 is clear and is in ++** filter.argv[1] if bit-1 is set. If bit-3 is set, then $ruleid is ++** in filter.argv[0] if bit-1 and bit-2 are both zero, is in ++** filter.argv[1] if exactly one of bit-1 and bit-2 are set, and is in ++** filter.argv[2] if both bit-1 and bit-2 are set. ++*/ ++static int amatchBestIndex( ++ sqlite3_vtab *tab, ++ sqlite3_index_info *pIdxInfo ++){ ++ int iPlan = 0; ++ int iDistTerm = -1; ++ int iLangTerm = -1; ++ int i; ++ const struct sqlite3_index_constraint *pConstraint; ++ ++ (void)tab; ++ pConstraint = pIdxInfo->aConstraint; ++ for(i=0; inConstraint; i++, pConstraint++){ ++ if( pConstraint->usable==0 ) continue; ++ if( (iPlan & 1)==0 ++ && pConstraint->iColumn==0 ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ++ ){ ++ iPlan |= 1; ++ pIdxInfo->aConstraintUsage[i].argvIndex = 1; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ } ++ if( (iPlan & 2)==0 ++ && pConstraint->iColumn==1 ++ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ++ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE) ++ ){ ++ iPlan |= 2; ++ iDistTerm = i; ++ } ++ if( (iPlan & 4)==0 ++ && pConstraint->iColumn==2 ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ++ ){ ++ iPlan |= 4; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ iLangTerm = i; ++ } ++ } ++ if( iPlan & 2 ){ ++ pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1+((iPlan&1)!=0); ++ } ++ if( iPlan & 4 ){ ++ int idx = 1; ++ if( iPlan & 1 ) idx++; ++ if( iPlan & 2 ) idx++; ++ pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx; ++ } ++ pIdxInfo->idxNum = iPlan; ++ if( pIdxInfo->nOrderBy==1 ++ && pIdxInfo->aOrderBy[0].iColumn==1 ++ && pIdxInfo->aOrderBy[0].desc==0 ++ ){ ++ pIdxInfo->orderByConsumed = 1; ++ } ++ pIdxInfo->estimatedCost = (double)10000; ++ ++ return SQLITE_OK; ++} ++ ++/* ++** The xUpdate() method. ++** ++** This implementation disallows DELETE and UPDATE. The only thing ++** allowed is INSERT into the "command" column. ++*/ ++static int amatchUpdate( ++ sqlite3_vtab *pVTab, ++ int argc, ++ sqlite3_value **argv, ++ sqlite_int64 *pRowid ++){ ++ amatch_vtab *p = (amatch_vtab*)pVTab; ++ const unsigned char *zCmd; ++ (void)pRowid; ++ if( argc==1 ){ ++ pVTab->zErrMsg = sqlite3_mprintf("DELETE from %s is not allowed", ++ p->zSelf); ++ return SQLITE_ERROR; ++ } ++ if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){ ++ pVTab->zErrMsg = sqlite3_mprintf("UPDATE of %s is not allowed", ++ p->zSelf); ++ return SQLITE_ERROR; ++ } ++ if( sqlite3_value_type(argv[2+AMATCH_COL_WORD])!=SQLITE_NULL ++ || sqlite3_value_type(argv[2+AMATCH_COL_DISTANCE])!=SQLITE_NULL ++ || sqlite3_value_type(argv[2+AMATCH_COL_LANGUAGE])!=SQLITE_NULL ++ ){ ++ pVTab->zErrMsg = sqlite3_mprintf( ++ "INSERT INTO %s allowed for column [command] only", p->zSelf); ++ return SQLITE_ERROR; ++ } ++ zCmd = sqlite3_value_text(argv[2+AMATCH_COL_COMMAND]); ++ if( zCmd==0 ) return SQLITE_OK; ++ ++ return SQLITE_OK; ++} ++ ++/* ++** A virtual table module that implements the "approximate_match". ++*/ ++static const sqlite3_module amatchModule = { ++ 0, /* iVersion */ ++ amatchConnect, /* xCreate */ ++ amatchConnect, /* xConnect */ ++ amatchBestIndex, /* xBestIndex */ ++ amatchDisconnect, /* xDisconnect */ ++ amatchDisconnect, /* xDestroy */ ++ amatchOpen, /* xOpen - open a cursor */ ++ amatchClose, /* xClose - close a cursor */ ++ amatchFilter, /* xFilter - configure scan constraints */ ++ amatchNext, /* xNext - advance a cursor */ ++ amatchEof, /* xEof - check for end of scan */ ++ amatchColumn, /* xColumn - read data */ ++ amatchRowid, /* xRowid - read data */ ++ amatchUpdate, /* xUpdate */ ++ 0, /* xBegin */ ++ 0, /* xSync */ ++ 0, /* xCommit */ ++ 0, /* xRollback */ ++ 0, /* xFindMethod */ ++ 0, /* xRename */ ++ 0, /* xSavepoint */ ++ 0, /* xRelease */ ++ 0 /* xRollbackTo */ ++}; ++ ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ ++/* ++** Register the amatch virtual table ++*/ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_amatch_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Not used */ ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ rc = sqlite3_create_module(db, "approximate_match", &amatchModule, 0); ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Not used */ ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ rc = sqlite3_create_module(db, "approximate_match", &amatchModule, 0); ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/closure.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/closure.c 2016-01-06 16:30:42.472119600 +0100 +@@ -0,0 +1,973 @@ ++/* ++** 2013-04-16 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++************************************************************************* ++** ++** This file contains code for a virtual table that finds the transitive ++** closure of a parent/child relationship in a real table. The virtual ++** table is called "transitive_closure". ++** ++** A transitive_closure virtual table is created like this: ++** ++** CREATE VIRTUAL TABLE x USING transitive_closure( ++** tablename=, -- T ++** idcolumn=, -- X ++** parentcolumn= -- P ++** ); ++** ++** When it is created, the new transitive_closure table may be supplied ++** with default values for the name of a table T and columns T.X and T.P. ++** The T.X and T.P columns must contain integers. The ideal case is for ++** T.X to be the INTEGER PRIMARY KEY. The T.P column should reference ++** the T.X column. The row referenced by T.P is the parent of the current row. ++** ++** The tablename, idcolumn, and parentcolumn supplied by the CREATE VIRTUAL ++** TABLE statement may be overridden in individual queries by including ++** terms like tablename='newtable', idcolumn='id2', or ++** parentcolumn='parent3' in the WHERE clause of the query. ++** ++** For efficiency, it is essential that there be an index on the P column: ++** ++** CREATE Tidx1 ON T(P) ++** ++** Suppose a specific instance of the closure table is as follows: ++** ++** CREATE VIRTUAL TABLE ct1 USING transitive_closure( ++** tablename='group', ++** idcolumn='groupId', ++** parentcolumn='parentId' ++** ); ++** ++** Such an instance of the transitive_closure virtual table would be ++** appropriate for walking a tree defined using a table like this, for example: ++** ++** CREATE TABLE group( ++** groupId INTEGER PRIMARY KEY, ++** parentId INTEGER REFERENCES group ++** ); ++** CREATE INDEX group_idx1 ON group(parentId); ++** ++** The group table above would presumably have other application-specific ++** fields. The key point here is that rows of the group table form a ++** tree. The purpose of the ct1 virtual table is to easily extract ++** branches of that tree. ++** ++** Once it has been created, the ct1 virtual table can be queried ++** as follows: ++** ++** SELECT * FROM element ++** WHERE element.groupId IN (SELECT id FROM ct1 WHERE root=?1); ++** ++** The above query will return all elements that are part of group ?1 ++** or children of group ?1 or grand-children of ?1 and so forth for all ++** descendents of group ?1. The same query can be formulated as a join: ++** ++** SELECT element.* FROM element, ct1 ++** WHERE element.groupid=ct1.id ++** AND ct1.root=?1; ++** ++** The depth of the transitive_closure (the number of generations of ++** parent/child relations to follow) can be limited by setting "depth" ++** column in the WHERE clause. So, for example, the following query ++** finds only children and grandchildren but no further descendents: ++** ++** SELECT element.* FROM element, ct1 ++** WHERE element.groupid=ct1.id ++** AND ct1.root=?1 ++** AND ct1.depth<=2; ++** ++** The "ct1.depth<=2" term could be a strict equality "ct1.depth=2" in ++** order to find only the grandchildren of ?1, not ?1 itself or the ++** children of ?1. ++** ++** The root=?1 term must be supplied in WHERE clause or else the query ++** of the ct1 virtual table will return an empty set. The tablename, ++** idcolumn, and parentcolumn attributes can be overridden in the WHERE ++** clause if desired. So, for example, the ct1 table could be repurposed ++** to find ancestors rather than descendents by inverting the roles of ++** the idcolumn and parentcolumn: ++** ++** SELECT element.* FROM element, ct1 ++** WHERE element.groupid=ct1.id ++** AND ct1.root=?1 ++** AND ct1.idcolumn='parentId' ++** AND ct1.parentcolumn='groupId'; ++** ++** Multiple calls to ct1 could be combined. For example, the following ++** query finds all elements that "cousins" of groupId ?1. That is to say ++** elements where the groupId is a grandchild of the grandparent of ?1. ++** (This definition of "cousins" also includes siblings and self.) ++** ++** SELECT element.* FROM element, ct1 ++** WHERE element.groupId=ct1.id ++** AND ct1.depth=2 ++** AND ct1.root IN (SELECT id FROM ct1 ++** WHERE root=?1 ++** AND depth=2 ++** AND idcolumn='parentId' ++** AND parentcolumn='groupId'); ++** ++** In our example, the group.groupId column is unique and thus the ++** subquery will return exactly one row. For that reason, the IN ++** operator could be replaced by "=" to get the same result. But ++** in the general case where the idcolumn is not unique, an IN operator ++** would be required for this kind of query. ++** ++** Note that because the tablename, idcolumn, and parentcolumn can ++** all be specified in the query, it is possible for an application ++** to define a single transitive_closure virtual table for use on lots ++** of different hierarchy tables. One might say: ++** ++** CREATE VIRTUAL TABLE temp.closure USING transitive_closure; ++** ++** As each database connection is being opened. Then the application ++** would always have a "closure" virtual table handy to use for querying. ++** ++** SELECT element.* FROM element, closure ++** WHERE element.groupid=ct1.id ++** AND closure.root=?1 ++** AND closure.tablename='group' ++** AND closure.idname='groupId' ++** AND closure.parentname='parentId'; ++** ++** See the documentation at http://www.sqlite.org/loadext.html for information ++** on how to compile and use loadable extensions such as this one. ++*/ ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ ++/* ++** Forward declaration of objects used by this implementation ++*/ ++typedef struct closure_vtab closure_vtab; ++typedef struct closure_cursor closure_cursor; ++typedef struct closure_queue closure_queue; ++typedef struct closure_avl closure_avl; ++ ++/***************************************************************************** ++** AVL Tree implementation ++*/ ++/* ++** Objects that want to be members of the AVL tree should embedded an ++** instance of this structure. ++*/ ++struct closure_avl { ++ sqlite3_int64 id; /* Id of this entry in the table */ ++ int iGeneration; /* Which generation is this entry part of */ ++ closure_avl *pList; /* A linked list of nodes */ ++ closure_avl *pBefore; /* Other elements less than id */ ++ closure_avl *pAfter; /* Other elements greater than id */ ++ closure_avl *pUp; /* Parent element */ ++ short int height; /* Height of this node. Leaf==1 */ ++ short int imbalance; /* Height difference between pBefore and pAfter */ ++}; ++ ++/* Recompute the closure_avl.height and closure_avl.imbalance fields for p. ++** Assume that the children of p have correct heights. ++*/ ++static void closureAvlRecomputeHeight(closure_avl *p){ ++ short int hBefore = p->pBefore ? p->pBefore->height : 0; ++ short int hAfter = p->pAfter ? p->pAfter->height : 0; ++ p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */ ++ p->height = (hBefore>hAfter ? hBefore : hAfter)+1; ++} ++ ++/* ++** P B ++** / \ / \ ++** B Z ==> X P ++** / \ / \ ++** X Y Y Z ++** ++*/ ++static closure_avl *closureAvlRotateBefore(closure_avl *pP){ ++ closure_avl *pB = pP->pBefore; ++ closure_avl *pY = pB->pAfter; ++ pB->pUp = pP->pUp; ++ pB->pAfter = pP; ++ pP->pUp = pB; ++ pP->pBefore = pY; ++ if( pY ) pY->pUp = pP; ++ closureAvlRecomputeHeight(pP); ++ closureAvlRecomputeHeight(pB); ++ return pB; ++} ++ ++/* ++** P A ++** / \ / \ ++** X A ==> P Z ++** / \ / \ ++** Y Z X Y ++** ++*/ ++static closure_avl *closureAvlRotateAfter(closure_avl *pP){ ++ closure_avl *pA = pP->pAfter; ++ closure_avl *pY = pA->pBefore; ++ pA->pUp = pP->pUp; ++ pA->pBefore = pP; ++ pP->pUp = pA; ++ pP->pAfter = pY; ++ if( pY ) pY->pUp = pP; ++ closureAvlRecomputeHeight(pP); ++ closureAvlRecomputeHeight(pA); ++ return pA; ++} ++ ++/* ++** Return a pointer to the pBefore or pAfter pointer in the parent ++** of p that points to p. Or if p is the root node, return pp. ++*/ ++static closure_avl **closureAvlFromPtr(closure_avl *p, closure_avl **pp){ ++ closure_avl *pUp = p->pUp; ++ if( pUp==0 ) return pp; ++ if( pUp->pAfter==p ) return &pUp->pAfter; ++ return &pUp->pBefore; ++} ++ ++/* ++** Rebalance all nodes starting with p and working up to the root. ++** Return the new root. ++*/ ++static closure_avl *closureAvlBalance(closure_avl *p){ ++ closure_avl *pTop = p; ++ closure_avl **pp; ++ while( p ){ ++ closureAvlRecomputeHeight(p); ++ if( p->imbalance>=2 ){ ++ closure_avl *pB = p->pBefore; ++ if( pB->imbalance<0 ) p->pBefore = closureAvlRotateAfter(pB); ++ pp = closureAvlFromPtr(p,&p); ++ p = *pp = closureAvlRotateBefore(p); ++ }else if( p->imbalance<=(-2) ){ ++ closure_avl *pA = p->pAfter; ++ if( pA->imbalance>0 ) p->pAfter = closureAvlRotateBefore(pA); ++ pp = closureAvlFromPtr(p,&p); ++ p = *pp = closureAvlRotateAfter(p); ++ } ++ pTop = p; ++ p = p->pUp; ++ } ++ return pTop; ++} ++ ++/* Search the tree rooted at p for an entry with id. Return a pointer ++** to the entry or return NULL. ++*/ ++static closure_avl *closureAvlSearch(closure_avl *p, sqlite3_int64 id){ ++ while( p && id!=p->id ){ ++ p = (idid) ? p->pBefore : p->pAfter; ++ } ++ return p; ++} ++ ++/* Find the first node (the one with the smallest key). ++*/ ++static closure_avl *closureAvlFirst(closure_avl *p){ ++ if( p ) while( p->pBefore ) p = p->pBefore; ++ return p; ++} ++ ++/* Return the node with the next larger key after p. ++*/ ++closure_avl *closureAvlNext(closure_avl *p){ ++ closure_avl *pPrev = 0; ++ while( p && p->pAfter==pPrev ){ ++ pPrev = p; ++ p = p->pUp; ++ } ++ if( p && pPrev==0 ){ ++ p = closureAvlFirst(p->pAfter); ++ } ++ return p; ++} ++ ++/* Insert a new node pNew. Return NULL on success. If the key is not ++** unique, then do not perform the insert but instead leave pNew unchanged ++** and return a pointer to an existing node with the same key. ++*/ ++static closure_avl *closureAvlInsert( ++ closure_avl **ppHead, /* Head of the tree */ ++ closure_avl *pNew /* New node to be inserted */ ++){ ++ closure_avl *p = *ppHead; ++ if( p==0 ){ ++ p = pNew; ++ pNew->pUp = 0; ++ }else{ ++ while( p ){ ++ if( pNew->idid ){ ++ if( p->pBefore ){ ++ p = p->pBefore; ++ }else{ ++ p->pBefore = pNew; ++ pNew->pUp = p; ++ break; ++ } ++ }else if( pNew->id>p->id ){ ++ if( p->pAfter ){ ++ p = p->pAfter; ++ }else{ ++ p->pAfter = pNew; ++ pNew->pUp = p; ++ break; ++ } ++ }else{ ++ return p; ++ } ++ } ++ } ++ pNew->pBefore = 0; ++ pNew->pAfter = 0; ++ pNew->height = 1; ++ pNew->imbalance = 0; ++ *ppHead = closureAvlBalance(p); ++ return 0; ++} ++ ++/* Walk the tree can call xDestroy on each node ++*/ ++static void closureAvlDestroy(closure_avl *p, void (*xDestroy)(closure_avl*)){ ++ if( p ){ ++ closureAvlDestroy(p->pBefore, xDestroy); ++ closureAvlDestroy(p->pAfter, xDestroy); ++ xDestroy(p); ++ } ++} ++/* ++** End of the AVL Tree implementation ++******************************************************************************/ ++ ++/* ++** A closure virtual-table object ++*/ ++struct closure_vtab { ++ sqlite3_vtab base; /* Base class - must be first */ ++ char *zDb; /* Name of database. (ex: "main") */ ++ char *zSelf; /* Name of this virtual table */ ++ char *zTableName; /* Name of table holding parent/child relation */ ++ char *zIdColumn; /* Name of ID column of zTableName */ ++ char *zParentColumn; /* Name of PARENT column in zTableName */ ++ sqlite3 *db; /* The database connection */ ++ int nCursor; /* Number of pending cursors */ ++}; ++ ++/* A closure cursor object */ ++struct closure_cursor { ++ sqlite3_vtab_cursor base; /* Base class - must be first */ ++ closure_vtab *pVtab; /* The virtual table this cursor belongs to */ ++ char *zTableName; /* Name of table holding parent/child relation */ ++ char *zIdColumn; /* Name of ID column of zTableName */ ++ char *zParentColumn; /* Name of PARENT column in zTableName */ ++ closure_avl *pCurrent; /* Current element of output */ ++ closure_avl *pClosure; /* The complete closure tree */ ++}; ++ ++/* A queue of AVL nodes */ ++struct closure_queue { ++ closure_avl *pFirst; /* Oldest node on the queue */ ++ closure_avl *pLast; /* Youngest node on the queue */ ++}; ++ ++/* ++** Add a node to the end of the queue ++*/ ++static void queuePush(closure_queue *pQueue, closure_avl *pNode){ ++ pNode->pList = 0; ++ if( pQueue->pLast ){ ++ pQueue->pLast->pList = pNode; ++ }else{ ++ pQueue->pFirst = pNode; ++ } ++ pQueue->pLast = pNode; ++} ++ ++/* ++** Extract the oldest element (the front element) from the queue. ++*/ ++static closure_avl *queuePull(closure_queue *pQueue){ ++ closure_avl *p = pQueue->pFirst; ++ if( p ){ ++ pQueue->pFirst = p->pList; ++ if( pQueue->pFirst==0 ) pQueue->pLast = 0; ++ } ++ return p; ++} ++ ++/* ++** This function converts an SQL quoted string into an unquoted string ++** and returns a pointer to a buffer allocated using sqlite3_malloc() ++** containing the result. The caller should eventually free this buffer ++** using sqlite3_free. ++** ++** Examples: ++** ++** "abc" becomes abc ++** 'xyz' becomes xyz ++** [pqr] becomes pqr ++** `mno` becomes mno ++*/ ++static char *closureDequote(const char *zIn){ ++ int nIn; /* Size of input string, in bytes */ ++ char *zOut; /* Output (dequoted) string */ ++ ++ nIn = (int)strlen(zIn); ++ zOut = sqlite3_malloc(nIn+1); ++ if( zOut ){ ++ char q = zIn[0]; /* Quote character (if any ) */ ++ ++ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ ++ memcpy(zOut, zIn, nIn+1); ++ }else{ ++ int iOut = 0; /* Index of next byte to write to output */ ++ int iIn; /* Index of next byte to read from input */ ++ ++ if( q=='[' ) q = ']'; ++ for(iIn=1; iInzDb); ++ sqlite3_free(p->zSelf); ++ sqlite3_free(p->zTableName); ++ sqlite3_free(p->zIdColumn); ++ sqlite3_free(p->zParentColumn); ++ memset(p, 0, sizeof(*p)); ++ sqlite3_free(p); ++ } ++} ++ ++/* ++** xDisconnect/xDestroy method for the closure module. ++*/ ++static int closureDisconnect(sqlite3_vtab *pVtab){ ++ closure_vtab *p = (closure_vtab*)pVtab; ++ assert( p->nCursor==0 ); ++ closureFree(p); ++ return SQLITE_OK; ++} ++ ++/* ++** Check to see if the argument is of the form: ++** ++** KEY = VALUE ++** ++** If it is, return a pointer to the first character of VALUE. ++** If not, return NULL. Spaces around the = are ignored. ++*/ ++static const char *closureValueOfKey(const char *zKey, const char *zStr){ ++ int nKey = (int)strlen(zKey); ++ int nStr = (int)strlen(zStr); ++ int i; ++ if( nStr module name ("transitive_closure") ++** argv[1] -> database name ++** argv[2] -> table name ++** argv[3...] -> arguments ++*/ ++static int closureConnect( ++ sqlite3 *db, ++ void *pAux, ++ int argc, const char *const*argv, ++ sqlite3_vtab **ppVtab, ++ char **pzErr ++){ ++ int rc = SQLITE_OK; /* Return code */ ++ closure_vtab *pNew = 0; /* New virtual table */ ++ const char *zDb = argv[1]; ++ const char *zVal; ++ int i; ++ ++ (void)pAux; ++ *ppVtab = 0; ++ pNew = sqlite3_malloc( sizeof(*pNew) ); ++ if( pNew==0 ) return SQLITE_NOMEM; ++ rc = SQLITE_NOMEM; ++ memset(pNew, 0, sizeof(*pNew)); ++ pNew->db = db; ++ pNew->zDb = sqlite3_mprintf("%s", zDb); ++ if( pNew->zDb==0 ) goto closureConnectError; ++ pNew->zSelf = sqlite3_mprintf("%s", argv[2]); ++ if( pNew->zSelf==0 ) goto closureConnectError; ++ for(i=3; izTableName); ++ pNew->zTableName = closureDequote(zVal); ++ if( pNew->zTableName==0 ) goto closureConnectError; ++ continue; ++ } ++ zVal = closureValueOfKey("idcolumn", argv[i]); ++ if( zVal ){ ++ sqlite3_free(pNew->zIdColumn); ++ pNew->zIdColumn = closureDequote(zVal); ++ if( pNew->zIdColumn==0 ) goto closureConnectError; ++ continue; ++ } ++ zVal = closureValueOfKey("parentcolumn", argv[i]); ++ if( zVal ){ ++ sqlite3_free(pNew->zParentColumn); ++ pNew->zParentColumn = closureDequote(zVal); ++ if( pNew->zParentColumn==0 ) goto closureConnectError; ++ continue; ++ } ++ *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]); ++ closureFree(pNew); ++ *ppVtab = 0; ++ return SQLITE_ERROR; ++ } ++ rc = sqlite3_declare_vtab(db, ++ "CREATE TABLE x(id,depth,root HIDDEN,tablename HIDDEN," ++ "idcolumn HIDDEN,parentcolumn HIDDEN)" ++ ); ++#define CLOSURE_COL_ID 0 ++#define CLOSURE_COL_DEPTH 1 ++#define CLOSURE_COL_ROOT 2 ++#define CLOSURE_COL_TABLENAME 3 ++#define CLOSURE_COL_IDCOLUMN 4 ++#define CLOSURE_COL_PARENTCOLUMN 5 ++ if( rc!=SQLITE_OK ){ ++ closureFree(pNew); ++ } ++ *ppVtab = &pNew->base; ++ return rc; ++ ++closureConnectError: ++ closureFree(pNew); ++ return rc; ++} ++ ++/* ++** Open a new closure cursor. ++*/ ++static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ ++ closure_vtab *p = (closure_vtab*)pVTab; ++ closure_cursor *pCur; ++ pCur = sqlite3_malloc( sizeof(*pCur) ); ++ if( pCur==0 ) return SQLITE_NOMEM; ++ memset(pCur, 0, sizeof(*pCur)); ++ pCur->pVtab = p; ++ *ppCursor = &pCur->base; ++ p->nCursor++; ++ return SQLITE_OK; ++} ++ ++/* ++** Free up all the memory allocated by a cursor. Set it rLimit to 0 ++** to indicate that it is at EOF. ++*/ ++static void closureClearCursor(closure_cursor *pCur){ ++ closureAvlDestroy(pCur->pClosure, (void(*)(closure_avl*))sqlite3_free); ++ sqlite3_free(pCur->zTableName); ++ sqlite3_free(pCur->zIdColumn); ++ sqlite3_free(pCur->zParentColumn); ++ pCur->zTableName = 0; ++ pCur->zIdColumn = 0; ++ pCur->zParentColumn = 0; ++ pCur->pCurrent = 0; ++ pCur->pClosure = 0; ++} ++ ++/* ++** Close a closure cursor. ++*/ ++static int closureClose(sqlite3_vtab_cursor *cur){ ++ closure_cursor *pCur = (closure_cursor *)cur; ++ closureClearCursor(pCur); ++ pCur->pVtab->nCursor--; ++ sqlite3_free(pCur); ++ return SQLITE_OK; ++} ++ ++/* ++** Advance a cursor to its next row of output ++*/ ++static int closureNext(sqlite3_vtab_cursor *cur){ ++ closure_cursor *pCur = (closure_cursor*)cur; ++ pCur->pCurrent = closureAvlNext(pCur->pCurrent); ++ return SQLITE_OK; ++} ++ ++/* ++** Allocate and insert a node ++*/ ++static int closureInsertNode( ++ closure_queue *pQueue, /* Add new node to this queue */ ++ closure_cursor *pCur, /* The cursor into which to add the node */ ++ sqlite3_int64 id, /* The node ID */ ++ int iGeneration /* The generation number for this node */ ++){ ++ closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) ); ++ if( pNew==0 ) return SQLITE_NOMEM; ++ memset(pNew, 0, sizeof(*pNew)); ++ pNew->id = id; ++ pNew->iGeneration = iGeneration; ++ closureAvlInsert(&pCur->pClosure, pNew); ++ queuePush(pQueue, pNew); ++ return SQLITE_OK; ++} ++ ++/* ++** Called to "rewind" a cursor back to the beginning so that ++** it starts its output over again. Always called at least once ++** prior to any closureColumn, closureRowid, or closureEof call. ++** ++** This routine actually computes the closure. ++** ++** See the comment at the beginning of closureBestIndex() for a ++** description of the meaning of idxNum. The idxStr parameter is ++** not used. ++*/ ++static int closureFilter( ++ sqlite3_vtab_cursor *pVtabCursor, ++ int idxNum, const char *idxStr, ++ int argc, sqlite3_value **argv ++){ ++ closure_cursor *pCur = (closure_cursor *)pVtabCursor; ++ closure_vtab *pVtab = pCur->pVtab; ++ sqlite3_int64 iRoot; ++ int mxGen = 999999999; ++ char *zSql; ++ sqlite3_stmt *pStmt; ++ closure_avl *pAvl; ++ int rc = SQLITE_OK; ++ const char *zTableName = pVtab->zTableName; ++ const char *zIdColumn = pVtab->zIdColumn; ++ const char *zParentColumn = pVtab->zParentColumn; ++ closure_queue sQueue; ++ ++ (void)idxStr; /* Unused parameter */ ++ (void)argc; /* Unused parameter */ ++ closureClearCursor(pCur); ++ memset(&sQueue, 0, sizeof(sQueue)); ++ if( (idxNum & 1)==0 ){ ++ /* No root=$root in the WHERE clause. Return an empty set */ ++ return SQLITE_OK; ++ } ++ iRoot = sqlite3_value_int64(argv[0]); ++ if( (idxNum & 0x000f0)!=0 ){ ++ mxGen = sqlite3_value_int(argv[(idxNum>>4)&0x0f]); ++ if( (idxNum & 0x00002)!=0 ) mxGen--; ++ } ++ if( (idxNum & 0x00f00)!=0 ){ ++ zTableName = (const char*)sqlite3_value_text(argv[(idxNum>>8)&0x0f]); ++ pCur->zTableName = sqlite3_mprintf("%s", zTableName); ++ } ++ if( (idxNum & 0x0f000)!=0 ){ ++ zIdColumn = (const char*)sqlite3_value_text(argv[(idxNum>>12)&0x0f]); ++ pCur->zIdColumn = sqlite3_mprintf("%s", zIdColumn); ++ } ++ if( (idxNum & 0x0f0000)!=0 ){ ++ zParentColumn = (const char*)sqlite3_value_text(argv[(idxNum>>16)&0x0f]); ++ pCur->zParentColumn = sqlite3_mprintf("%s", zParentColumn); ++ } ++ ++ zSql = sqlite3_mprintf( ++ "SELECT \"%w\".\"%w\" FROM \"%w\" WHERE \"%w\".\"%w\"=?1", ++ zTableName, zIdColumn, zTableName, zTableName, zParentColumn); ++ if( zSql==0 ){ ++ return SQLITE_NOMEM; ++ }else{ ++ rc = sqlite3_prepare_v2(pVtab->db, zSql, -1, &pStmt, 0); ++ sqlite3_free(zSql); ++ if( rc ){ ++ sqlite3_free(pVtab->base.zErrMsg); ++ pVtab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pVtab->db)); ++ return rc; ++ } ++ } ++ if( rc==SQLITE_OK ){ ++ rc = closureInsertNode(&sQueue, pCur, iRoot, 0); ++ } ++ while( (pAvl = queuePull(&sQueue))!=0 ){ ++ if( pAvl->iGeneration>=mxGen ) continue; ++ sqlite3_bind_int64(pStmt, 1, pAvl->id); ++ while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ ++ if( sqlite3_column_type(pStmt,0)==SQLITE_INTEGER ){ ++ sqlite3_int64 iNew = sqlite3_column_int64(pStmt, 0); ++ if( closureAvlSearch(pCur->pClosure, iNew)==0 ){ ++ rc = closureInsertNode(&sQueue, pCur, iNew, pAvl->iGeneration+1); ++ } ++ } ++ } ++ sqlite3_reset(pStmt); ++ } ++ sqlite3_finalize(pStmt); ++ if( rc==SQLITE_OK ){ ++ pCur->pCurrent = closureAvlFirst(pCur->pClosure); ++ } ++ ++ return rc; ++} ++ ++/* ++** Only the word and distance columns have values. All other columns ++** return NULL ++*/ ++static int closureColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ ++ closure_cursor *pCur = (closure_cursor*)cur; ++ switch( i ){ ++ case CLOSURE_COL_ID: { ++ sqlite3_result_int64(ctx, pCur->pCurrent->id); ++ break; ++ } ++ case CLOSURE_COL_DEPTH: { ++ sqlite3_result_int(ctx, pCur->pCurrent->iGeneration); ++ break; ++ } ++ case CLOSURE_COL_ROOT: { ++ sqlite3_result_null(ctx); ++ break; ++ } ++ case CLOSURE_COL_TABLENAME: { ++ sqlite3_result_text(ctx, ++ pCur->zTableName ? pCur->zTableName : pCur->pVtab->zTableName, ++ -1, SQLITE_TRANSIENT); ++ break; ++ } ++ case CLOSURE_COL_IDCOLUMN: { ++ sqlite3_result_text(ctx, ++ pCur->zIdColumn ? pCur->zIdColumn : pCur->pVtab->zIdColumn, ++ -1, SQLITE_TRANSIENT); ++ break; ++ } ++ case CLOSURE_COL_PARENTCOLUMN: { ++ sqlite3_result_text(ctx, ++ pCur->zParentColumn ? pCur->zParentColumn : pCur->pVtab->zParentColumn, ++ -1, SQLITE_TRANSIENT); ++ break; ++ } ++ } ++ return SQLITE_OK; ++} ++ ++/* ++** The rowid. For the closure table, this is the same as the "id" column. ++*/ ++static int closureRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ++ closure_cursor *pCur = (closure_cursor*)cur; ++ *pRowid = pCur->pCurrent->id; ++ return SQLITE_OK; ++} ++ ++/* ++** EOF indicator ++*/ ++static int closureEof(sqlite3_vtab_cursor *cur){ ++ closure_cursor *pCur = (closure_cursor*)cur; ++ return pCur->pCurrent==0; ++} ++ ++/* ++** Search for terms of these forms: ++** ++** (A) root = $root ++** (B1) depth < $depth ++** (B2) depth <= $depth ++** (B3) depth = $depth ++** (C) tablename = $tablename ++** (D) idcolumn = $idcolumn ++** (E) parentcolumn = $parentcolumn ++** ++** ++** ++** idxNum meaning ++** ---------- ------------------------------------------------------ ++** 0x00000001 Term of the form (A) found ++** 0x00000002 The term of bit-2 is like (B1) ++** 0x000000f0 Index in filter.argv[] of $depth. 0 if not used. ++** 0x00000f00 Index in filter.argv[] of $tablename. 0 if not used. ++** 0x0000f000 Index in filter.argv[] of $idcolumn. 0 if not used ++** 0x000f0000 Index in filter.argv[] of $parentcolumn. 0 if not used. ++** ++** There must be a term of type (A). If there is not, then the index type ++** is 0 and the query will return an empty set. ++*/ ++static int closureBestIndex( ++ sqlite3_vtab *pTab, /* The virtual table */ ++ sqlite3_index_info *pIdxInfo /* Information about the query */ ++){ ++ int iPlan = 0; ++ int i; ++ int idx = 1; ++ int seenMatch = 0; ++ const struct sqlite3_index_constraint *pConstraint; ++ closure_vtab *pVtab = (closure_vtab*)pTab; ++ double rCost = 10000000.0; ++ ++ pConstraint = pIdxInfo->aConstraint; ++ for(i=0; inConstraint; i++, pConstraint++){ ++ if( pConstraint->iColumn==CLOSURE_COL_ROOT ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ ++ seenMatch = 1; ++ } ++ if( pConstraint->usable==0 ) continue; ++ if( (iPlan & 1)==0 ++ && pConstraint->iColumn==CLOSURE_COL_ROOT ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ++ ){ ++ iPlan |= 1; ++ pIdxInfo->aConstraintUsage[i].argvIndex = 1; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ rCost /= 100.0; ++ } ++ if( (iPlan & 0x0000f0)==0 ++ && pConstraint->iColumn==CLOSURE_COL_DEPTH ++ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ++ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ++ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ) ++ ){ ++ iPlan |= idx<<4; ++ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; ++ if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ) iPlan |= 0x000002; ++ rCost /= 5.0; ++ } ++ if( (iPlan & 0x000f00)==0 ++ && pConstraint->iColumn==CLOSURE_COL_TABLENAME ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ++ ){ ++ iPlan |= idx<<8; ++ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ rCost /= 5.0; ++ } ++ if( (iPlan & 0x00f000)==0 ++ && pConstraint->iColumn==CLOSURE_COL_IDCOLUMN ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ++ ){ ++ iPlan |= idx<<12; ++ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ } ++ if( (iPlan & 0x0f0000)==0 ++ && pConstraint->iColumn==CLOSURE_COL_PARENTCOLUMN ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ++ ){ ++ iPlan |= idx<<16; ++ pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ } ++ } ++ if( (pVtab->zTableName==0 && (iPlan & 0x000f00)==0) ++ || (pVtab->zIdColumn==0 && (iPlan & 0x00f000)==0) ++ || (pVtab->zParentColumn==0 && (iPlan & 0x0f0000)==0) ++ ){ ++ /* All of tablename, idcolumn, and parentcolumn must be specified ++ ** in either the CREATE VIRTUAL TABLE or in the WHERE clause constraints ++ ** or else the result is an empty set. */ ++ iPlan = 0; ++ } ++ pIdxInfo->idxNum = iPlan; ++ if( pIdxInfo->nOrderBy==1 ++ && pIdxInfo->aOrderBy[0].iColumn==CLOSURE_COL_ID ++ && pIdxInfo->aOrderBy[0].desc==0 ++ ){ ++ pIdxInfo->orderByConsumed = 1; ++ } ++ if( seenMatch && (iPlan&1)==0 ) rCost *= 1e30; ++ pIdxInfo->estimatedCost = rCost; ++ ++ return SQLITE_OK; ++} ++ ++/* ++** A virtual table module that implements the "transitive_closure". ++*/ ++static const sqlite3_module closureModule = { ++ 0, /* iVersion */ ++ closureConnect, /* xCreate */ ++ closureConnect, /* xConnect */ ++ closureBestIndex, /* xBestIndex */ ++ closureDisconnect, /* xDisconnect */ ++ closureDisconnect, /* xDestroy */ ++ closureOpen, /* xOpen - open a cursor */ ++ closureClose, /* xClose - close a cursor */ ++ closureFilter, /* xFilter - configure scan constraints */ ++ closureNext, /* xNext - advance a cursor */ ++ closureEof, /* xEof - check for end of scan */ ++ closureColumn, /* xColumn - read data */ ++ closureRowid, /* xRowid - read data */ ++ 0, /* xUpdate */ ++ 0, /* xBegin */ ++ 0, /* xSync */ ++ 0, /* xCommit */ ++ 0, /* xRollback */ ++ 0, /* xFindMethod */ ++ 0, /* xRename */ ++ 0, /* xSavepoint */ ++ 0, /* xRelease */ ++ 0 /* xRollbackTo */ ++}; ++ ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ ++/* ++** Register the closure virtual table ++*/ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_closure_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0); ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0); ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/compress.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/compress.c 2016-01-06 16:30:42.475119800 +0100 +@@ -0,0 +1,178 @@ ++/* ++** 2014-06-13 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++****************************************************************************** ++** ++** This SQLite extension implements SQL compression functions ++** compress() and uncompress() using ZLIB. ++*/ ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++#include ++ ++/* ++** Implementation of the "compress(X)" SQL function. The input X is ++** compressed using zLib and the output is returned. ++** ++** The output is a BLOB that begins with an integer that forming the ++** input size in bytes (the size of X before compression). The variable- ++** length integer is implemented as 1 to 5 bytes. If the first byte is 0, ++** 4 bytes are used, the most significant bits first. Otherwise there are ++** seven bits per integer stored in the lower seven bits of each byte. ++** More significant bits occur first. The most significant bit (0x80) ++** is a flag to indicate the end of the integer. ++*/ ++static void compressFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const unsigned char *pIn; ++ unsigned char *pOut; ++ size_t nIn; ++ unsigned long int nOut; ++ int j, rc; ++ ++ pIn = sqlite3_value_blob(argv[0]); ++ nIn = sqlite3_value_bytes(argv[0]); ++ nOut = 13 + nIn + (nIn+999)/1000; ++ pOut = sqlite3_malloc( nOut+5 ); ++ if( (nIn<=0xffffff) || (!(nIn&0x80)&&!(nIn&0x8000)&&!(nIn&0x800000))) { ++ pOut[0] = nIn>>24 & 0xff; ++ pOut[1] = nIn>>16 & 0xff; ++ pOut[2] = nIn>>8 & 0xff; ++ pOut[3] = nIn & 0xff; ++ j = 4; ++ }else{ ++ int i; ++ unsigned char x[8]; ++ for(i=4; i>=0; i--){ ++ x[i] = (nIn >> (7*(4-i)))&0x7f; ++ } ++ for(i=0; i<4 && x[i]==0; i++){} ++ for(j=0; i<=4; i++, j++) pOut[j] = x[i]; ++ pOut[j-1] |= 0x80; ++ } ++ rc = compress(&pOut[j], &nOut, pIn, nIn); ++ if( rc==Z_OK ){ ++ sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free); ++ }else{ ++ sqlite3_free(pOut); ++ sqlite3_result_error(context, "input cannot be zlib compressed", -1); ++ } ++} ++ ++/* ++** Implementation of the "uncompress(X)" SQL function. The argument X ++** is a blob which was obtained from compress(Y). The output will be ++** the value Y. ++*/ ++static void uncompressFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const unsigned char *pIn; ++ unsigned char *pOut; ++ unsigned int nIn; ++ unsigned long nOut; ++ int rc; ++ ++ pIn = sqlite3_value_blob(argv[0]); ++ nIn = sqlite3_value_bytes(argv[0]); ++ nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3]; ++ if( pIn[0] ){ ++ unsigned long nOut2 = 0; ++ int i; ++ ++ /* ++ ** If the high-byte of the blob length > 0, there are actually ++ ** two possibilities: ++ ** 1) The blob is > 16MByte, possible but unlikely as most blobs ++ ** are not that big. ++ ** 2) The content was compressed with SQLite's ext/misc/compress.c ++ ** ++ ** Just try both possibilities (smallest first), if the decompression ++ ** fails (either by Z_BUF_ERROR or Z_DATA_ERROR) we will find out quick ++ ** enough which one was correct. ++ */ ++ for(i=0; i ++ ++/* ++** Structure used to accumulate the output ++*/ ++struct EvalResult { ++ char *z; /* Accumulated output */ ++ const char *zSep; /* Separator */ ++ int szSep; /* Size of the separator string */ ++ sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */ ++ sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */ ++}; ++ ++/* ++** Callback from sqlite_exec() for the eval() function. ++*/ ++static int callback(void *pCtx, int argc, char **argv, char **colnames){ ++ struct EvalResult *p = (struct EvalResult*)pCtx; ++ int i; ++ for(i=0; inUsed+p->szSep+1 > p->nAlloc ){ ++ char *zNew; ++ p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; ++ /* Using sqlite3_realloc64() would be better, but it is a recent ++ ** addition and will cause a segfault if loaded by an older version ++ ** of SQLite. */ ++ zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; ++ if( zNew==0 ){ ++ sqlite3_free(p->z); ++ memset(p, 0, sizeof(*p)); ++ return 1; ++ } ++ p->z = zNew; ++ } ++ if( p->nUsed>0 ){ ++ memcpy(&p->z[p->nUsed], p->zSep, p->szSep); ++ p->nUsed += p->szSep; ++ } ++ memcpy(&p->z[p->nUsed], z, sz); ++ p->nUsed += sz; ++ } ++ return 0; ++} ++ ++/* ++** Implementation of the eval(X) and eval(X,Y) SQL functions. ++** ++** Evaluate the SQL text in X. Return the results, using string ++** Y as the separator. If Y is omitted, use a single space character. ++*/ ++static void sqlEvalFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const char *zSql; ++ sqlite3 *db; ++ char *zErr = 0; ++ int rc; ++ struct EvalResult x; ++ ++ memset(&x, 0, sizeof(x)); ++ x.zSep = " "; ++ zSql = (const char*)sqlite3_value_text(argv[0]); ++ if( zSql==0 ) return; ++ if( argc>1 ){ ++ x.zSep = (const char*)sqlite3_value_text(argv[1]); ++ if( x.zSep==0 ) return; ++ } ++ x.szSep = (int)strlen(x.zSep); ++ db = sqlite3_context_db_handle(context); ++ rc = sqlite3_exec(db, zSql, callback, &x, &zErr); ++ if( rc!=SQLITE_OK ){ ++ sqlite3_result_error(context, zErr, -1); ++ sqlite3_free(zErr); ++ }else if( x.zSep==0 ){ ++ sqlite3_result_error_nomem(context); ++ sqlite3_free(x.z); ++ }else{ ++ sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); ++ } ++} ++ ++ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_eval_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, ++ sqlEvalFunc, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, ++ sqlEvalFunc, 0, 0); ++ } ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, ++ sqlEvalFunc, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, ++ sqlEvalFunc, 0, 0); ++ } ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/fileio.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/fileio.c 2016-01-06 16:30:42.501121300 +0100 +@@ -0,0 +1,118 @@ ++/* ++** 2014-06-13 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++****************************************************************************** ++** ++** This SQLite extension implements SQL functions readfile() and ++** writefile(). ++*/ ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++#include ++ ++/* ++** Implementation of the "readfile(X)" SQL function. The entire content ++** of the file named X is read and returned as a BLOB. NULL is returned ++** if the file does not exist or is unreadable. ++*/ ++static void readfileFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const char *zName; ++ FILE *in; ++ long nIn; ++ void *pBuf; ++ ++ zName = (const char*)sqlite3_value_text(argv[0]); ++ if( zName==0 ) return; ++ in = fopen(zName, "rb"); ++ if( in==0 ) return; ++ fseek(in, 0, SEEK_END); ++ nIn = ftell(in); ++ rewind(in); ++ pBuf = sqlite3_malloc( nIn ); ++ if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ ++ sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); ++ }else{ ++ sqlite3_free(pBuf); ++ } ++ fclose(in); ++} ++ ++/* ++** Implementation of the "writefile(X,Y)" SQL function. The argument Y ++** is written into file X. The number of bytes written is returned. Or ++** NULL is returned if something goes wrong, such as being unable to open ++** file X for writing. ++*/ ++static void writefileFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ FILE *out; ++ const char *z; ++ sqlite3_int64 rc; ++ const char *zFile; ++ ++ zFile = (const char*)sqlite3_value_text(argv[0]); ++ if( zFile==0 ) return; ++ out = fopen(zFile, "wb"); ++ if( out==0 ) return; ++ z = (const char*)sqlite3_value_blob(argv[1]); ++ if( z==0 ){ ++ rc = 0; ++ }else{ ++ rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out); ++ } ++ fclose(out); ++ sqlite3_result_int64(context, rc); ++} ++ ++ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_fileio_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, ++ readfileFunc, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0, ++ writefileFunc, 0, 0); ++ } ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, ++ readfileFunc, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0, ++ writefileFunc, 0, 0); ++ } ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/fuzzer.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/fuzzer.c 2016-01-06 16:30:42.503121400 +0100 +@@ -0,0 +1,1199 @@ ++/* ++** 2011 March 24 ++** ++** 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. ++** ++************************************************************************* ++** ++** Code for a demonstration virtual table that generates variations ++** on an input word at increasing edit distances from the original. ++** ++** A fuzzer virtual table is created like this: ++** ++** CREATE VIRTUAL TABLE f USING fuzzer(); ++** ++** When it is created, the new fuzzer table must be supplied with the ++** name of a "fuzzer data table", which must reside in the same database ++** file as the new fuzzer table. The fuzzer data table contains the various ++** transformations and their costs that the fuzzer logic uses to generate ++** variations. ++** ++** The fuzzer data table must contain exactly four columns (more precisely, ++** the statement "SELECT * FROM " must return records ++** that consist of four columns). It does not matter what the columns are ++** named. ++** ++** Each row in the fuzzer data table represents a single character ++** transformation. The left most column of the row (column 0) contains an ++** integer value - the identifier of the ruleset to which the transformation ++** rule belongs (see "MULTIPLE RULE SETS" below). The second column of the ++** row (column 0) contains the input character or characters. The third ++** column contains the output character or characters. And the fourth column ++** contains the integer cost of making the transformation. For example: ++** ++** CREATE TABLE f_data(ruleset, cFrom, cTo, Cost); ++** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, '', 'a', 100); ++** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'b', '', 87); ++** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'o', 'oe', 38); ++** INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'oe', 'o', 40); ++** ++** The first row inserted into the fuzzer data table by the SQL script ++** above indicates that the cost of inserting a letter 'a' is 100. (All ++** costs are integers. We recommend that costs be scaled so that the ++** average cost is around 100.) The second INSERT statement creates a rule ++** saying that the cost of deleting a single letter 'b' is 87. The third ++** and fourth INSERT statements mean that the cost of transforming a ++** single letter "o" into the two-letter sequence "oe" is 38 and that the ++** cost of transforming "oe" back into "o" is 40. ++** ++** The contents of the fuzzer data table are loaded into main memory when ++** a fuzzer table is first created, and may be internally reloaded by the ++** system at any subsequent time. Therefore, the fuzzer data table should be ++** populated before the fuzzer table is created and not modified thereafter. ++** If you do need to modify the contents of the fuzzer data table, it is ++** recommended that the associated fuzzer table be dropped, the fuzzer data ++** table edited, and the fuzzer table recreated within a single transaction. ++** Alternatively, the fuzzer data table can be edited then the database ++** connection can be closed and reopened. ++** ++** Once it has been created, the fuzzer table can be queried as follows: ++** ++** SELECT word, distance FROM f ++** WHERE word MATCH 'abcdefg' ++** AND distance<200; ++** ++** This first query outputs the string "abcdefg" and all strings that ++** can be derived from that string by appling the specified transformations. ++** The strings are output together with their total transformation cost ++** (called "distance") and appear in order of increasing cost. No string ++** is output more than once. If there are multiple ways to transform the ++** target string into the output string then the lowest cost transform is ++** the one that is returned. In the example, the search is limited to ++** strings with a total distance of less than 200. ++** ++** The fuzzer is a read-only table. Any attempt to DELETE, INSERT, or ++** UPDATE on a fuzzer table will throw an error. ++** ++** It is important to put some kind of a limit on the fuzzer output. This ++** can be either in the form of a LIMIT clause at the end of the query, ++** or better, a "distance ++#include ++#include ++#include ++ ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ ++/* ++** Forward declaration of objects used by this implementation ++*/ ++typedef struct fuzzer_vtab fuzzer_vtab; ++typedef struct fuzzer_cursor fuzzer_cursor; ++typedef struct fuzzer_rule fuzzer_rule; ++typedef struct fuzzer_seen fuzzer_seen; ++typedef struct fuzzer_stem fuzzer_stem; ++ ++/* ++** Various types. ++** ++** fuzzer_cost is the "cost" of an edit operation. ++** ++** fuzzer_len is the length of a matching string. ++** ++** fuzzer_ruleid is an ruleset identifier. ++*/ ++typedef int fuzzer_cost; ++typedef signed char fuzzer_len; ++typedef int fuzzer_ruleid; ++ ++/* ++** Limits ++*/ ++#define FUZZER_MX_LENGTH 50 /* Maximum length of a rule string */ ++#define FUZZER_MX_RULEID 2147483647 /* Maximum rule ID */ ++#define FUZZER_MX_COST 1000 /* Maximum single-rule cost */ ++#define FUZZER_MX_OUTPUT_LENGTH 100 /* Maximum length of an output string */ ++ ++ ++/* ++** Each transformation rule is stored as an instance of this object. ++** All rules are kept on a linked list sorted by rCost. ++*/ ++struct fuzzer_rule { ++ fuzzer_rule *pNext; /* Next rule in order of increasing rCost */ ++ char *zFrom; /* Transform from */ ++ fuzzer_cost rCost; /* Cost of this transformation */ ++ fuzzer_len nFrom, nTo; /* Length of the zFrom and zTo strings */ ++ fuzzer_ruleid iRuleset; /* The rule set to which this rule belongs */ ++ char zTo[4]; /* Transform to (extra space appended) */ ++}; ++ ++/* ++** A stem object is used to generate variants. It is also used to record ++** previously generated outputs. ++** ++** Every stem is added to a hash table as it is output. Generation of ++** duplicate stems is suppressed. ++** ++** Active stems (those that might generate new outputs) are kepts on a linked ++** list sorted by increasing cost. The cost is the sum of rBaseCost and ++** pRule->rCost. ++*/ ++struct fuzzer_stem { ++ char *zBasis; /* Word being fuzzed */ ++ const fuzzer_rule *pRule; /* Current rule to apply */ ++ fuzzer_stem *pNext; /* Next stem in rCost order */ ++ fuzzer_stem *pHash; /* Next stem with same hash on zBasis */ ++ fuzzer_cost rBaseCost; /* Base cost of getting to zBasis */ ++ fuzzer_cost rCostX; /* Precomputed rBaseCost + pRule->rCost */ ++ fuzzer_len nBasis; /* Length of the zBasis string */ ++ fuzzer_len n; /* Apply pRule at this character offset */ ++}; ++ ++/* ++** A fuzzer virtual-table object ++*/ ++struct fuzzer_vtab { ++ sqlite3_vtab base; /* Base class - must be first */ ++ char *zClassName; /* Name of this class. Default: "fuzzer" */ ++ fuzzer_rule *pRule; /* All active rules in this fuzzer */ ++ int nCursor; /* Number of active cursors */ ++}; ++ ++#define FUZZER_HASH 4001 /* Hash table size */ ++#define FUZZER_NQUEUE 20 /* Number of slots on the stem queue */ ++ ++/* A fuzzer cursor object */ ++struct fuzzer_cursor { ++ sqlite3_vtab_cursor base; /* Base class - must be first */ ++ sqlite3_int64 iRowid; /* The rowid of the current word */ ++ fuzzer_vtab *pVtab; /* The virtual table this cursor belongs to */ ++ fuzzer_cost rLimit; /* Maximum cost of any term */ ++ fuzzer_stem *pStem; /* Stem with smallest rCostX */ ++ fuzzer_stem *pDone; /* Stems already processed to completion */ ++ fuzzer_stem *aQueue[FUZZER_NQUEUE]; /* Queue of stems with higher rCostX */ ++ int mxQueue; /* Largest used index in aQueue[] */ ++ char *zBuf; /* Temporary use buffer */ ++ int nBuf; /* Bytes allocated for zBuf */ ++ int nStem; /* Number of stems allocated */ ++ int iRuleset; /* Only process rules from this ruleset */ ++ fuzzer_rule nullRule; /* Null rule used first */ ++ fuzzer_stem *apHash[FUZZER_HASH]; /* Hash of previously generated terms */ ++}; ++ ++/* ++** The two input rule lists are both sorted in order of increasing ++** cost. Merge them together into a single list, sorted by cost, and ++** return a pointer to the head of that list. ++*/ ++static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){ ++ fuzzer_rule head; ++ fuzzer_rule *pTail; ++ ++ pTail = &head; ++ while( pA && pB ){ ++ if( pA->rCost<=pB->rCost ){ ++ pTail->pNext = pA; ++ pTail = pA; ++ pA = pA->pNext; ++ }else{ ++ pTail->pNext = pB; ++ pTail = pB; ++ pB = pB->pNext; ++ } ++ } ++ if( pA==0 ){ ++ pTail->pNext = pB; ++ }else{ ++ pTail->pNext = pA; ++ } ++ return head.pNext; ++} ++ ++/* ++** Statement pStmt currently points to a row in the fuzzer data table. This ++** function allocates and populates a fuzzer_rule structure according to ++** the content of the row. ++** ++** If successful, *ppRule is set to point to the new object and SQLITE_OK ++** is returned. Otherwise, *ppRule is zeroed, *pzErr may be set to point ++** to an error message and an SQLite error code returned. ++*/ ++static int fuzzerLoadOneRule( ++ fuzzer_vtab *p, /* Fuzzer virtual table handle */ ++ sqlite3_stmt *pStmt, /* Base rule on statements current row */ ++ fuzzer_rule **ppRule, /* OUT: New rule object */ ++ char **pzErr /* OUT: Error message */ ++){ ++ sqlite3_int64 iRuleset = sqlite3_column_int64(pStmt, 0); ++ const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1); ++ const char *zTo = (const char *)sqlite3_column_text(pStmt, 2); ++ int nCost = sqlite3_column_int(pStmt, 3); ++ ++ int rc = SQLITE_OK; /* Return code */ ++ int nFrom; /* Size of string zFrom, in bytes */ ++ int nTo; /* Size of string zTo, in bytes */ ++ fuzzer_rule *pRule = 0; /* New rule object to return */ ++ ++ if( zFrom==0 ) zFrom = ""; ++ if( zTo==0 ) zTo = ""; ++ nFrom = (int)strlen(zFrom); ++ nTo = (int)strlen(zTo); ++ ++ /* Silently ignore null transformations */ ++ if( strcmp(zFrom, zTo)==0 ){ ++ *ppRule = 0; ++ return SQLITE_OK; ++ } ++ ++ if( nCost<=0 || nCost>FUZZER_MX_COST ){ ++ *pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d", ++ p->zClassName, FUZZER_MX_COST ++ ); ++ rc = SQLITE_ERROR; ++ }else ++ if( nFrom>FUZZER_MX_LENGTH || nTo>FUZZER_MX_LENGTH ){ ++ *pzErr = sqlite3_mprintf("%s: maximum string length is %d", ++ p->zClassName, FUZZER_MX_LENGTH ++ ); ++ rc = SQLITE_ERROR; ++ }else ++ if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){ ++ *pzErr = sqlite3_mprintf("%s: ruleset must be between 0 and %d", ++ p->zClassName, FUZZER_MX_RULEID ++ ); ++ rc = SQLITE_ERROR; ++ }else{ ++ ++ pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo ); ++ if( pRule==0 ){ ++ rc = SQLITE_NOMEM; ++ }else{ ++ memset(pRule, 0, sizeof(*pRule)); ++ pRule->zFrom = pRule->zTo; ++ pRule->zFrom += nTo + 1; ++ pRule->nFrom = nFrom; ++ memcpy(pRule->zFrom, zFrom, nFrom+1); ++ memcpy(pRule->zTo, zTo, nTo+1); ++ pRule->nTo = nTo; ++ pRule->rCost = nCost; ++ pRule->iRuleset = (int)iRuleset; ++ } ++ } ++ ++ *ppRule = pRule; ++ return rc; ++} ++ ++/* ++** Load the content of the fuzzer data table into memory. ++*/ ++static int fuzzerLoadRules( ++ sqlite3 *db, /* Database handle */ ++ fuzzer_vtab *p, /* Virtual fuzzer table to configure */ ++ const char *zDb, /* Database containing rules data */ ++ const char *zData, /* Table containing rules data */ ++ char **pzErr /* OUT: Error message */ ++){ ++ int rc = SQLITE_OK; /* Return code */ ++ char *zSql; /* SELECT used to read from rules table */ ++ fuzzer_rule *pHead = 0; ++ ++ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zData); ++ if( zSql==0 ){ ++ rc = SQLITE_NOMEM; ++ }else{ ++ int rc2; /* finalize() return code */ ++ sqlite3_stmt *pStmt = 0; ++ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); ++ if( rc!=SQLITE_OK ){ ++ *pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db)); ++ }else if( sqlite3_column_count(pStmt)!=4 ){ ++ *pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4", ++ p->zClassName, zData, sqlite3_column_count(pStmt) ++ ); ++ rc = SQLITE_ERROR; ++ }else{ ++ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ ++ fuzzer_rule *pRule = 0; ++ rc = fuzzerLoadOneRule(p, pStmt, &pRule, pzErr); ++ if( pRule ){ ++ pRule->pNext = pHead; ++ pHead = pRule; ++ } ++ } ++ } ++ rc2 = sqlite3_finalize(pStmt); ++ if( rc==SQLITE_OK ) rc = rc2; ++ } ++ sqlite3_free(zSql); ++ ++ /* All rules are now in a singly linked list starting at pHead. This ++ ** block sorts them by cost and then sets fuzzer_vtab.pRule to point to ++ ** point to the head of the sorted list. ++ */ ++ if( rc==SQLITE_OK ){ ++ unsigned int i; ++ fuzzer_rule *pX; ++ fuzzer_rule *a[15]; ++ for(i=0; ipNext; ++ pX->pNext = 0; ++ for(i=0; a[i] && ipRule = fuzzerMergeRules(p->pRule, pX); ++ }else{ ++ /* An error has occurred. Setting p->pRule to point to the head of the ++ ** allocated list ensures that the list will be cleaned up in this case. ++ */ ++ assert( p->pRule==0 ); ++ p->pRule = pHead; ++ } ++ ++ return rc; ++} ++ ++/* ++** This function converts an SQL quoted string into an unquoted string ++** and returns a pointer to a buffer allocated using sqlite3_malloc() ++** containing the result. The caller should eventually free this buffer ++** using sqlite3_free. ++** ++** Examples: ++** ++** "abc" becomes abc ++** 'xyz' becomes xyz ++** [pqr] becomes pqr ++** `mno` becomes mno ++*/ ++static char *fuzzerDequote(const char *zIn){ ++ int nIn; /* Size of input string, in bytes */ ++ char *zOut; /* Output (dequoted) string */ ++ ++ nIn = (int)strlen(zIn); ++ zOut = sqlite3_malloc(nIn+1); ++ if( zOut ){ ++ char q = zIn[0]; /* Quote character (if any ) */ ++ ++ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ ++ memcpy(zOut, zIn, nIn+1); ++ }else{ ++ int iOut = 0; /* Index of next byte to write to output */ ++ int iIn; /* Index of next byte to read from input */ ++ ++ if( q=='[' ) q = ']'; ++ for(iIn=1; iInnCursor==0 ); ++ while( p->pRule ){ ++ fuzzer_rule *pRule = p->pRule; ++ p->pRule = pRule->pNext; ++ sqlite3_free(pRule); ++ } ++ sqlite3_free(p); ++ return SQLITE_OK; ++} ++ ++/* ++** xConnect/xCreate method for the fuzzer module. Arguments are: ++** ++** argv[0] -> module name ("fuzzer") ++** argv[1] -> database name ++** argv[2] -> table name ++** argv[3] -> fuzzer rule table name ++*/ ++static int fuzzerConnect( ++ sqlite3 *db, ++ void *pAux, ++ int argc, const char *const*argv, ++ sqlite3_vtab **ppVtab, ++ char **pzErr ++){ ++ int rc = SQLITE_OK; /* Return code */ ++ fuzzer_vtab *pNew = 0; /* New virtual table */ ++ const char *zModule = argv[0]; ++ const char *zDb = argv[1]; ++ ++ if( argc!=4 ){ ++ *pzErr = sqlite3_mprintf( ++ "%s: wrong number of CREATE VIRTUAL TABLE arguments", zModule ++ ); ++ rc = SQLITE_ERROR; ++ }else{ ++ int nModule; /* Length of zModule, in bytes */ ++ ++ nModule = (int)strlen(zModule); ++ pNew = sqlite3_malloc( sizeof(*pNew) + nModule + 1); ++ if( pNew==0 ){ ++ rc = SQLITE_NOMEM; ++ }else{ ++ char *zTab; /* Dequoted name of fuzzer data table */ ++ ++ memset(pNew, 0, sizeof(*pNew)); ++ pNew->zClassName = (char*)&pNew[1]; ++ memcpy(pNew->zClassName, zModule, nModule+1); ++ ++ zTab = fuzzerDequote(argv[3]); ++ if( zTab==0 ){ ++ rc = SQLITE_NOMEM; ++ }else{ ++ rc = fuzzerLoadRules(db, pNew, zDb, zTab, pzErr); ++ sqlite3_free(zTab); ++ } ++ ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,ruleset)"); ++ } ++ if( rc!=SQLITE_OK ){ ++ fuzzerDisconnect((sqlite3_vtab *)pNew); ++ pNew = 0; ++ } ++ } ++ } ++ ++ *ppVtab = (sqlite3_vtab *)pNew; ++ return rc; ++} ++ ++/* ++** Open a new fuzzer cursor. ++*/ ++static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ ++ fuzzer_vtab *p = (fuzzer_vtab*)pVTab; ++ fuzzer_cursor *pCur; ++ pCur = sqlite3_malloc( sizeof(*pCur) ); ++ if( pCur==0 ) return SQLITE_NOMEM; ++ memset(pCur, 0, sizeof(*pCur)); ++ pCur->pVtab = p; ++ *ppCursor = &pCur->base; ++ p->nCursor++; ++ return SQLITE_OK; ++} ++ ++/* ++** Free all stems in a list. ++*/ ++static void fuzzerClearStemList(fuzzer_stem *pStem){ ++ while( pStem ){ ++ fuzzer_stem *pNext = pStem->pNext; ++ sqlite3_free(pStem); ++ pStem = pNext; ++ } ++} ++ ++/* ++** Free up all the memory allocated by a cursor. Set it rLimit to 0 ++** to indicate that it is at EOF. ++*/ ++static void fuzzerClearCursor(fuzzer_cursor *pCur, int clearHash){ ++ int i; ++ fuzzerClearStemList(pCur->pStem); ++ fuzzerClearStemList(pCur->pDone); ++ for(i=0; iaQueue[i]); ++ pCur->rLimit = (fuzzer_cost)0; ++ if( clearHash && pCur->nStem ){ ++ pCur->mxQueue = 0; ++ pCur->pStem = 0; ++ pCur->pDone = 0; ++ memset(pCur->aQueue, 0, sizeof(pCur->aQueue)); ++ memset(pCur->apHash, 0, sizeof(pCur->apHash)); ++ } ++ pCur->nStem = 0; ++} ++ ++/* ++** Close a fuzzer cursor. ++*/ ++static int fuzzerClose(sqlite3_vtab_cursor *cur){ ++ fuzzer_cursor *pCur = (fuzzer_cursor *)cur; ++ fuzzerClearCursor(pCur, 0); ++ sqlite3_free(pCur->zBuf); ++ pCur->pVtab->nCursor--; ++ sqlite3_free(pCur); ++ return SQLITE_OK; ++} ++ ++/* ++** Compute the current output term for a fuzzer_stem. ++*/ ++static int fuzzerRender( ++ fuzzer_stem *pStem, /* The stem to be rendered */ ++ char **pzBuf, /* Write results into this buffer. realloc if needed */ ++ int *pnBuf /* Size of the buffer */ ++){ ++ const fuzzer_rule *pRule = pStem->pRule; ++ int n; /* Size of output term without nul-term */ ++ char *z; /* Buffer to assemble output term in */ ++ ++ n = pStem->nBasis + pRule->nTo - pRule->nFrom; ++ if( (*pnBuf)n; ++ z = *pzBuf; ++ if( n<0 ){ ++ memcpy(z, pStem->zBasis, pStem->nBasis+1); ++ }else{ ++ memcpy(z, pStem->zBasis, n); ++ memcpy(&z[n], pRule->zTo, pRule->nTo); ++ memcpy(&z[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom], ++ pStem->nBasis-n-pRule->nFrom+1); ++ } ++ ++ assert( z[pStem->nBasis + pRule->nTo - pRule->nFrom]==0 ); ++ return SQLITE_OK; ++} ++ ++/* ++** Compute a hash on zBasis. ++*/ ++static unsigned int fuzzerHash(const char *z){ ++ unsigned int h = 0; ++ while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); } ++ return h % FUZZER_HASH; ++} ++ ++/* ++** Current cost of a stem ++*/ ++static fuzzer_cost fuzzerCost(fuzzer_stem *pStem){ ++ return pStem->rCostX = pStem->rBaseCost + pStem->pRule->rCost; ++} ++ ++#if 0 ++/* ++** Print a description of a fuzzer_stem on stderr. ++*/ ++static void fuzzerStemPrint( ++ const char *zPrefix, ++ fuzzer_stem *pStem, ++ const char *zSuffix ++){ ++ if( pStem->n<0 ){ ++ fprintf(stderr, "%s[%s](%d)-->self%s", ++ zPrefix, ++ pStem->zBasis, pStem->rBaseCost, ++ zSuffix ++ ); ++ }else{ ++ char *zBuf = 0; ++ int nBuf = 0; ++ if( fuzzerRender(pStem, &zBuf, &nBuf)!=SQLITE_OK ) return; ++ fprintf(stderr, "%s[%s](%d)-->{%s}(%d)%s", ++ zPrefix, ++ pStem->zBasis, pStem->rBaseCost, zBuf, pStem->, ++ zSuffix ++ ); ++ sqlite3_free(zBuf); ++ } ++} ++#endif ++ ++/* ++** Return 1 if the string to which the cursor is point has already ++** been emitted. Return 0 if not. Return -1 on a memory allocation ++** failures. ++*/ ++static int fuzzerSeen(fuzzer_cursor *pCur, fuzzer_stem *pStem){ ++ unsigned int h; ++ fuzzer_stem *pLookup; ++ ++ if( fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){ ++ return -1; ++ } ++ h = fuzzerHash(pCur->zBuf); ++ pLookup = pCur->apHash[h]; ++ while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){ ++ pLookup = pLookup->pHash; ++ } ++ return pLookup!=0; ++} ++ ++/* ++** If argument pRule is NULL, this function returns false. ++** ++** Otherwise, it returns true if rule pRule should be skipped. A rule ++** should be skipped if it does not belong to rule-set iRuleset, or if ++** applying it to stem pStem would create a string longer than ++** FUZZER_MX_OUTPUT_LENGTH bytes. ++*/ ++static int fuzzerSkipRule( ++ const fuzzer_rule *pRule, /* Determine whether or not to skip this */ ++ fuzzer_stem *pStem, /* Stem rule may be applied to */ ++ int iRuleset /* Rule-set used by the current query */ ++){ ++ return pRule && ( ++ (pRule->iRuleset!=iRuleset) ++ || (pStem->nBasis + pRule->nTo - pRule->nFrom)>FUZZER_MX_OUTPUT_LENGTH ++ ); ++} ++ ++/* ++** Advance a fuzzer_stem to its next value. Return 0 if there are ++** no more values that can be generated by this fuzzer_stem. Return ++** -1 on a memory allocation failure. ++*/ ++static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){ ++ const fuzzer_rule *pRule; ++ while( (pRule = pStem->pRule)!=0 ){ ++ assert( pRule==&pCur->nullRule || pRule->iRuleset==pCur->iRuleset ); ++ while( pStem->n < pStem->nBasis - pRule->nFrom ){ ++ pStem->n++; ++ if( pRule->nFrom==0 ++ || memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0 ++ ){ ++ /* Found a rewrite case. Make sure it is not a duplicate */ ++ int rc = fuzzerSeen(pCur, pStem); ++ if( rc<0 ) return -1; ++ if( rc==0 ){ ++ fuzzerCost(pStem); ++ return 1; ++ } ++ } ++ } ++ pStem->n = -1; ++ do{ ++ pRule = pRule->pNext; ++ }while( fuzzerSkipRule(pRule, pStem, pCur->iRuleset) ); ++ pStem->pRule = pRule; ++ if( pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0; ++ } ++ return 0; ++} ++ ++/* ++** The two input stem lists are both sorted in order of increasing ++** rCostX. Merge them together into a single list, sorted by rCostX, and ++** return a pointer to the head of that new list. ++*/ ++static fuzzer_stem *fuzzerMergeStems(fuzzer_stem *pA, fuzzer_stem *pB){ ++ fuzzer_stem head; ++ fuzzer_stem *pTail; ++ ++ pTail = &head; ++ while( pA && pB ){ ++ if( pA->rCostX<=pB->rCostX ){ ++ pTail->pNext = pA; ++ pTail = pA; ++ pA = pA->pNext; ++ }else{ ++ pTail->pNext = pB; ++ pTail = pB; ++ pB = pB->pNext; ++ } ++ } ++ if( pA==0 ){ ++ pTail->pNext = pB; ++ }else{ ++ pTail->pNext = pA; ++ } ++ return head.pNext; ++} ++ ++/* ++** Load pCur->pStem with the lowest-cost stem. Return a pointer ++** to the lowest-cost stem. ++*/ ++static fuzzer_stem *fuzzerLowestCostStem(fuzzer_cursor *pCur){ ++ fuzzer_stem *pBest, *pX; ++ int iBest; ++ int i; ++ ++ if( pCur->pStem==0 ){ ++ iBest = -1; ++ pBest = 0; ++ for(i=0; i<=pCur->mxQueue; i++){ ++ pX = pCur->aQueue[i]; ++ if( pX==0 ) continue; ++ if( pBest==0 || pBest->rCostX>pX->rCostX ){ ++ pBest = pX; ++ iBest = i; ++ } ++ } ++ if( pBest ){ ++ pCur->aQueue[iBest] = pBest->pNext; ++ pBest->pNext = 0; ++ pCur->pStem = pBest; ++ } ++ } ++ return pCur->pStem; ++} ++ ++/* ++** Insert pNew into queue of pending stems. Then find the stem ++** with the lowest rCostX and move it into pCur->pStem. ++** list. The insert is done such the pNew is in the correct order ++** according to fuzzer_stem.zBaseCost+fuzzer_stem.pRule->rCost. ++*/ ++static fuzzer_stem *fuzzerInsert(fuzzer_cursor *pCur, fuzzer_stem *pNew){ ++ fuzzer_stem *pX; ++ int i; ++ ++ /* If pCur->pStem exists and is greater than pNew, then make pNew ++ ** the new pCur->pStem and insert the old pCur->pStem instead. ++ */ ++ if( (pX = pCur->pStem)!=0 && pX->rCostX>pNew->rCostX ){ ++ pNew->pNext = 0; ++ pCur->pStem = pNew; ++ pNew = pX; ++ } ++ ++ /* Insert the new value */ ++ pNew->pNext = 0; ++ pX = pNew; ++ for(i=0; i<=pCur->mxQueue; i++){ ++ if( pCur->aQueue[i] ){ ++ pX = fuzzerMergeStems(pX, pCur->aQueue[i]); ++ pCur->aQueue[i] = 0; ++ }else{ ++ pCur->aQueue[i] = pX; ++ break; ++ } ++ } ++ if( i>pCur->mxQueue ){ ++ if( imxQueue = i; ++ pCur->aQueue[i] = pX; ++ }else{ ++ assert( pCur->mxQueue==FUZZER_NQUEUE-1 ); ++ pX = fuzzerMergeStems(pX, pCur->aQueue[FUZZER_NQUEUE-1]); ++ pCur->aQueue[FUZZER_NQUEUE-1] = pX; ++ } ++ } ++ ++ return fuzzerLowestCostStem(pCur); ++} ++ ++/* ++** Allocate a new fuzzer_stem. Add it to the hash table but do not ++** link it into either the pCur->pStem or pCur->pDone lists. ++*/ ++static fuzzer_stem *fuzzerNewStem( ++ fuzzer_cursor *pCur, ++ const char *zWord, ++ fuzzer_cost rBaseCost ++){ ++ fuzzer_stem *pNew; ++ fuzzer_rule *pRule; ++ unsigned int h; ++ ++ pNew = sqlite3_malloc( sizeof(*pNew) + (int)strlen(zWord) + 1 ); ++ if( pNew==0 ) return 0; ++ memset(pNew, 0, sizeof(*pNew)); ++ pNew->zBasis = (char*)&pNew[1]; ++ pNew->nBasis = (fuzzer_len)strlen(zWord); ++ memcpy(pNew->zBasis, zWord, pNew->nBasis+1); ++ pRule = pCur->pVtab->pRule; ++ while( fuzzerSkipRule(pRule, pNew, pCur->iRuleset) ){ ++ pRule = pRule->pNext; ++ } ++ pNew->pRule = pRule; ++ pNew->n = -1; ++ pNew->rBaseCost = pNew->rCostX = rBaseCost; ++ h = fuzzerHash(pNew->zBasis); ++ pNew->pHash = pCur->apHash[h]; ++ pCur->apHash[h] = pNew; ++ pCur->nStem++; ++ return pNew; ++} ++ ++ ++/* ++** Advance a cursor to its next row of output ++*/ ++static int fuzzerNext(sqlite3_vtab_cursor *cur){ ++ fuzzer_cursor *pCur = (fuzzer_cursor*)cur; ++ int rc; ++ fuzzer_stem *pStem, *pNew; ++ ++ pCur->iRowid++; ++ ++ /* Use the element the cursor is currently point to to create ++ ** a new stem and insert the new stem into the priority queue. ++ */ ++ pStem = pCur->pStem; ++ if( pStem->rCostX>0 ){ ++ rc = fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf); ++ if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM; ++ pNew = fuzzerNewStem(pCur, pCur->zBuf, pStem->rCostX); ++ if( pNew ){ ++ if( fuzzerAdvance(pCur, pNew)==0 ){ ++ pNew->pNext = pCur->pDone; ++ pCur->pDone = pNew; ++ }else{ ++ if( fuzzerInsert(pCur, pNew)==pNew ){ ++ return SQLITE_OK; ++ } ++ } ++ }else{ ++ return SQLITE_NOMEM; ++ } ++ } ++ ++ /* Adjust the priority queue so that the first element of the ++ ** stem list is the next lowest cost word. ++ */ ++ while( (pStem = pCur->pStem)!=0 ){ ++ int res = fuzzerAdvance(pCur, pStem); ++ if( res<0 ){ ++ return SQLITE_NOMEM; ++ }else if( res>0 ){ ++ pCur->pStem = 0; ++ pStem = fuzzerInsert(pCur, pStem); ++ if( (rc = fuzzerSeen(pCur, pStem))!=0 ){ ++ if( rc<0 ) return SQLITE_NOMEM; ++ continue; ++ } ++ return SQLITE_OK; /* New word found */ ++ } ++ pCur->pStem = 0; ++ pStem->pNext = pCur->pDone; ++ pCur->pDone = pStem; ++ if( fuzzerLowestCostStem(pCur) ){ ++ rc = fuzzerSeen(pCur, pCur->pStem); ++ if( rc<0 ) return SQLITE_NOMEM; ++ if( rc==0 ){ ++ return SQLITE_OK; ++ } ++ } ++ } ++ ++ /* Reach this point only if queue has been exhausted and there is ++ ** nothing left to be output. */ ++ pCur->rLimit = (fuzzer_cost)0; ++ return SQLITE_OK; ++} ++ ++/* ++** Called to "rewind" a cursor back to the beginning so that ++** it starts its output over again. Always called at least once ++** prior to any fuzzerColumn, fuzzerRowid, or fuzzerEof call. ++*/ ++static int fuzzerFilter( ++ sqlite3_vtab_cursor *pVtabCursor, ++ int idxNum, const char *idxStr, ++ int argc, sqlite3_value **argv ++){ ++ fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor; ++ const char *zWord = ""; ++ fuzzer_stem *pStem; ++ int idx; ++ ++ fuzzerClearCursor(pCur, 1); ++ pCur->rLimit = 2147483647; ++ idx = 0; ++ if( idxNum & 1 ){ ++ zWord = (const char*)sqlite3_value_text(argv[0]); ++ idx++; ++ } ++ if( idxNum & 2 ){ ++ pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[idx]); ++ idx++; ++ } ++ if( idxNum & 4 ){ ++ pCur->iRuleset = (fuzzer_cost)sqlite3_value_int(argv[idx]); ++ idx++; ++ } ++ pCur->nullRule.pNext = pCur->pVtab->pRule; ++ pCur->nullRule.rCost = 0; ++ pCur->nullRule.nFrom = 0; ++ pCur->nullRule.nTo = 0; ++ pCur->nullRule.zFrom = ""; ++ pCur->iRowid = 1; ++ assert( pCur->pStem==0 ); ++ ++ /* If the query term is longer than FUZZER_MX_OUTPUT_LENGTH bytes, this ++ ** query will return zero rows. */ ++ if( (int)strlen(zWord)pStem = pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0); ++ if( pStem==0 ) return SQLITE_NOMEM; ++ pStem->pRule = &pCur->nullRule; ++ pStem->n = pStem->nBasis; ++ }else{ ++ pCur->rLimit = 0; ++ } ++ ++ return SQLITE_OK; ++} ++ ++/* ++** Only the word and distance columns have values. All other columns ++** return NULL ++*/ ++static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ ++ fuzzer_cursor *pCur = (fuzzer_cursor*)cur; ++ if( i==0 ){ ++ /* the "word" column */ ++ if( fuzzerRender(pCur->pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){ ++ return SQLITE_NOMEM; ++ } ++ sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT); ++ }else if( i==1 ){ ++ /* the "distance" column */ ++ sqlite3_result_int(ctx, pCur->pStem->rCostX); ++ }else{ ++ /* All other columns are NULL */ ++ sqlite3_result_null(ctx); ++ } ++ return SQLITE_OK; ++} ++ ++/* ++** The rowid. ++*/ ++static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ++ fuzzer_cursor *pCur = (fuzzer_cursor*)cur; ++ *pRowid = pCur->iRowid; ++ return SQLITE_OK; ++} ++ ++/* ++** When the fuzzer_cursor.rLimit value is 0 or less, that is a signal ++** that the cursor has nothing more to output. ++*/ ++static int fuzzerEof(sqlite3_vtab_cursor *cur){ ++ fuzzer_cursor *pCur = (fuzzer_cursor*)cur; ++ return pCur->rLimit<=(fuzzer_cost)0; ++} ++ ++/* ++** Search for terms of these forms: ++** ++** (A) word MATCH $str ++** (B1) distance < $value ++** (B2) distance <= $value ++** (C) ruleid == $ruleid ++** ++** The distance< and distance<= are both treated as distance<=. ++** The query plan number is a bit vector: ++** ++** bit 1: Term of the form (A) found ++** bit 2: Term like (B1) or (B2) found ++** bit 3: Term like (C) found ++** ++** If bit-1 is set, $str is always in filter.argv[0]. If bit-2 is set ++** then $value is in filter.argv[0] if bit-1 is clear and is in ++** filter.argv[1] if bit-1 is set. If bit-3 is set, then $ruleid is ++** in filter.argv[0] if bit-1 and bit-2 are both zero, is in ++** filter.argv[1] if exactly one of bit-1 and bit-2 are set, and is in ++** filter.argv[2] if both bit-1 and bit-2 are set. ++*/ ++static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ++ int iPlan = 0; ++ int iDistTerm = -1; ++ int iRulesetTerm = -1; ++ int i; ++ int seenMatch = 0; ++ const struct sqlite3_index_constraint *pConstraint; ++ double rCost = 1e12; ++ ++ pConstraint = pIdxInfo->aConstraint; ++ for(i=0; inConstraint; i++, pConstraint++){ ++ if( pConstraint->iColumn==0 ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ ++ seenMatch = 1; ++ } ++ if( pConstraint->usable==0 ) continue; ++ if( (iPlan & 1)==0 ++ && pConstraint->iColumn==0 ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ++ ){ ++ iPlan |= 1; ++ pIdxInfo->aConstraintUsage[i].argvIndex = 1; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ rCost /= 1e6; ++ } ++ if( (iPlan & 2)==0 ++ && pConstraint->iColumn==1 ++ && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ++ || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE) ++ ){ ++ iPlan |= 2; ++ iDistTerm = i; ++ rCost /= 10.0; ++ } ++ if( (iPlan & 4)==0 ++ && pConstraint->iColumn==2 ++ && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ++ ){ ++ iPlan |= 4; ++ pIdxInfo->aConstraintUsage[i].omit = 1; ++ iRulesetTerm = i; ++ rCost /= 10.0; ++ } ++ } ++ if( iPlan & 2 ){ ++ pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1+((iPlan&1)!=0); ++ } ++ if( iPlan & 4 ){ ++ int idx = 1; ++ if( iPlan & 1 ) idx++; ++ if( iPlan & 2 ) idx++; ++ pIdxInfo->aConstraintUsage[iRulesetTerm].argvIndex = idx; ++ } ++ pIdxInfo->idxNum = iPlan; ++ if( pIdxInfo->nOrderBy==1 ++ && pIdxInfo->aOrderBy[0].iColumn==1 ++ && pIdxInfo->aOrderBy[0].desc==0 ++ ){ ++ pIdxInfo->orderByConsumed = 1; ++ } ++ if( seenMatch && (iPlan&1)==0 ) rCost = 1e99; ++ pIdxInfo->estimatedCost = rCost; ++ ++ return SQLITE_OK; ++} ++ ++/* ++** A virtual table module that implements the "fuzzer". ++*/ ++static const sqlite3_module fuzzerModule = { ++ 0, /* iVersion */ ++ fuzzerConnect, ++ fuzzerConnect, ++ fuzzerBestIndex, ++ fuzzerDisconnect, ++ fuzzerDisconnect, ++ fuzzerOpen, /* xOpen - open a cursor */ ++ fuzzerClose, /* xClose - close a cursor */ ++ fuzzerFilter, /* xFilter - configure scan constraints */ ++ fuzzerNext, /* xNext - advance a cursor */ ++ fuzzerEof, /* xEof - check for end of scan */ ++ fuzzerColumn, /* xColumn - read data */ ++ fuzzerRowid, /* xRowid - read data */ ++ 0, /* xUpdate */ ++ 0, /* xBegin */ ++ 0, /* xSync */ ++ 0, /* xCommit */ ++ 0, /* xRollback */ ++ 0, /* xFindMethod */ ++ 0, /* xRename */ ++}; ++ ++#endif /* SQLITE_OMIT_VIRTUALTABLE */ ++ ++ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_fuzzer_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0); ++#endif ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++#ifndef SQLITE_OMIT_VIRTUALTABLE ++ rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0); ++#endif ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/icu.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/icu.c 2016-01-06 16:30:35.371713500 +0100 +@@ -0,0 +1,514 @@ ++/* ++** 2007 May 6 ++** ++** 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. ++** ++************************************************************************* ++** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ ++** ++** This file implements an integration between the ICU library ++** ("International Components for Unicode", an open-source library ++** for handling unicode data) and SQLite. The integration uses ++** ICU to provide the following to SQLite: ++** ++** * An implementation of the SQL regexp() function (and hence REGEXP ++** operator) using the ICU uregex_XX() APIs. ++** ++** * Implementations of the SQL scalar upper() and lower() functions ++** for case mapping. ++** ++** * Integration of ICU and SQLite collation sequences. ++** ++** * An implementation of the LIKE operator that uses ICU to ++** provide case-independent matching. ++*/ ++ ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) ++ ++/* Include ICU headers */ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef SQLITE_CORE ++ #include "sqlite3ext.h" ++ SQLITE_EXTENSION_INIT1 ++#else ++ #include "sqlite3.h" ++#endif ++ ++/* ++** Maximum length (in bytes) of the pattern in a LIKE or GLOB ++** operator. ++*/ ++#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH ++# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 ++#endif ++ ++/* ++** Version of sqlite3_free() that is always a function, never a macro. ++*/ ++static void xFree(void *p){ ++ sqlite3_free(p); ++} ++ ++/* ++** Compare two UTF-8 strings for equality where the first string is ++** a "LIKE" expression. Return true (1) if they are the same and ++** false (0) if they are different. ++*/ ++static int icuLikeCompare( ++ const uint8_t *zPattern, /* LIKE pattern */ ++ const uint8_t *zString, /* The UTF-8 string to compare against */ ++ const UChar32 uEsc /* The escape character */ ++){ ++ static const int MATCH_ONE = (UChar32)'_'; ++ static const int MATCH_ALL = (UChar32)'%'; ++ ++ int iPattern = 0; /* Current byte index in zPattern */ ++ int iString = 0; /* Current byte index in zString */ ++ ++ int prevEscape = 0; /* True if the previous character was uEsc */ ++ ++ while( zPattern[iPattern]!=0 ){ ++ ++ /* Read (and consume) the next character from the input pattern. */ ++ UChar32 uPattern; ++ U8_NEXT_UNSAFE(zPattern, iPattern, uPattern); ++ ++ /* There are now 4 possibilities: ++ ** ++ ** 1. uPattern is an unescaped match-all character "%", ++ ** 2. uPattern is an unescaped match-one character "_", ++ ** 3. uPattern is an unescaped escape character, or ++ ** 4. uPattern is to be handled as an ordinary character ++ */ ++ if( !prevEscape && uPattern==MATCH_ALL ){ ++ /* Case 1. */ ++ uint8_t c; ++ ++ /* Skip any MATCH_ALL or MATCH_ONE characters that follow a ++ ** MATCH_ALL. For each MATCH_ONE, skip one character in the ++ ** test string. ++ */ ++ while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){ ++ if( c==MATCH_ONE ){ ++ if( zString[iString]==0 ) return 0; ++ U8_FWD_1_UNSAFE(zString, iString); ++ } ++ iPattern++; ++ } ++ ++ if( zPattern[iPattern]==0 ) return 1; ++ ++ while( zString[iString] ){ ++ if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){ ++ return 1; ++ } ++ U8_FWD_1_UNSAFE(zString, iString); ++ } ++ return 0; ++ ++ }else if( !prevEscape && uPattern==MATCH_ONE ){ ++ /* Case 2. */ ++ if( zString[iString]==0 ) return 0; ++ U8_FWD_1_UNSAFE(zString, iString); ++ ++ }else if( !prevEscape && uPattern==uEsc){ ++ /* Case 3. */ ++ prevEscape = 1; ++ ++ }else{ ++ /* Case 4. */ ++ UChar32 uString; ++ U8_NEXT_UNSAFE(zString, iString, uString); ++ uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT); ++ uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT); ++ if( uString!=uPattern ){ ++ return 0; ++ } ++ prevEscape = 0; ++ } ++ } ++ ++ return zString[iString]==0; ++} ++ ++/* ++** Implementation of the like() SQL function. This function implements ++** the build-in LIKE operator. The first argument to the function is the ++** pattern and the second argument is the string. So, the SQL statements: ++** ++** A LIKE B ++** ++** is implemented as like(B, A). If there is an escape character E, ++** ++** A LIKE B ESCAPE E ++** ++** is mapped to like(B, A, E). ++*/ ++static void icuLikeFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const unsigned char *zA = sqlite3_value_text(argv[0]); ++ const unsigned char *zB = sqlite3_value_text(argv[1]); ++ UChar32 uEsc = 0; ++ ++ /* Limit the length of the LIKE or GLOB pattern to avoid problems ++ ** of deep recursion and N*N behavior in patternCompare(). ++ */ ++ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ ++ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); ++ return; ++ } ++ ++ ++ if( argc==3 ){ ++ /* The escape character string must consist of a single UTF-8 character. ++ ** Otherwise, return an error. ++ */ ++ size_t nE= sqlite3_value_bytes(argv[2]); ++ const unsigned char *zE = sqlite3_value_text(argv[2]); ++ int i = 0; ++ if( zE==0 ) return; ++ U8_NEXT(zE, i, nE, uEsc); ++ if( i!=nE){ ++ sqlite3_result_error(context, ++ "ESCAPE expression must be a single character", -1); ++ return; ++ } ++ } ++ ++ if( zA && zB ){ ++ sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); ++ } ++} ++ ++/* ++** This function is called when an ICU function called from within ++** the implementation of an SQL scalar function returns an error. ++** ++** The scalar function context passed as the first argument is ++** loaded with an error message based on the following two args. ++*/ ++static void icuFunctionError( ++ sqlite3_context *pCtx, /* SQLite scalar function context */ ++ const char *zName, /* Name of ICU function that failed */ ++ UErrorCode e /* Error code returned by ICU function */ ++){ ++ char zBuf[128]; ++ sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); ++ zBuf[127] = '\0'; ++ sqlite3_result_error(pCtx, zBuf, -1); ++} ++ ++/* ++** Function to delete compiled regexp objects. Registered as ++** a destructor function with sqlite3_set_auxdata(). ++*/ ++static void icuRegexpDelete(void *p){ ++ URegularExpression *pExpr = (URegularExpression *)p; ++ uregex_close(pExpr); ++} ++ ++/* ++** Implementation of SQLite REGEXP operator. This scalar function takes ++** two arguments. The first is a regular expression pattern to compile ++** the second is a string to match against that pattern. If either ++** argument is an SQL NULL, then NULL Is returned. Otherwise, the result ++** is 1 if the string matches the pattern, or 0 otherwise. ++** ++** SQLite maps the regexp() function to the regexp() operator such ++** that the following two are equivalent: ++** ++** zString REGEXP zPattern ++** regexp(zPattern, zString) ++** ++** Uses the following ICU regexp APIs: ++** ++** uregex_open() ++** uregex_matches() ++** uregex_close() ++*/ ++static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ++ UErrorCode status = U_ZERO_ERROR; ++ URegularExpression *pExpr; ++ UBool res; ++ const UChar *zString = sqlite3_value_text16(apArg[1]); ++ ++ (void)nArg; /* Unused parameter */ ++ ++ /* If the left hand side of the regexp operator is NULL, ++ ** then the result is also NULL. ++ */ ++ if( !zString ){ ++ return; ++ } ++ ++ pExpr = sqlite3_get_auxdata(p, 0); ++ if( !pExpr ){ ++ const UChar *zPattern = sqlite3_value_text16(apArg[0]); ++ if( !zPattern ){ ++ return; ++ } ++ pExpr = uregex_open(zPattern, -1, 0, 0, &status); ++ ++ if( U_SUCCESS(status) ){ ++ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); ++ }else{ ++ assert(!pExpr); ++ icuFunctionError(p, "uregex_open", status); ++ return; ++ } ++ } ++ ++ /* Configure the text that the regular expression operates on. */ ++ uregex_setText(pExpr, zString, -1, &status); ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "uregex_setText", status); ++ return; ++ } ++ ++ /* Attempt the match */ ++ res = uregex_matches(pExpr, 0, &status); ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "uregex_matches", status); ++ return; ++ } ++ ++ /* Set the text that the regular expression operates on to a NULL ++ ** pointer. This is not really necessary, but it is tidier than ++ ** leaving the regular expression object configured with an invalid ++ ** pointer after this function returns. ++ */ ++ uregex_setText(pExpr, 0, 0, &status); ++ ++ /* Return 1 or 0. */ ++ sqlite3_result_int(p, res ? 1 : 0); ++} ++ ++/* ++** Implementations of scalar functions for case mapping - upper() and ++** lower(). Function upper() converts its input to upper-case (ABC). ++** Function lower() converts to lower-case (abc). ++** ++** ICU provides two types of case mapping, "general" case mapping and ++** "language specific". Refer to ICU documentation for the differences ++** between the two. ++** ++** To utilise "general" case mapping, the upper() or lower() scalar ++** functions are invoked with one argument: ++** ++** upper('ABC') -> 'abc' ++** lower('abc') -> 'ABC' ++** ++** To access ICU "language specific" case mapping, upper() or lower() ++** should be invoked with two arguments. The second argument is the name ++** of the locale to use. Passing an empty string ("") or SQL NULL value ++** as the second argument is the same as invoking the 1 argument version ++** of upper() or lower(). ++** ++** lower('I', 'en_us') -> 'i' ++** lower('I', 'tr_tr') -> 'ı' (small dotless i) ++** ++** http://www.icu-project.org/userguide/posix.html#case_mappings ++*/ ++static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ++ const UChar *zInput; ++ UChar *zOutput; ++ size_t nInput; ++ size_t nOutput; ++ ++ UErrorCode status = U_ZERO_ERROR; ++ const char *zLocale = 0; ++ ++ assert(nArg==1 || nArg==2); ++ if( nArg==2 ){ ++ zLocale = (const char *)sqlite3_value_text(apArg[1]); ++ } ++ ++ zInput = sqlite3_value_text16(apArg[0]); ++ if( !zInput ){ ++ return; ++ } ++ nInput = sqlite3_value_bytes16(apArg[0]); ++ ++ nOutput = nInput * 2 + 2; ++ zOutput = sqlite3_malloc(nOutput); ++ if( !zOutput ){ ++ return; ++ } ++ ++ if( sqlite3_user_data(p) ){ ++ u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status); ++ }else{ ++ u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status); ++ } ++ ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "u_strToLower()/u_strToUpper", status); ++ return; ++ } ++ ++ sqlite3_result_text16(p, zOutput, -1, xFree); ++} ++ ++/* ++** Collation sequence destructor function. The pCtx argument points to ++** a UCollator structure previously allocated using ucol_open(). ++*/ ++static void icuCollationDel(void *pCtx){ ++ UCollator *p = (UCollator *)pCtx; ++ ucol_close(p); ++} ++ ++/* ++** Collation sequence comparison function. The pCtx argument points to ++** a UCollator structure previously allocated using ucol_open(). ++*/ ++static int icuCollationColl( ++ void *pCtx, ++ int nLeft, ++ const void *zLeft, ++ int nRight, ++ const void *zRight ++){ ++ UCollationResult res; ++ UCollator *p = (UCollator *)pCtx; ++ res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); ++ switch( res ){ ++ case UCOL_LESS: return -1; ++ case UCOL_GREATER: return +1; ++ case UCOL_EQUAL: return 0; ++ } ++ assert(!"Unexpected return value from ucol_strcoll()"); ++ return 0; ++} ++ ++/* ++** Implementation of the scalar function icu_load_collation(). ++** ++** This scalar function is used to add ICU collation based collation ++** types to an SQLite database connection. It is intended to be called ++** as follows: ++** ++** SELECT icu_load_collation(, ); ++** ++** Where is a string containing an ICU locale identifier (i.e. ++** "en_AU", "tr_TR" etc.) and is the name of the ++** collation sequence to create. ++*/ ++static void icuLoadCollation( ++ sqlite3_context *p, ++ int nArg, ++ sqlite3_value **apArg ++){ ++ sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); ++ UErrorCode status = U_ZERO_ERROR; ++ const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ ++ const char *zName; /* SQL Collation sequence name (eg. "japanese") */ ++ UCollator *pUCollator; /* ICU library collation object */ ++ int rc; /* Return code from sqlite3_create_collation_x() */ ++ ++ assert(nArg==2); ++ (void)nArg; /* Unused parameter */ ++ zLocale = (const char *)sqlite3_value_text(apArg[0]); ++ zName = (const char *)sqlite3_value_text(apArg[1]); ++ ++ if( !zLocale || !zName ){ ++ return; ++ } ++ ++ pUCollator = ucol_open(zLocale, &status); ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "ucol_open", status); ++ return; ++ } ++ assert(p); ++ ++ rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, ++ icuCollationColl, icuCollationDel ++ ); ++ if( rc!=SQLITE_OK ){ ++ ucol_close(pUCollator); ++ sqlite3_result_error(p, "Error registering collation function", -1); ++ } ++} ++ ++/* ++** Register the ICU extension functions with database db. ++*/ ++int sqlite3IcuInit(sqlite3 *db){ ++ struct IcuScalar { ++ const char *zName; /* Function name */ ++ int nArg; /* Number of arguments */ ++ int enc; /* Optimal text encoding */ ++ void *pContext; /* sqlite3_user_data() context */ ++ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); ++ } scalars[] = { ++ {"regexp", 2, SQLITE_UTF8, 0, icuRegexpFunc}, ++ ++ {"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16}, ++ {"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16}, ++ {"upper", 1, SQLITE_UTF16, (void*)1, icuCaseFunc16}, ++ {"upper", 2, SQLITE_UTF16, (void*)1, icuCaseFunc16}, ++ ++ {"lower", 1, SQLITE_UTF8, 0, icuCaseFunc16}, ++ {"lower", 2, SQLITE_UTF8, 0, icuCaseFunc16}, ++ {"upper", 1, SQLITE_UTF8, (void*)1, icuCaseFunc16}, ++ {"upper", 2, SQLITE_UTF8, (void*)1, icuCaseFunc16}, ++ ++ {"like", 2, SQLITE_UTF8, 0, icuLikeFunc}, ++ {"like", 3, SQLITE_UTF8, 0, icuLikeFunc}, ++ ++ {"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation}, ++ }; ++ ++ int rc = SQLITE_OK; ++ int i; ++ ++ for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ ++ struct IcuScalar *p = &scalars[i]; ++ rc = sqlite3_create_function_v2( ++ db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0, 0 ++ ); ++ } ++ ++ return rc; ++} ++ ++#if !SQLITE_CORE ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_icu_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ SQLITE_EXTENSION_INIT2(pApi) ++ return sqlite3IcuInit(db); ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ SQLITE_EXTENSION_INIT2(pApi) ++ return sqlite3IcuInit(db); ++} ++#endif ++#endif ++ ++#endif +--- origsrc/sqlite-autoconf-3100000/ieee754.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/ieee754.c 2016-01-06 16:30:42.504121500 +0100 +@@ -0,0 +1,149 @@ ++/* ++** 2013-04-17 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++****************************************************************************** ++** ++** This SQLite extension implements functions for the exact display ++** and input of IEEE754 Binary64 floating-point numbers. ++** ++** ieee754(X) ++** ieee754(Y,Z) ++** ++** In the first form, the value X should be a floating-point number. ++** The function will return a string of the form 'ieee754(Y,Z)' where ++** Y and Z are integers such that X==Y*pow(2,Z). ++** ++** In the second form, Y and Z are integers which are the mantissa and ++** base-2 exponent of a new floating point number. The function returns ++** a floating-point value equal to Y*pow(2,Z). ++** ++** Examples: ++** ++** ieee754(2.0) -> 'ieee754(2,0)' ++** ieee754(45.25) -> 'ieee754(181,-2)' ++** ieee754(2, 0) -> 2.0 ++** ieee754(181, -2) -> 45.25 ++*/ ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++#include ++#include ++ ++/* ++** Implementation of the ieee754() function ++*/ ++static void ieee754func( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ if( argc==1 ){ ++ sqlite3_int64 m, a; ++ double r; ++ int e; ++ int isNeg; ++ char zResult[100]; ++ assert( sizeof(m)==sizeof(r) ); ++ if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return; ++ r = sqlite3_value_double(argv[0]); ++ if( r<0.0 ){ ++ isNeg = 1; ++ r = -r; ++ }else{ ++ isNeg = 0; ++ } ++ memcpy(&a,&r,sizeof(a)); ++ if( a==0 ){ ++ e = 0; ++ m = 0; ++ }else{ ++ e = a>>52; ++ m = a & ((((sqlite3_int64)1)<<52)-1); ++ m |= ((sqlite3_int64)1)<<52; ++ while( e<1075 && m>0 && (m&1)==0 ){ ++ m >>= 1; ++ e++; ++ } ++ if( isNeg ) m = -m; ++ } ++ sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", ++ m, e-1075); ++ sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); ++ }else if( argc==2 ){ ++ sqlite3_int64 m, e, a; ++ double r; ++ int isNeg = 0; ++ m = sqlite3_value_int64(argv[0]); ++ e = sqlite3_value_int64(argv[1]); ++ if( m<0 ){ ++ isNeg = 1; ++ m = -m; ++ if( m<0 ) return; ++ }else if( m==0 && e>1000 && e<1000 ){ ++ sqlite3_result_double(context, 0.0); ++ return; ++ } ++ while( (m>>32)&0xffe00000 ){ ++ m >>= 1; ++ e++; ++ } ++ while( m!=0 && ((m>>32)&0xfff00000)==0 ){ ++ m <<= 1; ++ e--; ++ } ++ e += 1075; ++ if( e<0 ) e = m = 0; ++ if( e>0x7ff ) e = 0x7ff; ++ a = m & ((((sqlite3_int64)1)<<52)-1); ++ a |= e<<52; ++ if( isNeg ) a |= ((sqlite3_uint64)1)<<63; ++ memcpy(&r, &a, sizeof(r)); ++ sqlite3_result_double(context, r); ++ } ++} ++ ++ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_ieee_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0, ++ ieee754func, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0, ++ ieee754func, 0, 0); ++ } ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0, ++ ieee754func, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0, ++ ieee754func, 0, 0); ++ } ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/nextchar.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/nextchar.c 2016-01-06 16:30:42.508121700 +0100 +@@ -0,0 +1,333 @@ ++/* ++** 2013-02-28 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++****************************************************************************** ++** ++** This file contains code to implement the next_char(A,T,F,W,C) SQL function. ++** ++** The next_char(A,T,F,W,C) function finds all valid "next" characters for ++** string A given the vocabulary in T.F. If the W value exists and is a ++** non-empty string, then it is an SQL expression that limits the entries ++** in T.F that will be considered. If C exists and is a non-empty string, ++** then it is the name of the collating sequence to use for comparison. If ++** ++** Only the first three arguments are required. If the C parameter is ++** omitted or is NULL or is an empty string, then the default collating ++** sequence of T.F is used for comparision. If the W parameter is omitted ++** or is NULL or is an empty string, then no filtering of the output is ++** done. ++** ++** The T.F column should be indexed using collation C or else this routine ++** will be quite slow. ++** ++** For example, suppose an application has a dictionary like this: ++** ++** CREATE TABLE dictionary(word TEXT UNIQUE); ++** ++** Further suppose that for user keypad entry, it is desired to disable ++** (gray out) keys that are not valid as the next character. If the ++** the user has previously entered (say) 'cha' then to find all allowed ++** next characters (and thereby determine when keys should not be grayed ++** out) run the following query: ++** ++** SELECT next_char('cha','dictionary','word'); ++** ++** IMPLEMENTATION NOTES: ++** ++** The next_char function is implemented using recursive SQL that makes ++** use of the table name and column name as part of a query. If either ++** the table name or column name are keywords or contain special characters, ++** then they should be escaped. For example: ++** ++** SELECT next_char('cha','[dictionary]','[word]'); ++** ++** This also means that the table name can be a subquery: ++** ++** SELECT next_char('cha','(SELECT word AS w FROM dictionary)','w'); ++*/ ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++#include ++ ++/* ++** A structure to hold context of the next_char() computation across ++** nested function calls. ++*/ ++typedef struct nextCharContext nextCharContext; ++struct nextCharContext { ++ sqlite3 *db; /* Database connection */ ++ sqlite3_stmt *pStmt; /* Prepared statement used to query */ ++ const unsigned char *zPrefix; /* Prefix to scan */ ++ int nPrefix; /* Size of zPrefix in bytes */ ++ int nAlloc; /* Space allocated to aResult */ ++ int nUsed; /* Space used in aResult */ ++ unsigned int *aResult; /* Array of next characters */ ++ int mallocFailed; /* True if malloc fails */ ++ int otherError; /* True for any other failure */ ++}; ++ ++/* ++** Append a result character if the character is not already in the ++** result. ++*/ ++static void nextCharAppend(nextCharContext *p, unsigned c){ ++ int i; ++ for(i=0; inUsed; i++){ ++ if( p->aResult[i]==c ) return; ++ } ++ if( p->nUsed+1 > p->nAlloc ){ ++ unsigned int *aNew; ++ int n = p->nAlloc*2 + 30; ++ aNew = sqlite3_realloc(p->aResult, n*sizeof(unsigned int)); ++ if( aNew==0 ){ ++ p->mallocFailed = 1; ++ return; ++ }else{ ++ p->aResult = aNew; ++ p->nAlloc = n; ++ } ++ } ++ p->aResult[p->nUsed++] = c; ++} ++ ++/* ++** Write a character into z[] as UTF8. Return the number of bytes needed ++** to hold the character ++*/ ++static int writeUtf8(unsigned char *z, unsigned c){ ++ if( c<0x00080 ){ ++ z[0] = (unsigned char)(c&0xff); ++ return 1; ++ } ++ if( c<0x00800 ){ ++ z[0] = 0xC0 + (unsigned char)((c>>6)&0x1F); ++ z[1] = 0x80 + (unsigned char)(c & 0x3F); ++ return 2; ++ } ++ if( c<0x10000 ){ ++ z[0] = 0xE0 + (unsigned char)((c>>12)&0x0F); ++ z[1] = 0x80 + (unsigned char)((c>>6) & 0x3F); ++ z[2] = 0x80 + (unsigned char)(c & 0x3F); ++ return 3; ++ } ++ z[0] = 0xF0 + (unsigned char)((c>>18) & 0x07); ++ z[1] = 0x80 + (unsigned char)((c>>12) & 0x3F); ++ z[2] = 0x80 + (unsigned char)((c>>6) & 0x3F); ++ z[3] = 0x80 + (unsigned char)(c & 0x3F); ++ return 4; ++} ++ ++/* ++** Read a UTF8 character out of z[] and write it into *pOut. Return ++** the number of bytes in z[] that were used to construct the character. ++*/ ++static int readUtf8(const unsigned char *z, unsigned *pOut){ ++ static const unsigned char validBits[] = { ++ 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, ++ }; ++ unsigned c = z[0]; ++ if( c<0xc0 ){ ++ *pOut = c; ++ return 1; ++ }else{ ++ int n = 1; ++ c = validBits[c-0xc0]; ++ while( (z[n] & 0xc0)==0x80 ){ ++ c = (c<<6) + (0x3f & z[n++]); ++ } ++ if( c<0x80 || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ ++ c = 0xFFFD; ++ } ++ *pOut = c; ++ return n; ++ } ++} ++ ++/* ++** The nextCharContext structure has been set up. Add all "next" characters ++** to the result set. ++*/ ++static void findNextChars(nextCharContext *p){ ++ unsigned cPrev = 0; ++ unsigned char zPrev[8]; ++ int n, rc; ++ ++ for(;;){ ++ sqlite3_bind_text(p->pStmt, 1, (char*)p->zPrefix, p->nPrefix, ++ SQLITE_STATIC); ++ n = writeUtf8(zPrev, cPrev+1); ++ sqlite3_bind_text(p->pStmt, 2, (char*)zPrev, n, SQLITE_STATIC); ++ rc = sqlite3_step(p->pStmt); ++ if( rc==SQLITE_DONE ){ ++ sqlite3_reset(p->pStmt); ++ return; ++ }else if( rc!=SQLITE_ROW ){ ++ p->otherError = rc; ++ return; ++ }else{ ++ const unsigned char *zOut = sqlite3_column_text(p->pStmt, 0); ++ unsigned cNext; ++ n = readUtf8(zOut+p->nPrefix, &cNext); ++ sqlite3_reset(p->pStmt); ++ nextCharAppend(p, cNext); ++ cPrev = cNext; ++ if( p->mallocFailed ) return; ++ } ++ } ++} ++ ++ ++/* ++** next_character(A,T,F,W) ++** ++** Return a string composted of all next possible characters after ++** A for elements of T.F. If W is supplied, then it is an SQL expression ++** that limits the elements in T.F that are considered. ++*/ ++static void nextCharFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ nextCharContext c; ++ const unsigned char *zTable = sqlite3_value_text(argv[1]); ++ const unsigned char *zField = sqlite3_value_text(argv[2]); ++ const unsigned char *zWhere; ++ const unsigned char *zCollName; ++ char *zWhereClause = 0; ++ char *zColl = 0; ++ char *zSql; ++ int rc; ++ ++ memset(&c, 0, sizeof(c)); ++ c.db = sqlite3_context_db_handle(context); ++ c.zPrefix = sqlite3_value_text(argv[0]); ++ c.nPrefix = sqlite3_value_bytes(argv[0]); ++ if( zTable==0 || zField==0 || c.zPrefix==0 ) return; ++ if( argc>=4 ++ && (zWhere = sqlite3_value_text(argv[3]))!=0 ++ && zWhere[0]!=0 ++ ){ ++ zWhereClause = sqlite3_mprintf("AND (%s)", zWhere); ++ if( zWhereClause==0 ){ ++ sqlite3_result_error_nomem(context); ++ return; ++ } ++ }else{ ++ zWhereClause = ""; ++ } ++ if( argc>=5 ++ && (zCollName = sqlite3_value_text(argv[4]))!=0 ++ && zCollName[0]!=0 ++ ){ ++ zColl = sqlite3_mprintf("collate \"%w\"", zCollName); ++ if( zColl==0 ){ ++ sqlite3_result_error_nomem(context); ++ if( zWhereClause[0] ) sqlite3_free(zWhereClause); ++ return; ++ } ++ }else{ ++ zColl = ""; ++ } ++ zSql = sqlite3_mprintf( ++ "SELECT %s FROM %s" ++ " WHERE %s>=(?1 || ?2) %s" ++ " AND %s<=(?1 || char(1114111)) %s" /* 1114111 == 0x10ffff */ ++ " %s" ++ " ORDER BY 1 %s ASC LIMIT 1", ++ zField, zTable, zField, zColl, zField, zColl, zWhereClause, zColl ++ ); ++ if( zWhereClause[0] ) sqlite3_free(zWhereClause); ++ if( zColl[0] ) sqlite3_free(zColl); ++ if( zSql==0 ){ ++ sqlite3_result_error_nomem(context); ++ return; ++ } ++ ++ rc = sqlite3_prepare_v2(c.db, zSql, -1, &c.pStmt, 0); ++ sqlite3_free(zSql); ++ if( rc ){ ++ sqlite3_result_error(context, sqlite3_errmsg(c.db), -1); ++ return; ++ } ++ findNextChars(&c); ++ if( c.mallocFailed ){ ++ sqlite3_result_error_nomem(context); ++ }else{ ++ unsigned char *pRes; ++ pRes = sqlite3_malloc( c.nUsed*4 + 1 ); ++ if( pRes==0 ){ ++ sqlite3_result_error_nomem(context); ++ }else{ ++ int i; ++ int n = 0; ++ for(i=0; i ++#include ++#include ++ ++/* The following object is the session context for a single percentile() ++** function. We have to remember all input Y values until the very end. ++** Those values are accumulated in the Percentile.a[] array. ++*/ ++typedef struct Percentile Percentile; ++struct Percentile { ++ unsigned nAlloc; /* Number of slots allocated for a[] */ ++ unsigned nUsed; /* Number of slots actually used in a[] */ ++ double rPct; /* 1.0 more than the value for P */ ++ double *a; /* Array of Y values */ ++}; ++ ++/* ++** Return TRUE if the input floating-point number is an infinity. ++*/ ++static int isInfinity(double r){ ++ sqlite3_uint64 u; ++ assert( sizeof(u)==sizeof(r) ); ++ memcpy(&u, &r, sizeof(u)); ++ return ((u>>52)&0x7ff)==0x7ff; ++} ++ ++/* ++** Return TRUE if two doubles differ by 0.001 or less ++*/ ++static int sameValue(double a, double b){ ++ a -= b; ++ return a>=-0.001 && a<=0.001; ++} ++ ++/* ++** The "step" function for percentile(Y,P) is called once for each ++** input row. ++*/ ++static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){ ++ Percentile *p; ++ double rPct; ++ int eType; ++ double y; ++ assert( argc==2 ); ++ ++ /* Requirement 3: P must be a number between 0 and 100 */ ++ eType = sqlite3_value_numeric_type(argv[1]); ++ rPct = sqlite3_value_double(argv[1]); ++ if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT) || ++ ((rPct = sqlite3_value_double(argv[1]))<0.0 || rPct>100.0) ){ ++ sqlite3_result_error(pCtx, "2nd argument to percentile() is not " ++ "a number between 0.0 and 100.0", -1); ++ return; ++ } ++ ++ /* Allocate the session context. */ ++ p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); ++ if( p==0 ) return; ++ ++ /* Remember the P value. Throw an error if the P value is different ++ ** from any prior row, per Requirement (2). */ ++ if( p->rPct==0.0 ){ ++ p->rPct = rPct+1.0; ++ }else if( !sameValue(p->rPct,rPct+1.0) ){ ++ sqlite3_result_error(pCtx, "2nd argument to percentile() is not the " ++ "same for all input rows", -1); ++ return; ++ } ++ ++ /* Ignore rows for which Y is NULL */ ++ eType = sqlite3_value_type(argv[0]); ++ if( eType==SQLITE_NULL ) return; ++ ++ /* If not NULL, then Y must be numeric. Otherwise throw an error. ++ ** Requirement 4 */ ++ if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ ++ sqlite3_result_error(pCtx, "1st argument to percentile() is not " ++ "numeric", -1); ++ return; ++ } ++ ++ /* Throw an error if the Y value is infinity or NaN */ ++ y = sqlite3_value_double(argv[0]); ++ if( isInfinity(y) ){ ++ sqlite3_result_error(pCtx, "Inf input to percentile()", -1); ++ return; ++ } ++ ++ /* Allocate and store the Y */ ++ if( p->nUsed>=p->nAlloc ){ ++ unsigned n = p->nAlloc*2 + 250; ++ double *a = sqlite3_realloc(p->a, sizeof(double)*n); ++ if( a==0 ){ ++ sqlite3_free(p->a); ++ memset(p, 0, sizeof(*p)); ++ sqlite3_result_error_nomem(pCtx); ++ return; ++ } ++ p->nAlloc = n; ++ p->a = a; ++ } ++ p->a[p->nUsed++] = y; ++} ++ ++/* ++** Compare to doubles for sorting using qsort() ++*/ ++static int doubleCmp(const void *pA, const void *pB){ ++ double a = *(double*)pA; ++ double b = *(double*)pB; ++ if( a==b ) return 0; ++ if( aa==0 ) return; ++ if( p->nUsed ){ ++ qsort(p->a, p->nUsed, sizeof(double), doubleCmp); ++ ix = (p->rPct-1.0)*(p->nUsed-1)*0.01; ++ i1 = (unsigned)ix; ++ i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; ++ v1 = p->a[i1]; ++ v2 = p->a[i2]; ++ vx = v1 + (v2-v1)*(ix-i1); ++ sqlite3_result_double(pCtx, vx); ++ } ++ sqlite3_free(p->a); ++ memset(p, 0, sizeof(*p)); ++} ++ ++ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_percentile_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0, ++ 0, percentStep, percentFinal); ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* Unused parameter */ ++ rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0, ++ 0, percentStep, percentFinal); ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/rbu.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/rbu.c 2016-01-06 16:48:54.403574500 +0100 +@@ -0,0 +1,125 @@ ++/* ++** 2014 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. ++** ++************************************************************************* ++** ++** This file contains a command-line application that uses the RBU ++** extension. See the usage() function below for an explanation. ++*/ ++ ++#include "sqlite3rbu.h" ++#include ++#include ++#include ++ ++/* ++** Print a usage message and exit. ++*/ ++void usage(const char *zArgv0){ ++ fprintf(stderr, ++"Usage: %s [-step NSTEP] TARGET-DB RBU-DB\n" ++"\n" ++" Argument RBU-DB must be an RBU database containing an update suitable for\n" ++" target database TARGET-DB. If NSTEP is set to less than or equal to zero\n" ++" (the default value), this program attempts to apply the entire update to\n" ++" the target database.\n" ++"\n" ++" If NSTEP is greater than zero, then a maximum of NSTEP calls are made\n" ++" to sqlite3rbu_step(). If the RBU update has not been completely applied\n" ++" after the NSTEP'th call is made, the state is saved in the database RBU-DB\n" ++" and the program exits. Subsequent invocations of this (or any other RBU)\n" ++" application will use this state to resume applying the RBU update to the\n" ++" target db.\n" ++"\n" ++, zArgv0); ++ exit(1); ++} ++ ++void report_default_vfs(){ ++ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); ++ fprintf(stdout, "default vfs is \"%s\"\n", pVfs->zName); ++} ++ ++void report_rbu_vfs(sqlite3rbu *pRbu){ ++ sqlite3 *db = sqlite3rbu_db(pRbu, 0); ++ if( db ){ ++ char *zName = 0; ++ sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zName); ++ if( zName ){ ++ fprintf(stdout, "using vfs \"%s\"\n", zName); ++ }else{ ++ fprintf(stdout, "vfs name not available\n"); ++ } ++ sqlite3_free(zName); ++ } ++} ++ ++int main(int argc, char **argv){ ++ int i; ++ const char *zTarget; /* Target database to apply RBU to */ ++ const char *zRbu; /* Database containing RBU */ ++ char zBuf[200]; /* Buffer for printf() */ ++ char *zErrmsg; /* Error message, if any */ ++ sqlite3rbu *pRbu; /* RBU handle */ ++ int nStep = 0; /* Maximum number of step() calls */ ++ int rc; ++ sqlite3_int64 nProgress = 0; ++ ++ /* Process command line arguments. Following this block local variables ++ ** zTarget, zRbu and nStep are all set. */ ++ if( argc==5 ){ ++ int nArg1 = strlen(argv[1]); ++ if( nArg1>5 || nArg1<2 || memcmp("-step", argv[1], nArg1) ) usage(argv[0]); ++ nStep = atoi(argv[2]); ++ }else if( argc!=3 ){ ++ usage(argv[0]); ++ } ++ zTarget = argv[argc-2]; ++ zRbu = argv[argc-1]; ++ ++ report_default_vfs(); ++ ++ /* Open an RBU handle. If nStep is less than or equal to zero, call ++ ** sqlite3rbu_step() until either the RBU has been completely applied ++ ** or an error occurs. Or, if nStep is greater than zero, call ++ ** sqlite3rbu_step() a maximum of nStep times. */ ++ pRbu = sqlite3rbu_open(zTarget, zRbu, 0); ++ report_rbu_vfs(pRbu); ++ for(i=0; (nStep<=0 || i ++#include ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++ ++/* ++** The following #defines change the names of some functions implemented in ++** this file to prevent name collisions with C-library functions of the ++** same name. ++*/ ++#define re_match sqlite3re_match ++#define re_compile sqlite3re_compile ++#define re_free sqlite3re_free ++ ++/* The end-of-input character */ ++#define RE_EOF 0 /* End of input */ ++ ++/* The NFA is implemented as sequence of opcodes taken from the following ++** set. Each opcode has a single integer argument. ++*/ ++#define RE_OP_MATCH 1 /* Match the one character in the argument */ ++#define RE_OP_ANY 2 /* Match any one character. (Implements ".") */ ++#define RE_OP_ANYSTAR 3 /* Special optimized version of .* */ ++#define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */ ++#define RE_OP_GOTO 5 /* Jump to opcode at iArg */ ++#define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */ ++#define RE_OP_CC_INC 7 /* Beginning of a [...] character class */ ++#define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */ ++#define RE_OP_CC_VALUE 9 /* Single value in a character class */ ++#define RE_OP_CC_RANGE 10 /* Range of values in a character class */ ++#define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */ ++#define RE_OP_NOTWORD 12 /* Not a perl word character */ ++#define RE_OP_DIGIT 13 /* digit: [0-9] */ ++#define RE_OP_NOTDIGIT 14 /* Not a digit */ ++#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ ++#define RE_OP_NOTSPACE 16 /* Not a digit */ ++#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ ++ ++/* Each opcode is a "state" in the NFA */ ++typedef unsigned short ReStateNumber; ++ ++/* Because this is an NFA and not a DFA, multiple states can be active at ++** once. An instance of the following object records all active states in ++** the NFA. The implementation is optimized for the common case where the ++** number of actives states is small. ++*/ ++typedef struct ReStateSet { ++ unsigned nState; /* Number of current states */ ++ ReStateNumber *aState; /* Current states */ ++} ReStateSet; ++ ++/* An input string read one character at a time. ++*/ ++typedef struct ReInput ReInput; ++struct ReInput { ++ const unsigned char *z; /* All text */ ++ int i; /* Next byte to read */ ++ int mx; /* EOF when i>=mx */ ++}; ++ ++/* A compiled NFA (or an NFA that is in the process of being compiled) is ++** an instance of the following object. ++*/ ++typedef struct ReCompiled ReCompiled; ++struct ReCompiled { ++ ReInput sIn; /* Regular expression text */ ++ const char *zErr; /* Error message to return */ ++ char *aOp; /* Operators for the virtual machine */ ++ int *aArg; /* Arguments to each operator */ ++ unsigned (*xNextChar)(ReInput*); /* Next character function */ ++ unsigned char zInit[12]; /* Initial text to match */ ++ int nInit; /* Number of characters in zInit */ ++ unsigned nState; /* Number of entries in aOp[] and aArg[] */ ++ unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ ++}; ++ ++/* Add a state to the given state set if it is not already there */ ++static void re_add_state(ReStateSet *pSet, int newState){ ++ unsigned i; ++ for(i=0; inState; i++) if( pSet->aState[i]==newState ) return; ++ pSet->aState[pSet->nState++] = newState; ++} ++ ++/* Extract the next unicode character from *pzIn and return it. Advance ++** *pzIn to the first byte past the end of the character returned. To ++** be clear: this routine converts utf8 to unicode. This routine is ++** optimized for the common case where the next character is a single byte. ++*/ ++static unsigned re_next_char(ReInput *p){ ++ unsigned c; ++ if( p->i>=p->mx ) return 0; ++ c = p->z[p->i++]; ++ if( c>=0x80 ){ ++ if( (c&0xe0)==0xc0 && p->imx && (p->z[p->i]&0xc0)==0x80 ){ ++ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); ++ if( c<0x80 ) c = 0xfffd; ++ }else if( (c&0xf0)==0xe0 && p->i+1mx && (p->z[p->i]&0xc0)==0x80 ++ && (p->z[p->i+1]&0xc0)==0x80 ){ ++ c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); ++ p->i += 2; ++ if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; ++ }else if( (c&0xf8)==0xf0 && p->i+3mx && (p->z[p->i]&0xc0)==0x80 ++ && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ ++ c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) ++ | (p->z[p->i+2]&0x3f); ++ p->i += 3; ++ if( c<=0xffff || c>0x10ffff ) c = 0xfffd; ++ }else{ ++ c = 0xfffd; ++ } ++ } ++ return c; ++} ++static unsigned re_next_char_nocase(ReInput *p){ ++ unsigned c = re_next_char(p); ++ if( c>='A' && c<='Z' ) c += 'a' - 'A'; ++ return c; ++} ++ ++/* Return true if c is a perl "word" character: [A-Za-z0-9_] */ ++static int re_word_char(int c){ ++ return (c>='0' && c<='9') || (c>='a' && c<='z') ++ || (c>='A' && c<='Z') || c=='_'; ++} ++ ++/* Return true if c is a "digit" character: [0-9] */ ++static int re_digit_char(int c){ ++ return (c>='0' && c<='9'); ++} ++ ++/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */ ++static int re_space_char(int c){ ++ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; ++} ++ ++/* Run a compiled regular expression on the zero-terminated input ++** string zIn[]. Return true on a match and false if there is no match. ++*/ ++int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ ++ ReStateSet aStateSet[2], *pThis, *pNext; ++ ReStateNumber aSpace[100]; ++ ReStateNumber *pToFree; ++ unsigned int i = 0; ++ unsigned int iSwap = 0; ++ int c = RE_EOF+1; ++ int cPrev = 0; ++ int rc = 0; ++ ReInput in; ++ ++ in.z = zIn; ++ in.i = 0; ++ in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); ++ ++ /* Look for the initial prefix match, if there is one. */ ++ if( pRe->nInit ){ ++ unsigned char x = pRe->zInit[0]; ++ while( in.i+pRe->nInit<=in.mx ++ && (zIn[in.i]!=x || ++ strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) ++ ){ ++ in.i++; ++ } ++ if( in.i+pRe->nInit>in.mx ) return 0; ++ } ++ ++ if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ ++ pToFree = 0; ++ aStateSet[0].aState = aSpace; ++ }else{ ++ pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState ); ++ if( pToFree==0 ) return -1; ++ aStateSet[0].aState = pToFree; ++ } ++ aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; ++ pNext = &aStateSet[1]; ++ pNext->nState = 0; ++ re_add_state(pNext, 0); ++ while( c!=RE_EOF && pNext->nState>0 ){ ++ cPrev = c; ++ c = pRe->xNextChar(&in); ++ pThis = pNext; ++ pNext = &aStateSet[iSwap]; ++ iSwap = 1 - iSwap; ++ pNext->nState = 0; ++ for(i=0; inState; i++){ ++ int x = pThis->aState[i]; ++ switch( pRe->aOp[x] ){ ++ case RE_OP_MATCH: { ++ if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_ANY: { ++ re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_WORD: { ++ if( re_word_char(c) ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_NOTWORD: { ++ if( !re_word_char(c) ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_DIGIT: { ++ if( re_digit_char(c) ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_NOTDIGIT: { ++ if( !re_digit_char(c) ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_SPACE: { ++ if( re_space_char(c) ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_NOTSPACE: { ++ if( !re_space_char(c) ) re_add_state(pNext, x+1); ++ break; ++ } ++ case RE_OP_BOUNDARY: { ++ if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); ++ break; ++ } ++ case RE_OP_ANYSTAR: { ++ re_add_state(pNext, x); ++ re_add_state(pThis, x+1); ++ break; ++ } ++ case RE_OP_FORK: { ++ re_add_state(pThis, x+pRe->aArg[x]); ++ re_add_state(pThis, x+1); ++ break; ++ } ++ case RE_OP_GOTO: { ++ re_add_state(pThis, x+pRe->aArg[x]); ++ break; ++ } ++ case RE_OP_ACCEPT: { ++ rc = 1; ++ goto re_match_end; ++ } ++ case RE_OP_CC_INC: ++ case RE_OP_CC_EXC: { ++ int j = 1; ++ int n = pRe->aArg[x]; ++ int hit = 0; ++ for(j=1; j>0 && jaOp[x+j]==RE_OP_CC_VALUE ){ ++ if( pRe->aArg[x+j]==c ){ ++ hit = 1; ++ j = -1; ++ } ++ }else{ ++ if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){ ++ hit = 1; ++ j = -1; ++ }else{ ++ j++; ++ } ++ } ++ } ++ if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; ++ if( hit ) re_add_state(pNext, x+n); ++ break; ++ } ++ } ++ } ++ } ++ for(i=0; inState; i++){ ++ if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } ++ } ++re_match_end: ++ sqlite3_free(pToFree); ++ return rc; ++} ++ ++/* Resize the opcode and argument arrays for an RE under construction. ++*/ ++static int re_resize(ReCompiled *p, int N){ ++ char *aOp; ++ int *aArg; ++ aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0])); ++ if( aOp==0 ) return 1; ++ p->aOp = aOp; ++ aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0])); ++ if( aArg==0 ) return 1; ++ p->aArg = aArg; ++ p->nAlloc = N; ++ return 0; ++} ++ ++/* Insert a new opcode and argument into an RE under construction. The ++** insertion point is just prior to existing opcode iBefore. ++*/ ++static int re_insert(ReCompiled *p, int iBefore, int op, int arg){ ++ int i; ++ if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; ++ for(i=p->nState; i>iBefore; i--){ ++ p->aOp[i] = p->aOp[i-1]; ++ p->aArg[i] = p->aArg[i-1]; ++ } ++ p->nState++; ++ p->aOp[iBefore] = op; ++ p->aArg[iBefore] = arg; ++ return iBefore; ++} ++ ++/* Append a new opcode and argument to the end of the RE under construction. ++*/ ++static int re_append(ReCompiled *p, int op, int arg){ ++ return re_insert(p, p->nState, op, arg); ++} ++ ++/* Make a copy of N opcodes starting at iStart onto the end of the RE ++** under construction. ++*/ ++static void re_copy(ReCompiled *p, int iStart, int N){ ++ if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return; ++ memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0])); ++ memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0])); ++ p->nState += N; ++} ++ ++/* Return true if c is a hexadecimal digit character: [0-9a-fA-F] ++** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If ++** c is not a hex digit *pV is unchanged. ++*/ ++static int re_hex(int c, int *pV){ ++ if( c>='0' && c<='9' ){ ++ c -= '0'; ++ }else if( c>='a' && c<='f' ){ ++ c -= 'a' - 10; ++ }else if( c>='A' && c<='F' ){ ++ c -= 'A' - 10; ++ }else{ ++ return 0; ++ } ++ *pV = (*pV)*16 + (c & 0xff); ++ return 1; ++} ++ ++/* A backslash character has been seen, read the next character and ++** return its interpretation. ++*/ ++static unsigned re_esc_char(ReCompiled *p){ ++ static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; ++ static const char zTrans[] = "\a\f\n\r\t\v"; ++ int i, v = 0; ++ char c; ++ if( p->sIn.i>=p->sIn.mx ) return 0; ++ c = p->sIn.z[p->sIn.i]; ++ if( c=='u' && p->sIn.i+4sIn.mx ){ ++ const unsigned char *zIn = p->sIn.z + p->sIn.i; ++ if( re_hex(zIn[1],&v) ++ && re_hex(zIn[2],&v) ++ && re_hex(zIn[3],&v) ++ && re_hex(zIn[4],&v) ++ ){ ++ p->sIn.i += 5; ++ return v; ++ } ++ } ++ if( c=='x' && p->sIn.i+2sIn.mx ){ ++ const unsigned char *zIn = p->sIn.z + p->sIn.i; ++ if( re_hex(zIn[1],&v) ++ && re_hex(zIn[2],&v) ++ ){ ++ p->sIn.i += 3; ++ return v; ++ } ++ } ++ for(i=0; zEsc[i] && zEsc[i]!=c; i++){} ++ if( zEsc[i] ){ ++ if( i<6 ) c = zTrans[i]; ++ p->sIn.i++; ++ }else{ ++ p->zErr = "unknown \\ escape"; ++ } ++ return c; ++} ++ ++/* Forward declaration */ ++static const char *re_subcompile_string(ReCompiled*); ++ ++/* Peek at the next byte of input */ ++static unsigned char rePeek(ReCompiled *p){ ++ return p->sIn.isIn.mx ? p->sIn.z[p->sIn.i] : 0; ++} ++ ++/* Compile RE text into a sequence of opcodes. Continue up to the ++** first unmatched ")" character, then return. If an error is found, ++** return a pointer to the error message string. ++*/ ++static const char *re_subcompile_re(ReCompiled *p){ ++ const char *zErr; ++ int iStart, iEnd, iGoto; ++ iStart = p->nState; ++ zErr = re_subcompile_string(p); ++ if( zErr ) return zErr; ++ while( rePeek(p)=='|' ){ ++ iEnd = p->nState; ++ re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart); ++ iGoto = re_append(p, RE_OP_GOTO, 0); ++ p->sIn.i++; ++ zErr = re_subcompile_string(p); ++ if( zErr ) return zErr; ++ p->aArg[iGoto] = p->nState - iGoto; ++ } ++ return 0; ++} ++ ++/* Compile an element of regular expression text (anything that can be ++** an operand to the "|" operator). Return NULL on success or a pointer ++** to the error message if there is a problem. ++*/ ++static const char *re_subcompile_string(ReCompiled *p){ ++ int iPrev = -1; ++ int iStart; ++ unsigned c; ++ const char *zErr; ++ while( (c = p->xNextChar(&p->sIn))!=0 ){ ++ iStart = p->nState; ++ switch( c ){ ++ case '|': ++ case '$': ++ case ')': { ++ p->sIn.i--; ++ return 0; ++ } ++ case '(': { ++ zErr = re_subcompile_re(p); ++ if( zErr ) return zErr; ++ if( rePeek(p)!=')' ) return "unmatched '('"; ++ p->sIn.i++; ++ break; ++ } ++ case '.': { ++ if( rePeek(p)=='*' ){ ++ re_append(p, RE_OP_ANYSTAR, 0); ++ p->sIn.i++; ++ }else{ ++ re_append(p, RE_OP_ANY, 0); ++ } ++ break; ++ } ++ case '*': { ++ if( iPrev<0 ) return "'*' without operand"; ++ re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); ++ re_append(p, RE_OP_FORK, iPrev - p->nState + 1); ++ break; ++ } ++ case '+': { ++ if( iPrev<0 ) return "'+' without operand"; ++ re_append(p, RE_OP_FORK, iPrev - p->nState); ++ break; ++ } ++ case '?': { ++ if( iPrev<0 ) return "'?' without operand"; ++ re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); ++ break; ++ } ++ case '{': { ++ int m = 0, n = 0; ++ int sz, j; ++ if( iPrev<0 ) return "'{m,n}' without operand"; ++ while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } ++ n = m; ++ if( c==',' ){ ++ p->sIn.i++; ++ n = 0; ++ while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } ++ } ++ if( c!='}' ) return "unmatched '{'"; ++ if( n>0 && nsIn.i++; ++ sz = p->nState - iPrev; ++ if( m==0 ){ ++ if( n==0 ) return "both m and n are zero in '{m,n}'"; ++ re_insert(p, iPrev, RE_OP_FORK, sz+1); ++ n--; ++ }else{ ++ for(j=1; j0 ){ ++ re_append(p, RE_OP_FORK, -sz); ++ } ++ break; ++ } ++ case '[': { ++ int iFirst = p->nState; ++ if( rePeek(p)=='^' ){ ++ re_append(p, RE_OP_CC_EXC, 0); ++ p->sIn.i++; ++ }else{ ++ re_append(p, RE_OP_CC_INC, 0); ++ } ++ while( (c = p->xNextChar(&p->sIn))!=0 ){ ++ if( c=='[' && rePeek(p)==':' ){ ++ return "POSIX character classes not supported"; ++ } ++ if( c=='\\' ) c = re_esc_char(p); ++ if( rePeek(p)=='-' ){ ++ re_append(p, RE_OP_CC_RANGE, c); ++ p->sIn.i++; ++ c = p->xNextChar(&p->sIn); ++ if( c=='\\' ) c = re_esc_char(p); ++ re_append(p, RE_OP_CC_RANGE, c); ++ }else{ ++ re_append(p, RE_OP_CC_VALUE, c); ++ } ++ if( rePeek(p)==']' ){ p->sIn.i++; break; } ++ } ++ if( c==0 ) return "unclosed '['"; ++ p->aArg[iFirst] = p->nState - iFirst; ++ break; ++ } ++ case '\\': { ++ int specialOp = 0; ++ switch( rePeek(p) ){ ++ case 'b': specialOp = RE_OP_BOUNDARY; break; ++ case 'd': specialOp = RE_OP_DIGIT; break; ++ case 'D': specialOp = RE_OP_NOTDIGIT; break; ++ case 's': specialOp = RE_OP_SPACE; break; ++ case 'S': specialOp = RE_OP_NOTSPACE; break; ++ case 'w': specialOp = RE_OP_WORD; break; ++ case 'W': specialOp = RE_OP_NOTWORD; break; ++ } ++ if( specialOp ){ ++ p->sIn.i++; ++ re_append(p, specialOp, 0); ++ }else{ ++ c = re_esc_char(p); ++ re_append(p, RE_OP_MATCH, c); ++ } ++ break; ++ } ++ default: { ++ re_append(p, RE_OP_MATCH, c); ++ break; ++ } ++ } ++ iPrev = iStart; ++ } ++ return 0; ++} ++ ++/* Free and reclaim all the memory used by a previously compiled ++** regular expression. Applications should invoke this routine once ++** for every call to re_compile() to avoid memory leaks. ++*/ ++void re_free(ReCompiled *pRe){ ++ if( pRe ){ ++ sqlite3_free(pRe->aOp); ++ sqlite3_free(pRe->aArg); ++ sqlite3_free(pRe); ++ } ++} ++ ++/* ++** Compile a textual regular expression in zIn[] into a compiled regular ++** expression suitable for us by re_match() and return a pointer to the ++** compiled regular expression in *ppRe. Return NULL on success or an ++** error message if something goes wrong. ++*/ ++const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){ ++ ReCompiled *pRe; ++ const char *zErr; ++ int i, j; ++ ++ *ppRe = 0; ++ pRe = sqlite3_malloc( sizeof(*pRe) ); ++ if( pRe==0 ){ ++ return "out of memory"; ++ } ++ memset(pRe, 0, sizeof(*pRe)); ++ pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char; ++ if( re_resize(pRe, 30) ){ ++ re_free(pRe); ++ return "out of memory"; ++ } ++ if( zIn[0]=='^' ){ ++ zIn++; ++ }else{ ++ re_append(pRe, RE_OP_ANYSTAR, 0); ++ } ++ pRe->sIn.z = (unsigned char*)zIn; ++ pRe->sIn.i = 0; ++ pRe->sIn.mx = (int)strlen(zIn); ++ zErr = re_subcompile_re(pRe); ++ if( zErr ){ ++ re_free(pRe); ++ return zErr; ++ } ++ if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ ++ re_append(pRe, RE_OP_MATCH, RE_EOF); ++ re_append(pRe, RE_OP_ACCEPT, 0); ++ *ppRe = pRe; ++ }else if( pRe->sIn.i>=pRe->sIn.mx ){ ++ re_append(pRe, RE_OP_ACCEPT, 0); ++ *ppRe = pRe; ++ }else{ ++ re_free(pRe); ++ return "unrecognized character"; ++ } ++ ++ /* The following is a performance optimization. If the regex begins with ++ ** ".*" (if the input regex lacks an initial "^") and afterwards there are ++ ** one or more matching characters, enter those matching characters into ++ ** zInit[]. The re_match() routine can then search ahead in the input ++ ** string looking for the initial match without having to run the whole ++ ** regex engine over the string. Do not worry able trying to match ++ ** unicode characters beyond plane 0 - those are very rare and this is ++ ** just an optimization. */ ++ if( pRe->aOp[0]==RE_OP_ANYSTAR ){ ++ for(j=0, i=1; jzInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ ++ unsigned x = pRe->aArg[i]; ++ if( x<=127 ){ ++ pRe->zInit[j++] = x; ++ }else if( x<=0xfff ){ ++ pRe->zInit[j++] = 0xc0 | (x>>6); ++ pRe->zInit[j++] = 0x80 | (x&0x3f); ++ }else if( x<=0xffff ){ ++ pRe->zInit[j++] = 0xd0 | (x>>12); ++ pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); ++ pRe->zInit[j++] = 0x80 | (x&0x3f); ++ }else{ ++ break; ++ } ++ } ++ if( j>0 && pRe->zInit[j-1]==0 ) j--; ++ pRe->nInit = j; ++ } ++ return pRe->zErr; ++} ++ ++/* ++** Implementation of the regexp() SQL function. This function implements ++** the build-in REGEXP operator. The first argument to the function is the ++** pattern and the second argument is the string. So, the SQL statements: ++** ++** A REGEXP B ++** ++** is implemented as regexp(B,A). ++*/ ++static void re_sql_func( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ ReCompiled *pRe; /* Compiled regular expression */ ++ const char *zPattern; /* The regular expression */ ++ const unsigned char *zStr;/* String being searched */ ++ const char *zErr; /* Compile error message */ ++ int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ ++ ++ pRe = sqlite3_get_auxdata(context, 0); ++ if( pRe==0 ){ ++ zPattern = (const char*)sqlite3_value_text(argv[0]); ++ if( zPattern==0 ) return; ++ zErr = re_compile(&pRe, zPattern, 0); ++ if( zErr ){ ++ re_free(pRe); ++ sqlite3_result_error(context, zErr, -1); ++ return; ++ } ++ if( pRe==0 ){ ++ sqlite3_result_error_nomem(context); ++ return; ++ } ++ setAux = 1; ++ } ++ zStr = (const unsigned char*)sqlite3_value_text(argv[1]); ++ if( zStr!=0 ){ ++ sqlite3_result_int(context, re_match(pRe, zStr, -1)); ++ } ++ if( setAux ){ ++ sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); ++ } ++} ++ ++/* ++** Invoke this routine to register the regexp() function with the ++** SQLite database connection. ++*/ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++int sqlite3_regexp_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, ++ re_sql_func, 0, 0); ++ return rc; ++} ++#if !defined(_WIN32) && !defined(SQLITE_TEST) ++int sqlite3_extension_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc = SQLITE_OK; ++ SQLITE_EXTENSION_INIT2(pApi); ++ rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, ++ re_sql_func, 0, 0); ++ return rc; ++} ++#endif +--- origsrc/sqlite-autoconf-3100000/rot13.c 1970-01-01 01:00:00.000000000 +0100 ++++ src/sqlite-autoconf-3100000/rot13.c 2016-01-06 16:30:42.512121900 +0100 +@@ -0,0 +1,131 @@ ++/* ++** 2013-05-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 SQLite extension implements a rot13() function and a rot13 ++** collating sequence. ++*/ ++#include "sqlite3ext.h" ++SQLITE_EXTENSION_INIT1 ++#include ++#include ++ ++/* ++** Perform rot13 encoding on a single ASCII character. ++*/ ++static unsigned char rot13(unsigned char c){ ++ if( c>='a' && c<='z' ){ ++ c += 13; ++ if( c>'z' ) c -= 26; ++ }else if( c>='A' && c<='Z' ){ ++ c += 13; ++ if( c>'Z' ) c -= 26; ++ } ++ return c; ++} ++ ++/* ++** Implementation of the rot13() function. ++** ++** Rotate ASCII alphabetic characters by 13 character positions. ++** Non-ASCII characters are unchanged. rot13(rot13(X)) should always ++** equal X. ++*/ ++static void rot13func( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const unsigned char *zIn; ++ int nIn; ++ unsigned char *zOut; ++ char *zToFree = 0; ++ int i; ++ char zTemp[100]; ++ assert( argc==1 ); ++ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; ++ zIn = (const unsigned char*)sqlite3_value_text(argv[0]); ++ nIn = sqlite3_value_bytes(argv[0]); ++ if( nIn