Merge the std-ext branch into trunk. This merge adds several new extensions
to the ext/misc folder, including transitive_closure, ieee754, and amatch, and it convers some older src/test_*.c file into extensions in the ext/misc folder. FossilOrigin-Name: bbe607c7d17c50b667990360e2ccfab8dd22f161
This commit is contained in:
commit
c140a6b40d
14
Makefile.in
14
Makefile.in
@ -361,7 +361,6 @@ TESTSRC = \
|
||||
$(TOP)/src/test_devsym.c \
|
||||
$(TOP)/src/test_fs.c \
|
||||
$(TOP)/src/test_func.c \
|
||||
$(TOP)/src/test_fuzzer.c \
|
||||
$(TOP)/src/test_hexio.c \
|
||||
$(TOP)/src/test_init.c \
|
||||
$(TOP)/src/test_intarray.c \
|
||||
@ -373,7 +372,6 @@ TESTSRC = \
|
||||
$(TOP)/src/test_osinst.c \
|
||||
$(TOP)/src/test_pcache.c \
|
||||
$(TOP)/src/test_quota.c \
|
||||
$(TOP)/src/test_regexp.c \
|
||||
$(TOP)/src/test_rtree.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
@ -383,11 +381,21 @@ TESTSRC = \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_wholenumber.c \
|
||||
$(TOP)/src/test_wsd.c \
|
||||
$(TOP)/ext/fts3/fts3_term.c \
|
||||
$(TOP)/ext/fts3/fts3_test.c
|
||||
|
||||
# Statically linked extensions
|
||||
#
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
$(TOP)/ext/misc/fuzzer.c \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/spellfix.c \
|
||||
$(TOP)/ext/misc/wholenumber.c
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
#
|
||||
TESTSRC2 = \
|
||||
|
19
Makefile.msc
19
Makefile.msc
@ -681,7 +681,6 @@ TESTSRC = \
|
||||
$(TOP)\src\test_devsym.c \
|
||||
$(TOP)\src\test_fs.c \
|
||||
$(TOP)\src\test_func.c \
|
||||
$(TOP)\src\test_fuzzer.c \
|
||||
$(TOP)\src\test_hexio.c \
|
||||
$(TOP)\src\test_init.c \
|
||||
$(TOP)\src\test_intarray.c \
|
||||
@ -693,7 +692,6 @@ TESTSRC = \
|
||||
$(TOP)\src\test_osinst.c \
|
||||
$(TOP)\src\test_pcache.c \
|
||||
$(TOP)\src\test_quota.c \
|
||||
$(TOP)\src\test_regexp.c \
|
||||
$(TOP)\src\test_rtree.c \
|
||||
$(TOP)\src\test_schema.c \
|
||||
$(TOP)\src\test_server.c \
|
||||
@ -703,11 +701,22 @@ TESTSRC = \
|
||||
$(TOP)\src\test_tclvar.c \
|
||||
$(TOP)\src\test_thread.c \
|
||||
$(TOP)\src\test_vfs.c \
|
||||
$(TOP)\src\test_wholenumber.c \
|
||||
$(TOP)\src\test_wsd.c \
|
||||
$(TOP)\ext\fts3\fts3_term.c \
|
||||
$(TOP)\ext\fts3\fts3_test.c
|
||||
|
||||
# Statically linked extensions
|
||||
#
|
||||
TESTEXT = \
|
||||
$(TOP)\ext\misc\amatch.c \
|
||||
$(TOP)\ext\misc\closure.c \
|
||||
$(TOP)\ext\misc\fuzzer.c \
|
||||
$(TOP)\ext\misc\ieee754.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\spellfix.c \
|
||||
$(TOP)\ext\misc\wholenumber.c
|
||||
|
||||
|
||||
# Source code to the library files needed by the test fixture
|
||||
#
|
||||
TESTSRC2 = \
|
||||
@ -1204,8 +1213,8 @@ rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR)
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.lib
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) libsqlite3.lib
|
||||
TESTFIXTURE_SRC1 = $(TESTEXT) sqlite3.c
|
||||
!IF $(USE_AMALGAMATION)==0
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
|
||||
!ELSE
|
||||
|
1477
ext/misc/amatch.c
Normal file
1477
ext/misc/amatch.c
Normal file
File diff suppressed because it is too large
Load Diff
942
ext/misc/closure.c
Normal file
942
ext/misc/closure.c
Normal file
@ -0,0 +1,942 @@
|
||||
/*
|
||||
** 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=<tablename>, -- T
|
||||
** idcolumn=<columnname>, -- X
|
||||
** parentcolumn=<columnname> -- 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** 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 = (id<p->id) ? 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->id<p->id ){
|
||||
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; iIn<nIn; iIn++){
|
||||
if( zIn[iIn]==q ) iIn++;
|
||||
zOut[iOut++] = zIn[iIn];
|
||||
}
|
||||
}
|
||||
assert( (int)strlen(zOut)<=nIn );
|
||||
}
|
||||
return zOut;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deallocate an closure_vtab object
|
||||
*/
|
||||
static void closureFree(closure_vtab *p){
|
||||
if( p ){
|
||||
sqlite3_free(p->zDb);
|
||||
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<nKey+1 ) return 0;
|
||||
if( memcmp(zStr, zKey, nKey)!=0 ) return 0;
|
||||
for(i=nKey; isspace(zStr[i]); i++){}
|
||||
if( zStr[i]!='=' ) return 0;
|
||||
i++;
|
||||
while( isspace(zStr[i]) ){ i++; }
|
||||
return zStr+i;
|
||||
}
|
||||
|
||||
/*
|
||||
** xConnect/xCreate method for the closure module. Arguments are:
|
||||
**
|
||||
** argv[0] -> module name ("approximate_match")
|
||||
** 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; i<argc; i++){
|
||||
zVal = closureValueOfKey("tablename", argv[i]);
|
||||
if( zVal ){
|
||||
sqlite3_free(pNew->zTableName);
|
||||
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;
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
closure_vtab *pVtab = (closure_vtab*)pTab;
|
||||
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
pIdxInfo->estimatedCost = (double)10000;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** A virtual table module that implements the "approximate_match".
|
||||
*/
|
||||
static 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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;
|
||||
rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0);
|
||||
return rc;
|
||||
}
|
@ -141,13 +141,14 @@
|
||||
** of the strings in the second or third column of the fuzzer data table
|
||||
** is 50 bytes. The maximum cost on a rule is 1000.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
|
||||
/* If SQLITE_DEBUG is not defined, disable assert statements. */
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@ -1155,61 +1156,16 @@ static sqlite3_module fuzzerModule = {
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
|
||||
/*
|
||||
** Register the fuzzer virtual table
|
||||
*/
|
||||
int fuzzer_register(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
|
||||
#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);
|
||||
rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
#include <tcl.h>
|
||||
/*
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
|
||||
/*
|
||||
** Register the echo virtual table module.
|
||||
*/
|
||||
static int register_fuzzer_module(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
getDbPointer(interp, Tcl_GetString(objv[1]), &db);
|
||||
fuzzer_register(db);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetestfuzzer_Init(Tcl_Interp *interp){
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
void *clientData;
|
||||
} aObjCmd[] = {
|
||||
{ "register_fuzzer_module", register_fuzzer_module, 0 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
|
||||
aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_TEST */
|
131
ext/misc/ieee754.c
Normal file
131
ext/misc/ieee754.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
** 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(w.0,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.0,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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** 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>>32)&0xfff00000)==0 ){
|
||||
m <<= 1;
|
||||
e--;
|
||||
}
|
||||
e += 1075;
|
||||
if( e<0 ) e = m = 0;
|
||||
if( e>0x7ff ) m = 0;
|
||||
a = m & ((((sqlite3_int64)1)<<52)-1);
|
||||
a |= e<<52;
|
||||
if( isNeg ) a |= ((sqlite3_int64)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;
|
||||
}
|
@ -12,7 +12,16 @@
|
||||
**
|
||||
** The code in this file implements a compact but reasonably
|
||||
** efficient regular-expression matcher for posix extended regular
|
||||
** expressions against UTF8 text. The following syntax is supported:
|
||||
** expressions against UTF8 text.
|
||||
**
|
||||
** This file is an SQLite extension. It registers a single function
|
||||
** named "regexp(A,B)" where A is the regular expression and B is the
|
||||
** string to be matched. By registering this function, SQLite will also
|
||||
** then implement the "B regexp A" operator. Note that with the function
|
||||
** the regular expression comes first, but with the operator it comes
|
||||
** second.
|
||||
**
|
||||
** The following regular expression syntax is supported:
|
||||
**
|
||||
** X* zero or more occurrences of X
|
||||
** X+ one or more occurrences of X
|
||||
@ -49,7 +58,17 @@
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
#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 */
|
||||
@ -175,7 +194,7 @@ static int re_space_char(int c){
|
||||
/* 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){
|
||||
static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
|
||||
ReStateSet aStateSet[2], *pThis, *pNext;
|
||||
ReStateNumber aSpace[100];
|
||||
ReStateNumber *pToFree;
|
||||
@ -718,53 +737,20 @@ static void re_sql_func(
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this routine in order to install the REGEXP function in an
|
||||
** Invoke this routine to register the regexp() function with the
|
||||
** SQLite database connection.
|
||||
**
|
||||
** Use:
|
||||
**
|
||||
** sqlite3_auto_extension(sqlite3_add_regexp_func);
|
||||
**
|
||||
** to cause this extension to be automatically loaded into each new
|
||||
** database connection.
|
||||
*/
|
||||
int sqlite3_add_regexp_func(sqlite3 *db){
|
||||
return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
|
||||
re_sql_func, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/***************************** Test Code ***********************************/
|
||||
#ifdef SQLITE_TEST
|
||||
#include <tcl.h>
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
|
||||
/* Implementation of the TCL command:
|
||||
**
|
||||
** sqlite3_add_regexp_func $DB
|
||||
*/
|
||||
static int tclSqlite3AddRegexpFunc(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_regexp_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
sqlite3 *db;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
sqlite3_add_regexp_func(db);
|
||||
return TCL_OK;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Register the sqlite3_add_regexp_func TCL command with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetestregexp_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_add_regexp_func",
|
||||
tclSqlite3AddRegexpFunc, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
/**************************** End Of Test Code *******************************/
|
@ -14,20 +14,17 @@
|
||||
** to search a large vocabulary for close matches. See separate
|
||||
** documentation files (spellfix1.wiki and editdist3.wiki) for details.
|
||||
*/
|
||||
#if SQLITE_CORE
|
||||
# include "sqliteInt.h"
|
||||
#else
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include "sqlite3ext.h"
|
||||
# include <assert.h>
|
||||
# define ALWAYS(X) 1
|
||||
# define NEVER(X) 0
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#endif /* !SQLITE_CORE */
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#define ALWAYS(X) 1
|
||||
#define NEVER(X) 0
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
@ -2822,21 +2819,13 @@ static int spellfix1Register(sqlite3 *db){
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if SQLITE_CORE || defined(SQLITE_TEST)
|
||||
/*
|
||||
** Register the spellfix1 virtual table and its associated functions.
|
||||
*/
|
||||
int sqlite3_spellfix1_register(sqlite3 *db){
|
||||
return spellfix1Register(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !SQLITE_CORE
|
||||
/*
|
||||
** Extension load function.
|
||||
*/
|
||||
int sqlite3_spellfix1_init(
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_spellfix_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
@ -2844,4 +2833,3 @@ int sqlite3_spellfix1_init(
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
return spellfix1Register(db);
|
||||
}
|
||||
#endif /* !SQLITE_CORE */
|
@ -22,7 +22,8 @@
|
||||
**
|
||||
** 1 2 3 4 5 6 7 8 9
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -250,62 +251,18 @@ static sqlite3_module wholenumberModule = {
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
|
||||
/*
|
||||
** Register the wholenumber virtual table
|
||||
*/
|
||||
int wholenumber_register(sqlite3 *db){
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_wholenumber_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, "wholenumber", &wholenumberModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
#include <tcl.h>
|
||||
/*
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
|
||||
/*
|
||||
** Register the echo virtual table module.
|
||||
*/
|
||||
static int register_wholenumber_module(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
wholenumber_register(db);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetestwholenumber_Init(Tcl_Interp *interp){
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
void *clientData;
|
||||
} aObjCmd[] = {
|
||||
{ "register_wholenumber_module", register_wholenumber_module, 0 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
|
||||
aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_TEST */
|
15
main.mk
15
main.mk
@ -244,7 +244,6 @@ TESTSRC = \
|
||||
$(TOP)/src/test_devsym.c \
|
||||
$(TOP)/src/test_fs.c \
|
||||
$(TOP)/src/test_func.c \
|
||||
$(TOP)/src/test_fuzzer.c \
|
||||
$(TOP)/src/test_hexio.c \
|
||||
$(TOP)/src/test_init.c \
|
||||
$(TOP)/src/test_intarray.c \
|
||||
@ -256,7 +255,6 @@ TESTSRC = \
|
||||
$(TOP)/src/test_osinst.c \
|
||||
$(TOP)/src/test_pcache.c \
|
||||
$(TOP)/src/test_quota.c \
|
||||
$(TOP)/src/test_regexp.c \
|
||||
$(TOP)/src/test_rtree.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
@ -267,9 +265,20 @@ TESTSRC = \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_wholenumber.c \
|
||||
$(TOP)/src/test_wsd.c
|
||||
|
||||
# Extensions to be statically loaded.
|
||||
#
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
$(TOP)/ext/misc/fuzzer.c \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/spellfix.c \
|
||||
$(TOP)/ext/misc/wholenumber.c
|
||||
|
||||
|
||||
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
|
||||
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c
|
||||
|
||||
|
54
manifest
54
manifest
@ -1,9 +1,9 @@
|
||||
C Make\ssure\sthe\saffinity\sand\sdatatype\sof\ssub-subqueries\sare\sinitialized\nprior\sto\ssubqueries\sas\sthe\slatter\srelies\son\sthe\sformer.
|
||||
D 2013-04-25T00:57:10.497
|
||||
C Merge\sthe\sstd-ext\sbranch\sinto\strunk.\s\sThis\smerge\sadds\sseveral\snew\sextensions\nto\sthe\sext/misc\sfolder,\sincluding\stransitive_closure,\sieee754,\sand\samatch,\nand\sit\sconvers\ssome\solder\ssrc/test_*.c\sfile\sinto\sextensions\sin\sthe\sext/misc\nfolder.
|
||||
D 2013-04-25T16:52:19.390
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 87591ea5bf7d6ed521ad42d5bc69c124debe11a5
|
||||
F Makefile.in 38a45083d4df568eefd31d27d67381850f35a016
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 67d9db478186d7d4a498c794fff049f7231a9626
|
||||
F Makefile.msc d03cde9073d5752d6ddcaa6807a8bdda277e48f2
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 05c7bd63b96f31cfdef5c766ed91307ac121f5aa
|
||||
@ -83,6 +83,13 @@ F ext/fts3/unicode/mkunicode.tcl 7a9bc018e2962abb79563c5a39fe581fcbf2f675
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/amatch.c 3369b2b544066e620d986f0085d039c77d1ef17f
|
||||
F ext/misc/closure.c fec0c8537c69843e0b7631d500a14c0527962cd6
|
||||
F ext/misc/fuzzer.c fb64a15af978ae73fa9075b9b1dfbe82b8defc6f w src/test_fuzzer.c
|
||||
F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556
|
||||
F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0 w src/test_regexp.c
|
||||
F ext/misc/spellfix.c 8bb699116e36cc5e68d7ddf1810b638a3090c744 w src/test_spellfix.c
|
||||
F ext/misc/wholenumber.c ce362368b9381ea48cbd951ade8df867eeeab014 w src/test_wholenumber.c
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 757abea591d4ff67c0ff4e8f9776aeda86b18c14
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
@ -104,7 +111,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk e97fbfe4c69060560574e1b59c43f4f88a38a0ec
|
||||
F main.mk 9535835509ac58a1902ba85ed77bcce9840d62d4
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@ -182,7 +189,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 83cc2d942ee216bc56956c6e6fadb691c1727fa1
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 6bfbe11e2fef81c5e18d30513ab6c69f171667eb
|
||||
F src/shell.c aca9d94653decd4496846dee0c7ba83eaf96a46d
|
||||
F src/shell.c 5d527e5d08f05ec2c43ff194ea44bf62b974f4c9
|
||||
F src/sqlite.h.in ec279b782bea05db63b8b29481f9642b406004af
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5
|
||||
@ -190,15 +197,15 @@ F src/sqliteInt.h 3585ea1bb8776baa9f2675e9ef3d9170e7aeda29
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 9a716c737590d2f129d71c8fc7065e5aba0e7222
|
||||
F src/test1.c 6784fdacb35c33ba564ef749b62c4718fe515484
|
||||
F src/tclsqlite.c 2ecec9937e69bc17560ad886da35195daa7261b8
|
||||
F src/test1.c e9562428421bf0cdbf11bf5f60ab0cdabee45885
|
||||
F src/test2.c 29e7154112f7448d64204e8d31179cf497ecf425
|
||||
F src/test3.c 96aed72a8e1d542fed127e3e8350ae357712fa82
|
||||
F src/test4.c cea2c55110241e4674e66d476d29c914627999f5
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test6.c a437f76f9874d2563352a7e6cd0d43217663c220
|
||||
F src/test7.c f4b894b7931f8cf9f5cbf37cfa0727703f526a40
|
||||
F src/test8.c 58ea1d9698f3947e4662107ef98f429e84ae20e0
|
||||
F src/test8.c f7e729e3e1973f68e6d98f5aa65046e3e2cb0bad
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 5c95b5d435eaa09d6c0e7d90371c5ca8cd567701
|
||||
@ -209,7 +216,6 @@ F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c 8f786bfd0ad48030cf2a06fb1f050e9c60a150d7
|
||||
F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170
|
||||
F src/test_fuzzer.c 1d26aa965120420bc14807da29d4d4541bfa6148
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
|
||||
F src/test_intarray.c 07ddcebe4097d400ffca362770f1d883c112387a
|
||||
@ -225,11 +231,9 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c 1ec82e02fd3643899e9a5de9684515e84641c91f
|
||||
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
|
||||
F src/test_regexp.c 06ae8138d41a793330f62351283dd6f6f21104f4
|
||||
F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
|
||||
F src/test_spellfix.c 56dfa6d583ac34f61af0834d7b58d674e7e18e13
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
@ -238,7 +242,6 @@ F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4
|
||||
F src/test_vfs.c 8e6087a8b3dcc260282074b0efba14b76311120c
|
||||
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
||||
F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
|
||||
F src/trigger.c cd95ac64efa60e39faf9b5597443192ff27a22fa
|
||||
@ -260,7 +263,7 @@ F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
|
||||
F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887
|
||||
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
|
||||
F src/where.c d54e63087b52c309550aa2defdb20ef27add9f9a
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
@ -275,7 +278,7 @@ F test/analyze3.test c3c7f6c3951900c188cf94b2d5ee3246d6b3ff89
|
||||
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
|
||||
F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e
|
||||
F test/analyze6.test aa8dae5066bbed35c5f45a507fb87f2d342f2c99
|
||||
F test/analyze7.test d3587aa5af75c9048d031b94fceca2534fa75d1d
|
||||
F test/analyze7.test bd09e89264c664d8d8d2450b6866dcdfae080a13
|
||||
F test/analyze8.test 4ca170de2ba30ccb1af2c0406803db72262f9691
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
@ -332,6 +335,7 @@ F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
|
||||
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287
|
||||
F test/closure01.test 6194a899cdbba561d0439c0d6cc7bcdf4fc413e7
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
@ -527,8 +531,8 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzer1.test a2e93bb1e19513dd6bf9c63d3d7c4673c983ca19
|
||||
F test/fuzzerfault.test ff2282c81797b6a355f0748d8b54c7287c5d2b25
|
||||
F test/fuzzer1.test 41bd5aa6ae0cf18d06342a4476e3cad98604ae48
|
||||
F test/fuzzerfault.test f96773292b82ce40f7e6614f04ab2166c4ed3c28
|
||||
F test/hook.test 45cb22b940c3cc0af616ba7430f666e245711a48
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3
|
||||
@ -624,7 +628,7 @@ F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d
|
||||
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
|
||||
F test/memdb.test db5260330676de007be8530d6ecc7c9ab2b06ad3
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f
|
||||
F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
|
||||
@ -684,7 +688,7 @@ F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
|
||||
F test/regexp1.test 5cbb6e7122ca51260d71079cf9245b63b8f64e1a
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
|
||||
F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
|
||||
@ -750,7 +754,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/spellfix.test 52ae2680b1247c52b9e2b2116de3fd26a78e6bd2
|
||||
F test/spellfix.test a85915ab25af7fcfb0d99cb1951e6ef15e26202c
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
@ -783,7 +787,7 @@ F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef
|
||||
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
|
||||
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
|
||||
F test/tkt-2a5629202f.test 1ab32e084e9fc3d36be6dee2617530846a0eb0b6
|
||||
F test/tkt-2d1a5c67d.test b028a811049eb472cb2d3a43fc8ce4f6894eebda
|
||||
F test/tkt-2d1a5c67d.test d371279946622698ab393ff88cad9f5f6d82960b
|
||||
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
|
||||
F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58
|
||||
F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac
|
||||
@ -1009,7 +1013,7 @@ F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test e7f77fded01dfcdf92ac2c5400f1e35d7a21463c
|
||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||
F tool/build-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x
|
||||
F tool/build-shell.sh a9c34a606e2e522ba9eeca1e07090f67dce8c912
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
@ -1054,7 +1058,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P f136bd95824dc95b9e6acdc4d55db263ba13fbaa
|
||||
R 35e39801836ac191fc1f292f3b81674a
|
||||
P 39b4e6ff9316cc78ea88349091e195b8104d1e9e 84018099c8715b982cd24ce9221f93c7379e8c08
|
||||
R dffac967ebf5545ada46cf15534fed7e
|
||||
U drh
|
||||
Z 424df927045edc37db2bc00e1032f86c
|
||||
Z d8995ab3eecb48f05ff755314fd194c9
|
||||
|
@ -1 +1 @@
|
||||
39b4e6ff9316cc78ea88349091e195b8104d1e9e
|
||||
bbe607c7d17c50b667990360e2ccfab8dd22f161
|
12
src/shell.c
12
src/shell.c
@ -1480,18 +1480,6 @@ static void open_db(struct callback_data *p){
|
||||
}
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
sqlite3_enable_load_extension(p->db, 1);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_REGEXP
|
||||
{
|
||||
extern int sqlite3_add_regexp_func(sqlite3*);
|
||||
sqlite3_add_regexp_func(db);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SPELLFIX
|
||||
{
|
||||
extern int sqlite3_spellfix1_register(sqlite3*);
|
||||
sqlite3_spellfix1_register(db);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -3683,9 +3683,6 @@ static void init_all(Tcl_Interp *interp){
|
||||
extern int Sqlitemultiplex_Init(Tcl_Interp*);
|
||||
extern int SqliteSuperlock_Init(Tcl_Interp*);
|
||||
extern int SqlitetestSyscall_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestfuzzer_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestwholenumber_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestregexp_Init(Tcl_Interp*);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
|
||||
@ -3728,9 +3725,6 @@ static void init_all(Tcl_Interp *interp){
|
||||
Sqlitemultiplex_Init(interp);
|
||||
SqliteSuperlock_Init(interp);
|
||||
SqlitetestSyscall_Init(interp);
|
||||
Sqlitetestfuzzer_Init(interp);
|
||||
Sqlitetestwholenumber_Init(interp);
|
||||
Sqlitetestregexp_Init(interp);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
Sqlitetestfts3_Init(interp);
|
||||
|
60
src/test1.c
60
src/test1.c
@ -6045,6 +6045,65 @@ static int optimization_control(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
/*
|
||||
** load_static_extension DB NAME
|
||||
**
|
||||
** Load an extension that is statically linked.
|
||||
*/
|
||||
static int tclLoadStaticExtensionCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
static const struct {
|
||||
const char *zExtName;
|
||||
int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
} aExtension[] = {
|
||||
{ "amatch", sqlite3_amatch_init },
|
||||
{ "closure", sqlite3_closure_init },
|
||||
{ "fuzzer", sqlite3_fuzzer_init },
|
||||
{ "ieee754", sqlite3_ieee_init },
|
||||
{ "regexp", sqlite3_regexp_init },
|
||||
{ "spellfix", sqlite3_spellfix_init },
|
||||
{ "wholenumber", sqlite3_wholenumber_init },
|
||||
};
|
||||
sqlite3 *db;
|
||||
const char *zName;
|
||||
int i, rc;
|
||||
char *zErrMsg = 0;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB NAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zName = Tcl_GetString(objv[2]);
|
||||
for(i=0; i<ArraySize(aExtension); i++){
|
||||
if( strcmp(zName, aExtension[i].zExtName)==0 ) break;
|
||||
}
|
||||
if( i>=ArraySize(aExtension) ){
|
||||
Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = aExtension[i].pInit(db, &zErrMsg, 0);
|
||||
if( rc!=SQLITE_OK || zErrMsg ){
|
||||
Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg,
|
||||
(char*)0);
|
||||
sqlite3_free(zErrMsg);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
@ -6266,6 +6325,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#if SQLITE_OS_UNIX
|
||||
{ "getrusage", test_getrusage },
|
||||
#endif
|
||||
{ "load_static_extension", tclLoadStaticExtensionCmd },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
|
24
src/test8.c
24
src/test8.c
@ -1370,29 +1370,6 @@ static int declare_vtab(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#include "test_spellfix.c"
|
||||
|
||||
/*
|
||||
** Register the spellfix virtual table module.
|
||||
*/
|
||||
static int register_spellfix_module(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
|
||||
sqlite3_spellfix1_register(db);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
/*
|
||||
@ -1406,7 +1383,6 @@ int Sqlitetest8_Init(Tcl_Interp *interp){
|
||||
void *clientData;
|
||||
} aObjCmd[] = {
|
||||
{ "register_echo_module", register_echo_module, 0 },
|
||||
{ "register_spellfix_module", register_spellfix_module, 0 },
|
||||
{ "sqlite3_declare_vtab", declare_vtab, 0 },
|
||||
};
|
||||
int i;
|
||||
|
@ -150,7 +150,7 @@ db close
|
||||
forcedelete test.db
|
||||
do_test 8_3_names-5.0 {
|
||||
sqlite3 db file:./test.db?8_3_names=1
|
||||
register_wholenumber_module db
|
||||
load_static_extension db wholenumber
|
||||
db eval {
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE t1(x);
|
||||
@ -160,7 +160,7 @@ do_test 8_3_names-5.0 {
|
||||
UPDATE t1 SET x=x*2;
|
||||
}
|
||||
sqlite3 db2 file:./test.db?8_3_names=1
|
||||
register_wholenumber_module db2
|
||||
load_static_extension db2 wholenumber
|
||||
db2 eval {
|
||||
BEGIN;
|
||||
SELECT sum(x) FROM t1;
|
||||
|
@ -26,7 +26,7 @@ ifcapable {!analyze||!vtab} {
|
||||
# Generate some test data
|
||||
#
|
||||
do_test analyze7-1.0 {
|
||||
register_wholenumber_module db
|
||||
load_static_extension db wholenumber
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
|
224
test/closure01.test
Normal file
224
test/closure01.test
Normal file
@ -0,0 +1,224 @@
|
||||
# 2013-04-25
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for transitive_closure virtual table.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix closure01
|
||||
|
||||
load_static_extension db closure
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y INTEGER);
|
||||
CREATE INDEX t1y ON t1(y);
|
||||
INSERT INTO t1(x) VALUES(1),(2);
|
||||
INSERT INTO t1(x) SELECT x+2 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+4 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+8 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+16 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+32 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+64 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+128 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+256 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+512 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+1024 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+2048 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+4096 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+8192 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+16384 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+32768 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+65536 FROM t1;
|
||||
UPDATE t1 SET y=x/2 WHERE x>1;
|
||||
COMMIT;
|
||||
CREATE VIRTUAL TABLE cx
|
||||
USING transitive_closure(tablename=t1, idcolumn=x, parentcolumn=y);
|
||||
} {}
|
||||
|
||||
# The entire table
|
||||
do_execsql_test 1.1 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 GROUP BY depth ORDER BY 1;
|
||||
} {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/}
|
||||
|
||||
# descendents of 32768
|
||||
do_execsql_test 1.2 {
|
||||
SELECT * FROM cx WHERE root=32768 ORDER BY id;
|
||||
} {32768 0 65536 1 65537 1 131072 2}
|
||||
|
||||
# descendents of 16384
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM cx WHERE root=16384 AND depth<=2 ORDER BY id;
|
||||
} {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2}
|
||||
|
||||
# children of 16384
|
||||
do_execsql_test 1.4 {
|
||||
SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx
|
||||
WHERE root=16384
|
||||
AND depth=1
|
||||
ORDER BY id;
|
||||
} {32768 1 {} t1 x y 32769 1 {} t1 x y}
|
||||
|
||||
# great-grandparent of 16384
|
||||
do_execsql_test 1.5 {
|
||||
SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx
|
||||
WHERE root=16384
|
||||
AND depth=3
|
||||
AND idcolumn='Y'
|
||||
AND parentcolumn='X';
|
||||
} {2048 3 {} t1 Y X}
|
||||
|
||||
# depth<5
|
||||
do_execsql_test 1.6 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 AND depth<5
|
||||
GROUP BY depth ORDER BY 1;
|
||||
} {1 0 2 1 4 2 8 3 16 4}
|
||||
|
||||
# depth<=5
|
||||
do_execsql_test 1.7 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 AND depth<=5
|
||||
GROUP BY depth ORDER BY 1;
|
||||
} {1 0 2 1 4 2 8 3 16 4 32 5}
|
||||
|
||||
# depth==5
|
||||
do_execsql_test 1.8 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 AND depth=5
|
||||
GROUP BY depth ORDER BY 1;
|
||||
} {32 5}
|
||||
|
||||
# depth BETWEEN 3 AND 5
|
||||
do_execsql_test 1.9 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 AND depth BETWEEN 3 AND 5
|
||||
GROUP BY depth ORDER BY 1;
|
||||
} {8 3 16 4 32 5}
|
||||
|
||||
# depth==5 with min() and max()
|
||||
do_execsql_test 1.10 {
|
||||
SELECT count(*), min(id), max(id) FROM cx WHERE root=1 AND depth=5;
|
||||
} {32 32 63}
|
||||
|
||||
# Create a much smaller table t2 with only 32 elements
|
||||
db eval {
|
||||
CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER);
|
||||
INSERT INTO t2 SELECT x, y FROM t1 WHERE x<32;
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
CREATE VIRTUAL TABLE c2
|
||||
USING transitive_closure(tablename=t2, idcolumn=x, parentcolumn=y);
|
||||
}
|
||||
|
||||
# t2 full-table
|
||||
do_execsql_test 2.1 {
|
||||
SELECT count(*), min(id), max(id) FROM c2 WHERE root=1;
|
||||
} {31 1 31}
|
||||
# t2 root=10
|
||||
do_execsql_test 2.2 {
|
||||
SELECT id FROM c2 WHERE root=10;
|
||||
} {10 20 21}
|
||||
# t2 root=11
|
||||
do_execsql_test 2.3 {
|
||||
SELECT id FROM c2 WHERE root=12;
|
||||
} {12 24 25}
|
||||
# t2 root IN [10,12]
|
||||
do_execsql_test 2.4 {
|
||||
SELECT id FROM c2 WHERE root IN (10,12) ORDER BY id;
|
||||
} {10 12 20 21 24 25}
|
||||
# t2 root IN [10,12] (sorted)
|
||||
do_execsql_test 2.5 {
|
||||
SELECT id FROM c2 WHERE root IN (10,12) ORDER BY +id;
|
||||
} {10 12 20 21 24 25}
|
||||
|
||||
# t2 c2up from 20
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE c2up USING transitive_closure(
|
||||
tablename = t2,
|
||||
idcolumn = y,
|
||||
parentcolumn = x
|
||||
);
|
||||
SELECT id FROM c2up WHERE root=20;
|
||||
} {1 2 5 10 20}
|
||||
|
||||
# cx as c2up
|
||||
do_execsql_test 3.1 {
|
||||
SELECT id FROM cx
|
||||
WHERE root=20
|
||||
AND tablename='t2'
|
||||
AND idcolumn='y'
|
||||
AND parentcolumn='x';
|
||||
} {1 2 5 10 20}
|
||||
|
||||
# t2 first cousins of 20
|
||||
do_execsql_test 3.2 {
|
||||
SELECT DISTINCT id FROM c2
|
||||
WHERE root IN (SELECT id FROM c2up
|
||||
WHERE root=20 AND depth<=2)
|
||||
ORDER BY id;
|
||||
} {5 10 11 20 21 22 23}
|
||||
|
||||
# t2 first cousins of 20
|
||||
do_execsql_test 3.3 {
|
||||
SELECT id FROM c2
|
||||
WHERE root=(SELECT id FROM c2up
|
||||
WHERE root=20 AND depth=2)
|
||||
AND depth=2
|
||||
EXCEPT
|
||||
SELECT id FROM c2
|
||||
WHERE root=(SELECT id FROM c2up
|
||||
WHERE root=20 AND depth=1)
|
||||
AND depth<=1
|
||||
ORDER BY id;
|
||||
} {22 23}
|
||||
|
||||
# missing tablename.
|
||||
do_test 4.1 {
|
||||
catchsql {
|
||||
SELECT id FROM cx
|
||||
WHERE root=20
|
||||
AND tablename='t3'
|
||||
AND idcolumn='y'
|
||||
AND parentcolumn='x';
|
||||
}
|
||||
} {1 {no such table: t3}}
|
||||
|
||||
# missing idcolumn
|
||||
do_test 4.2 {
|
||||
catchsql {
|
||||
SELECT id FROM cx
|
||||
WHERE root=20
|
||||
AND tablename='t2'
|
||||
AND idcolumn='xyz'
|
||||
AND parentcolumn='x';
|
||||
}
|
||||
} {1 {no such column: t2.xyz}}
|
||||
|
||||
# missing parentcolumn
|
||||
do_test 4.3 {
|
||||
catchsql {
|
||||
SELECT id FROM cx
|
||||
WHERE root=20
|
||||
AND tablename='t2'
|
||||
AND idcolumn='x'
|
||||
AND parentcolumn='pqr';
|
||||
}
|
||||
} {1 {no such column: t2.pqr}}
|
||||
|
||||
# generic closure
|
||||
do_execsql_test 5.1 {
|
||||
CREATE VIRTUAL TABLE temp.closure USING transitive_closure;
|
||||
SELECT id FROM closure
|
||||
WHERE root=1
|
||||
AND depth=3
|
||||
AND tablename='t1'
|
||||
AND idcolumn='x'
|
||||
AND parentcolumn='y'
|
||||
ORDER BY id;
|
||||
} {8 9 10 11 12 13 14 15}
|
||||
|
||||
finish_test
|
@ -24,12 +24,7 @@ ifcapable !vtab {
|
||||
|
||||
set ::testprefix fuzzer1
|
||||
|
||||
# Test of test code. Only here to make the coverage metric better.
|
||||
do_test 0.1 {
|
||||
list [catch { register_fuzzer_module a b c } msg] $msg
|
||||
} {1 {wrong # args: should be "register_fuzzer_module DB"}}
|
||||
|
||||
register_fuzzer_module db
|
||||
load_static_extension db fuzzer
|
||||
|
||||
# Check configuration errors.
|
||||
#
|
||||
|
@ -17,7 +17,7 @@ source $testdir/tester.tcl
|
||||
ifcapable !vtab { finish_test ; return }
|
||||
set ::testprefix fuzzerfault
|
||||
|
||||
register_fuzzer_module db
|
||||
load_static_extension db fuzzer
|
||||
|
||||
do_test 1-pre1 {
|
||||
execsql {
|
||||
|
@ -365,7 +365,7 @@ do_test memdb-6.15 {
|
||||
|
||||
ifcapable subquery&&vtab {
|
||||
do_test memdb-7.1 {
|
||||
register_wholenumber_module db
|
||||
load_static_extension db wholenumber
|
||||
execsql {
|
||||
CREATE TABLE t6(x);
|
||||
CREATE VIRTUAL TABLE nums USING wholenumber;
|
||||
|
@ -16,7 +16,7 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test regexp1-1.1 {
|
||||
sqlite3_add_regexp_func db
|
||||
load_static_extension db regexp
|
||||
db eval {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
|
||||
INSERT INTO t1 VALUES(1, 'For since by man came death,');
|
||||
|
@ -16,7 +16,7 @@ set testprefix spellfix
|
||||
|
||||
ifcapable !vtab { finish_test ; return }
|
||||
|
||||
register_spellfix_module db
|
||||
load_static_extension db spellfix
|
||||
|
||||
set vocab {
|
||||
rabbi rabbit rabbits rabble rabid rabies raccoon raccoons race raced racer
|
||||
|
@ -46,7 +46,7 @@ for {set ii 1} {$ii<=10} {incr ii} {
|
||||
db close
|
||||
forcedelete test.db test.db-wal
|
||||
sqlite3 db test.db
|
||||
register_wholenumber_module db
|
||||
load_static_extension db wholenumber
|
||||
db eval {
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE t1(a,b);
|
||||
|
@ -59,7 +59,7 @@ do_test zerodamage-2.0 {
|
||||
}
|
||||
tv filter xDelete
|
||||
tv script xDeleteCallback
|
||||
register_wholenumber_module db
|
||||
load_static_extension db wholenumber
|
||||
db eval {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA journal_mode=DELETE;
|
||||
|
Loading…
Reference in New Issue
Block a user