1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge all recent trunk changes into the sessions branch.

FossilOrigin-Name: 3879ab1b532828fcc12a50a95b6730faebcb69e9
This commit is contained in:
drh
2013-05-03 18:29:22 +00:00
54 changed files with 4100 additions and 417 deletions

View File

@@ -368,7 +368,6 @@ TESTSRC = \
$(TOP)/src/test_devsym.c \ $(TOP)/src/test_devsym.c \
$(TOP)/src/test_fs.c \ $(TOP)/src/test_fs.c \
$(TOP)/src/test_func.c \ $(TOP)/src/test_func.c \
$(TOP)/src/test_fuzzer.c \
$(TOP)/src/test_hexio.c \ $(TOP)/src/test_hexio.c \
$(TOP)/src/test_init.c \ $(TOP)/src/test_init.c \
$(TOP)/src/test_intarray.c \ $(TOP)/src/test_intarray.c \
@@ -380,7 +379,6 @@ TESTSRC = \
$(TOP)/src/test_osinst.c \ $(TOP)/src/test_osinst.c \
$(TOP)/src/test_pcache.c \ $(TOP)/src/test_pcache.c \
$(TOP)/src/test_quota.c \ $(TOP)/src/test_quota.c \
$(TOP)/src/test_regexp.c \
$(TOP)/src/test_rtree.c \ $(TOP)/src/test_rtree.c \
$(TOP)/src/test_schema.c \ $(TOP)/src/test_schema.c \
$(TOP)/src/test_server.c \ $(TOP)/src/test_server.c \
@@ -390,12 +388,23 @@ TESTSRC = \
$(TOP)/src/test_tclvar.c \ $(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \ $(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \ $(TOP)/src/test_vfs.c \
$(TOP)/src/test_wholenumber.c \
$(TOP)/src/test_wsd.c \ $(TOP)/src/test_wsd.c \
$(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_term.c \
$(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/fts3/fts3_test.c \
$(TOP)/ext/session/test_session.c $(TOP)/ext/session/test_session.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/nextchar.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 # Source code to the library files needed by the test fixture
# #
TESTSRC2 = \ TESTSRC2 = \

View File

@@ -689,7 +689,6 @@ TESTSRC = \
$(TOP)\src\test_devsym.c \ $(TOP)\src\test_devsym.c \
$(TOP)\src\test_fs.c \ $(TOP)\src\test_fs.c \
$(TOP)\src\test_func.c \ $(TOP)\src\test_func.c \
$(TOP)\src\test_fuzzer.c \
$(TOP)\src\test_hexio.c \ $(TOP)\src\test_hexio.c \
$(TOP)\src\test_init.c \ $(TOP)\src\test_init.c \
$(TOP)\src\test_intarray.c \ $(TOP)\src\test_intarray.c \
@@ -701,7 +700,6 @@ TESTSRC = \
$(TOP)\src\test_osinst.c \ $(TOP)\src\test_osinst.c \
$(TOP)\src\test_pcache.c \ $(TOP)\src\test_pcache.c \
$(TOP)\src\test_quota.c \ $(TOP)\src\test_quota.c \
$(TOP)\src\test_regexp.c \
$(TOP)\src\test_rtree.c \ $(TOP)\src\test_rtree.c \
$(TOP)\src\test_schema.c \ $(TOP)\src\test_schema.c \
$(TOP)\src\test_server.c \ $(TOP)\src\test_server.c \
@@ -711,12 +709,24 @@ TESTSRC = \
$(TOP)\src\test_tclvar.c \ $(TOP)\src\test_tclvar.c \
$(TOP)\src\test_thread.c \ $(TOP)\src\test_thread.c \
$(TOP)\src\test_vfs.c \ $(TOP)\src\test_vfs.c \
$(TOP)\src\test_wholenumber.c \
$(TOP)\src\test_wsd.c \ $(TOP)\src\test_wsd.c \
$(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_term.c \
$(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\fts3\fts3_test.c \
$(TOP)\ext\session\test_session.c $(TOP)\ext\session\test_session.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\nextchar.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 # Source code to the library files needed by the test fixture
# (non-amalgamation) # (non-amalgamation)
# #
@@ -1227,8 +1237,8 @@ sqlite3session.lo: $(TOP)\ext\session\sqlite3sesion.c $(HDR) $(EXTHDR)
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.lib TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) libsqlite3.lib
TESTFIXTURE_SRC1 = $(TESTSRC3) sqlite3.c TESTFIXTURE_SRC1 = $(TESTEXT) $(TESTSRC3) sqlite3.c
!IF $(USE_AMALGAMATION)==0 !IF $(USE_AMALGAMATION)==0
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
!ELSE !ELSE

View File

@@ -2975,14 +2975,12 @@ static int fts3FilterMethod(
pCsr->iLangid = 0; pCsr->iLangid = 0;
if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]); if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
assert( p->base.zErrMsg==0 );
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
&p->base.zErrMsg
); );
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( rc==SQLITE_ERROR ){
static const char *zErr = "malformed MATCH expression: [%s]";
p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
}
return rc; return rc;
} }

View File

@@ -524,7 +524,7 @@ void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
/* fts3_expr.c */ /* fts3_expr.c */
int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
char **, int, int, int, const char *, int, Fts3Expr ** char **, int, int, int, const char *, int, Fts3Expr **, char **
); );
void sqlite3Fts3ExprFree(Fts3Expr *); void sqlite3Fts3ExprFree(Fts3Expr *);
#ifdef SQLITE_TEST #ifdef SQLITE_TEST

View File

@@ -640,8 +640,10 @@ static int fts3ExprParse(
} }
pNot->eType = FTSQUERY_NOT; pNot->eType = FTSQUERY_NOT;
pNot->pRight = p; pNot->pRight = p;
p->pParent = pNot;
if( pNotBranch ){ if( pNotBranch ){
pNot->pLeft = pNotBranch; pNot->pLeft = pNotBranch;
pNotBranch->pParent = pNot;
} }
pNotBranch = pNot; pNotBranch = pNot;
p = pPrev; p = pPrev;
@@ -729,6 +731,7 @@ static int fts3ExprParse(
pIter = pIter->pLeft; pIter = pIter->pLeft;
} }
pIter->pLeft = pRet; pIter->pLeft = pRet;
pRet->pParent = pIter;
pRet = pNotBranch; pRet = pNotBranch;
} }
} }
@@ -745,6 +748,222 @@ exprparse_out:
return rc; return rc;
} }
/*
** Return SQLITE_ERROR if the maximum depth of the expression tree passed
** as the only argument is more than nMaxDepth.
*/
static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
int rc = SQLITE_OK;
if( p ){
if( nMaxDepth<0 ){
rc = SQLITE_TOOBIG;
}else{
rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1);
if( rc==SQLITE_OK ){
rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1);
}
}
}
return rc;
}
/*
** This function attempts to transform the expression tree at (*pp) to
** an equivalent but more balanced form. The tree is modified in place.
** If successful, SQLITE_OK is returned and (*pp) set to point to the
** new root expression node.
**
** nMaxDepth is the maximum allowable depth of the balanced sub-tree.
**
** Otherwise, if an error occurs, an SQLite error code is returned and
** expression (*pp) freed.
*/
static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
int rc = SQLITE_OK; /* Return code */
Fts3Expr *pRoot = *pp; /* Initial root node */
Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */
int eType = pRoot->eType; /* Type of node in this tree */
if( nMaxDepth==0 ){
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
Fts3Expr **apLeaf;
apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
if( 0==apLeaf ){
rc = SQLITE_NOMEM;
}else{
memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
}
if( rc==SQLITE_OK ){
int i;
Fts3Expr *p;
/* Set $p to point to the left-most leaf in the tree of eType nodes. */
for(p=pRoot; p->eType==eType; p=p->pLeft){
assert( p->pParent==0 || p->pParent->pLeft==p );
assert( p->pLeft && p->pRight );
}
/* This loop runs once for each leaf in the tree of eType nodes. */
while( 1 ){
int iLvl;
Fts3Expr *pParent = p->pParent; /* Current parent of p */
assert( pParent==0 || pParent->pLeft==p );
p->pParent = 0;
if( pParent ){
pParent->pLeft = 0;
}else{
pRoot = 0;
}
rc = fts3ExprBalance(&p, nMaxDepth-1);
if( rc!=SQLITE_OK ) break;
for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
if( apLeaf[iLvl]==0 ){
apLeaf[iLvl] = p;
p = 0;
}else{
assert( pFree );
pFree->pLeft = apLeaf[iLvl];
pFree->pRight = p;
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
apLeaf[iLvl] = 0;
}
}
if( p ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_TOOBIG;
break;
}
/* If that was the last leaf node, break out of the loop */
if( pParent==0 ) break;
/* Set $p to point to the next leaf in the tree of eType nodes */
for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
/* Remove pParent from the original tree. */
assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
pParent->pRight->pParent = pParent->pParent;
if( pParent->pParent ){
pParent->pParent->pLeft = pParent->pRight;
}else{
assert( pParent==pRoot );
pRoot = pParent->pRight;
}
/* Link pParent into the free node list. It will be used as an
** internal node of the new tree. */
pParent->pParent = pFree;
pFree = pParent;
}
if( rc==SQLITE_OK ){
p = 0;
for(i=0; i<nMaxDepth; i++){
if( apLeaf[i] ){
if( p==0 ){
p = apLeaf[i];
p->pParent = 0;
}else{
pFree->pRight = p;
pFree->pLeft = apLeaf[i];
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
}
}
}
pRoot = p;
}else{
/* An error occurred. Delete the contents of the apLeaf[] array
** and pFree list. Everything else is cleaned up by the call to
** sqlite3Fts3ExprFree(pRoot) below. */
Fts3Expr *pDel;
for(i=0; i<nMaxDepth; i++){
sqlite3Fts3ExprFree(apLeaf[i]);
}
while( (pDel=pFree)!=0 ){
pFree = pDel->pParent;
sqlite3_free(pDel);
}
}
assert( pFree==0 );
sqlite3_free( apLeaf );
}
}
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRoot);
pRoot = 0;
}
*pp = pRoot;
return rc;
}
/*
** This function is similar to sqlite3Fts3ExprParse(), with the following
** differences:
**
** 1. It does not do expression rebalancing.
** 2. It does not check that the expression does not exceed the
** maximum allowable depth.
** 3. Even if it fails, *ppExpr may still be set to point to an
** expression tree. It should be deleted using sqlite3Fts3ExprFree()
** in this case.
*/
static int fts3ExprParseUnbalanced(
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
int iLangid, /* Language id for tokenizer */
char **azCol, /* Array of column names for fts3 table */
int bFts4, /* True to allow FTS4-only syntax */
int nCol, /* Number of entries in azCol[] */
int iDefaultCol, /* Default column to query */
const char *z, int n, /* Text of MATCH query */
Fts3Expr **ppExpr /* OUT: Parsed query structure */
){
int nParsed;
int rc;
ParseContext sParse;
memset(&sParse, 0, sizeof(ParseContext));
sParse.pTokenizer = pTokenizer;
sParse.iLangid = iLangid;
sParse.azCol = (const char **)azCol;
sParse.nCol = nCol;
sParse.iDefaultCol = iDefaultCol;
sParse.bFts4 = bFts4;
if( z==0 ){
*ppExpr = 0;
return SQLITE_OK;
}
if( n<0 ){
n = (int)strlen(z);
}
rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed);
assert( rc==SQLITE_OK || *ppExpr==0 );
/* Check for mismatched parenthesis */
if( rc==SQLITE_OK && sParse.nNest ){
rc = SQLITE_ERROR;
}
return rc;
}
/* /*
** Parameters z and n contain a pointer to and length of a buffer containing ** Parameters z and n contain a pointer to and length of a buffer containing
** an fts3 query expression, respectively. This function attempts to parse the ** an fts3 query expression, respectively. This function attempts to parse the
@@ -777,49 +996,74 @@ int sqlite3Fts3ExprParse(
int nCol, /* Number of entries in azCol[] */ int nCol, /* Number of entries in azCol[] */
int iDefaultCol, /* Default column to query */ int iDefaultCol, /* Default column to query */
const char *z, int n, /* Text of MATCH query */ const char *z, int n, /* Text of MATCH query */
Fts3Expr **ppExpr /* OUT: Parsed query structure */ Fts3Expr **ppExpr, /* OUT: Parsed query structure */
char **pzErr /* OUT: Error message (sqlite3_malloc) */
){ ){
int nParsed; static const int MAX_EXPR_DEPTH = 12;
int rc; int rc = fts3ExprParseUnbalanced(
ParseContext sParse; pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr
);
memset(&sParse, 0, sizeof(ParseContext)); /* Rebalance the expression. And check that its depth does not exceed
sParse.pTokenizer = pTokenizer; ** MAX_EXPR_DEPTH. */
sParse.iLangid = iLangid; if( rc==SQLITE_OK && *ppExpr ){
sParse.azCol = (const char **)azCol; rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH);
sParse.nCol = nCol; if( rc==SQLITE_OK ){
sParse.iDefaultCol = iDefaultCol; rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH);
sParse.bFts4 = bFts4; }
if( z==0 ){
*ppExpr = 0;
return SQLITE_OK;
} }
if( n<0 ){
n = (int)strlen(z);
}
rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed);
/* Check for mismatched parenthesis */ if( rc!=SQLITE_OK ){
if( rc==SQLITE_OK && sParse.nNest ){
rc = SQLITE_ERROR;
sqlite3Fts3ExprFree(*ppExpr); sqlite3Fts3ExprFree(*ppExpr);
*ppExpr = 0; *ppExpr = 0;
if( rc==SQLITE_TOOBIG ){
*pzErr = sqlite3_mprintf(
"FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH
);
rc = SQLITE_ERROR;
}else if( rc==SQLITE_ERROR ){
*pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z);
}
} }
return rc; return rc;
} }
/* /*
** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). ** Free a single node of an expression tree.
*/ */
void sqlite3Fts3ExprFree(Fts3Expr *p){ static void fts3FreeExprNode(Fts3Expr *p){
if( p ){ assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); sqlite3Fts3EvalPhraseCleanup(p->pPhrase);
sqlite3Fts3ExprFree(p->pLeft); sqlite3_free(p->aMI);
sqlite3Fts3ExprFree(p->pRight); sqlite3_free(p);
sqlite3Fts3EvalPhraseCleanup(p->pPhrase); }
sqlite3_free(p->aMI);
sqlite3_free(p); /*
** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse().
**
** This function would be simpler if it recursively called itself. But
** that would mean passing a sufficiently large expression to ExprParse()
** could cause a stack overflow.
*/
void sqlite3Fts3ExprFree(Fts3Expr *pDel){
Fts3Expr *p;
assert( pDel==0 || pDel->pParent==0 );
for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){
assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft );
}
while( p ){
Fts3Expr *pParent = p->pParent;
fts3FreeExprNode(p);
if( pParent && p==pParent->pLeft && pParent->pRight ){
p = pParent->pRight;
while( p && (p->pLeft || p->pRight) ){
assert( p==p->pParent->pRight || p==p->pParent->pLeft );
p = (p->pLeft ? p->pLeft : p->pRight);
}
}else{
p = pParent;
}
} }
} }
@@ -871,6 +1115,9 @@ static int queryTestTokenizer(
** the returned expression text and then freed using sqlite3_free(). ** the returned expression text and then freed using sqlite3_free().
*/ */
static char *exprToString(Fts3Expr *pExpr, char *zBuf){ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
if( pExpr==0 ){
return sqlite3_mprintf("");
}
switch( pExpr->eType ){ switch( pExpr->eType ){
case FTSQUERY_PHRASE: { case FTSQUERY_PHRASE: {
Fts3Phrase *pPhrase = pExpr->pPhrase; Fts3Phrase *pPhrase = pExpr->pPhrase;
@@ -978,10 +1225,21 @@ static void fts3ExprTest(
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
} }
rc = sqlite3Fts3ExprParse( if( sqlite3_user_data(context) ){
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr char *zDummy = 0;
); rc = sqlite3Fts3ExprParse(
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy
);
assert( rc==SQLITE_OK || pExpr==0 );
sqlite3_free(zDummy);
}else{
rc = fts3ExprParseUnbalanced(
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
);
}
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
sqlite3Fts3ExprFree(pExpr);
sqlite3_result_error(context, "Error parsing expression", -1); sqlite3_result_error(context, "Error parsing expression", -1);
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context); sqlite3_result_error_nomem(context);
@@ -1004,9 +1262,15 @@ exprtest_out:
** with database connection db. ** with database connection db.
*/ */
int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
return sqlite3_create_function( int rc = sqlite3_create_function(
db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0
); );
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "fts3_exprtest_rebalance",
-1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0
);
}
return rc;
} }
#endif #endif

1477
ext/misc/amatch.c Normal file

File diff suppressed because it is too large Load Diff

942
ext/misc/closure.c Normal file
View 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;
}

View File

@@ -141,13 +141,14 @@
** of the strings in the second or third column of the fuzzer data table ** 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. ** 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 SQLITE_DEBUG is not defined, disable assert statements. */
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) #if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG # define NDEBUG
#endif #endif
#include "sqlite3.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@@ -1155,61 +1156,16 @@ static sqlite3_module fuzzerModule = {
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
/* #ifdef _WIN32
** Register the fuzzer virtual table __declspec(dllexport)
*/
int fuzzer_register(sqlite3 *db){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
#endif #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; 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
View 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;
}

265
ext/misc/nextchar.c Normal file
View File

@@ -0,0 +1,265 @@
/*
** 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) SQL function.
**
** The next_char(A,T,F,H) function finds all valid "next" characters for
** string A given the vocabulary in T.F. The T.F field should be indexed.
** 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.
**
** 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');
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <string.h>
/*
** 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; i<p->nUsed; 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;
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
){
zSql = sqlite3_mprintf(
"SELECT \"%w\" FROM \"%w\""
" WHERE \"%w\">=(?1 || ?2)"
" AND \"%w\"<=(?1 || char(1114111))" /* 1114111 == 0x10ffff */
" ORDER BY 1 ASC LIMIT 1",
zField, zTable, zField, zField);
}else{
zSql = sqlite3_mprintf(
"SELECT \"%w\" FROM \"%w\""
" WHERE \"%w\">=(?1 || ?2)"
" AND \"%w\"<=(?1 || char(1114111))" /* 1114111 == 0x10ffff */
" AND (%s)"
" ORDER BY 1 ASC LIMIT 1",
zField, zTable, zField, zField, zWhere);
}
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<c.nUsed; i++){
n += writeUtf8(pRes+n, c.aResult[i]);
}
pRes[n] = 0;
sqlite3_result_text(context, (const char*)pRes, n, sqlite3_free);
}
}
sqlite3_finalize(c.pStmt);
sqlite3_free(c.aResult);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_nextchar_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, "next_char", 3, SQLITE_UTF8, 0,
nextCharFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0,
nextCharFunc, 0, 0);
}
return rc;
}

View File

@@ -12,7 +12,16 @@
** **
** The code in this file implements a compact but reasonably ** The code in this file implements a compact but reasonably
** efficient regular-expression matcher for posix extended regular ** 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* zero or more occurrences of X
** X+ one or more occurrences of X ** X+ one or more occurrences of X
@@ -49,7 +58,17 @@
*/ */
#include <string.h> #include <string.h>
#include <stdlib.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 */ /* The end-of-input character */
#define RE_EOF 0 /* End of input */ #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 /* Run a compiled regular expression on the zero-terminated input
** string zIn[]. Return true on a match and false if there is no match. ** 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; ReStateSet aStateSet[2], *pThis, *pNext;
ReStateNumber aSpace[100]; ReStateNumber aSpace[100];
ReStateNumber *pToFree; 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. ** 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){ #ifdef _WIN32
return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, __declspec(dllexport)
re_sql_func, 0, 0); #endif
} int sqlite3_regexp_init(
sqlite3 *db,
char **pzErrMsg,
/***************************** Test Code ***********************************/ const sqlite3_api_routines *pApi
#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[]
){ ){
sqlite3 *db; int rc = SQLITE_OK;
if( objc!=2 ){ SQLITE_EXTENSION_INIT2(pApi);
Tcl_WrongNumArgs(interp, 1, objv, "DB"); rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
return TCL_ERROR; re_sql_func, 0, 0);
} return rc;
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
sqlite3_add_regexp_func(db);
return TCL_OK;
} }
/* 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 *******************************/

View File

@@ -12,23 +12,22 @@
** **
** This module implements the spellfix1 VIRTUAL TABLE that can be used ** This module implements the spellfix1 VIRTUAL TABLE that can be used
** to search a large vocabulary for close matches. See separate ** to search a large vocabulary for close matches. See separate
** documentation files (spellfix1.wiki and editdist3.wiki) for details. ** documentation (http://www.sqlite.org/spellfix1.html) for details.
*/ */
#if SQLITE_CORE #include "sqlite3ext.h"
# include "sqliteInt.h" SQLITE_EXTENSION_INIT1
#else
#ifndef SQLITE_AMALGAMATION
# include <string.h> # include <string.h>
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include "sqlite3ext.h"
# include <assert.h> # include <assert.h>
# define ALWAYS(X) 1 # define ALWAYS(X) 1
# define NEVER(X) 0 # define NEVER(X) 0
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned short u16; typedef unsigned short u16;
SQLITE_EXTENSION_INIT1 # include <ctype.h>
#endif /* !SQLITE_CORE */ #endif
#include <ctype.h>
/* /*
** Character classes for ASCII characters: ** Character classes for ASCII characters:
@@ -2822,21 +2821,13 @@ static int spellfix1Register(sqlite3 *db){
return rc; 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. ** Extension load function.
*/ */
int sqlite3_spellfix1_init( #ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_spellfix_init(
sqlite3 *db, sqlite3 *db,
char **pzErrMsg, char **pzErrMsg,
const sqlite3_api_routines *pApi const sqlite3_api_routines *pApi
@@ -2844,4 +2835,3 @@ int sqlite3_spellfix1_init(
SQLITE_EXTENSION_INIT2(pApi); SQLITE_EXTENSION_INIT2(pApi);
return spellfix1Register(db); return spellfix1Register(db);
} }
#endif /* !SQLITE_CORE */

View File

@@ -22,7 +22,8 @@
** **
** 1 2 3 4 5 6 7 8 9 ** 1 2 3 4 5 6 7 8 9
*/ */
#include "sqlite3.h" #include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@@ -250,62 +251,18 @@ static sqlite3_module wholenumberModule = {
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifdef _WIN32
/* __declspec(dllexport)
** Register the wholenumber virtual table #endif
*/ int sqlite3_wholenumber_init(
int wholenumber_register(sqlite3 *db){ sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK; int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0); rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0);
#endif #endif
return rc; 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 */

26
magic.txt Normal file
View File

@@ -0,0 +1,26 @@
# This file contains suggested magic(5) text for the unix file(1)
# utility for recognizing SQLite3 databases.
#
# When SQLite is used as an application file format, it is desirable to
# have file(1) recognize the database file as being with the specific
# application. You can set the application_id for a database file
# using:
#
# PRAGMA application_id = INTEGER;
#
# INTEGER can be any signed 32-bit integer. That integer is written as
# a 4-byte big-endian integer into offset 68 of the database header.
#
# The Monotone application used "PRAGMA user_version=1598903374;" to set
# its identifier long before "PRAGMA application_id" became available.
# The user_version is very similar to application_id except that it is
# stored at offset 68 instead of offset 60. The application_id pragma
# is preferred. The rule using offset 60 for Monotone is for historical
# compatibility only.
#
0 string =SQLite\ format\ 3
>68 belong =0x0f055111 Fossil repository -
>68 belong =0x0f055112 Fossil checkout -
>68 belong =0x0f055113 Fossil global configuration -
>60 belong =0x5f4d544e Monotone source repository -
>0 string =SQLite SQLite3 database

16
main.mk
View File

@@ -248,7 +248,6 @@ TESTSRC = \
$(TOP)/src/test_devsym.c \ $(TOP)/src/test_devsym.c \
$(TOP)/src/test_fs.c \ $(TOP)/src/test_fs.c \
$(TOP)/src/test_func.c \ $(TOP)/src/test_func.c \
$(TOP)/src/test_fuzzer.c \
$(TOP)/src/test_hexio.c \ $(TOP)/src/test_hexio.c \
$(TOP)/src/test_init.c \ $(TOP)/src/test_init.c \
$(TOP)/src/test_intarray.c \ $(TOP)/src/test_intarray.c \
@@ -260,7 +259,6 @@ TESTSRC = \
$(TOP)/src/test_osinst.c \ $(TOP)/src/test_osinst.c \
$(TOP)/src/test_pcache.c \ $(TOP)/src/test_pcache.c \
$(TOP)/src/test_quota.c \ $(TOP)/src/test_quota.c \
$(TOP)/src/test_regexp.c \
$(TOP)/src/test_rtree.c \ $(TOP)/src/test_rtree.c \
$(TOP)/src/test_schema.c \ $(TOP)/src/test_schema.c \
$(TOP)/src/test_server.c \ $(TOP)/src/test_server.c \
@@ -271,9 +269,21 @@ TESTSRC = \
$(TOP)/src/test_tclvar.c \ $(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \ $(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \ $(TOP)/src/test_vfs.c \
$(TOP)/src/test_wholenumber.c \
$(TOP)/src/test_wsd.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/nextchar.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/fts2/fts2_tokenizer.c
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

107
manifest
View File

@@ -1,9 +1,9 @@
C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch. C Merge\sall\srecent\strunk\schanges\sinto\sthe\ssessions\sbranch.
D 2013-04-22T23:59:06.075 D 2013-05-03T18:29:22.159
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 4db477715e5d66fdcbb4f7a0870d10b0adbe007e F Makefile.in e2acdd75b30e5f2fd8739c923c746d9d2228fe9a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc 95b9e9992abcb32dda9ad7460bb1c4a3e0985909 F Makefile.msc af9891d1f609607a54524f4ccabcbe5c38e4a8e3
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315 F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 0dee4d2e0c64791ff0085277424fb5c07d79fc9a F VERSION 0dee4d2e0c64791ff0085277424fb5c07d79fc9a
@@ -55,11 +55,11 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 784aadfb4c2a217c3eb1feaecac924989f29728f F ext/fts3/fts3.c 5c3d44d16701cc4bc81ebf0bb9d5bff136d42de0
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h 352c8a83ee4c6a14ced1759a39dd890ab947cbe0 F ext/fts3/fts3Int.h 23ea0a2bb7258d2539376ed60220cce28ba25765
F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd
F ext/fts3/fts3_expr.c 6cb4410f87676ae633bd7923bbc78526cb839c4d F ext/fts3/fts3_expr.c 44b4a3c4983ddbf1958c4a40468efb4ff2e0549a
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5 F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
@@ -83,6 +83,14 @@ F ext/fts3/unicode/mkunicode.tcl 7a9bc018e2962abb79563c5a39fe581fcbf2f675
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 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/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e
F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0 w src/test_regexp.c
F ext/misc/spellfix.c f9d24a2b2617cee143b7841b453e4e1fd8f189cc w src/test_spellfix.c
F ext/misc/wholenumber.c ce362368b9381ea48cbd951ade8df867eeeab014 w src/test_wholenumber.c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 757abea591d4ff67c0ff4e8f9776aeda86b18c14 F ext/rtree/rtree.c 757abea591d4ff67c0ff4e8f9776aeda86b18c14
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
@@ -116,7 +124,8 @@ F ext/session/sqlite3session.h f374c9c4c96e08f67ac418871c29d423245c7673
F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99 F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk 88fb64131032933d96fd65039a6dd9140beb2566 F magic.txt 291863ca976425e2e7bf3f775eb98ece4dd120f6
F main.mk 06e980ed70c3fa4c27c35ff38735af6e05a64304
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -141,7 +150,7 @@ F src/backup.c b266767351ae2d847716c56fcb2a1fea7c761c03
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 480a6d255cc4f066029daf23dd54acf152cd0e13 F src/btree.c 480a6d255cc4f066029daf23dd54acf152cd0e13
F src/btree.h d9490cd37aaeb530a41b07f06e1262950b1be916 F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
F src/build.c 083da8466fd7e481cb8bd5264398f537507f6176 F src/build.c 083da8466fd7e481cb8bd5264398f537507f6176
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
@@ -149,7 +158,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 39a770e9729b1acd2de347f8f614584841d0083e F src/delete.c 39a770e9729b1acd2de347f8f614584841d0083e
F src/expr.c 48048fca951eedbc74aa32262154410d56c83812 F src/expr.c 437c03d5bb4fe3a53ecab3ad0286d6c5260da7ed
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179
F src/func.c d3fdcff9274bc161152e67ed3f626841c247f4b9 F src/func.c d3fdcff9274bc161152e67ed3f626841c247f4b9
@@ -179,38 +188,38 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 5a9ac4a566fb566a2ff9b9e3a9d723075d9d26a7 F src/os_unix.c 658b180a09a18214d94547f737dbded71667cdab
F src/os_win.c 673b3e3d1fa3040d8d95a7f1f5e0e553aed56cfb F src/os_win.c 673b3e3d1fa3040d8d95a7f1f5e0e553aed56cfb
F src/pager.c 6c3a8a5d665498b0344395a2c9f82d5abc4cc771 F src/pager.c 49e23f9898113ddfe90942bdf1c1ef57955d0921
F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95 F src/parse.y 9708365594eea519cdc8504dee425c0a41c79502
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9 F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9
F src/pragma.c 3eacf001cbf4becbd494f8d82d08fdf1648cf8cb F src/pragma.c 8779308bc1ea1901c4bc94dfe9a83d436f73f52c
F src/prepare.c 743e484233c51109666d402f470523553b41797c F src/prepare.c 743e484233c51109666d402f470523553b41797c
F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 10a1b332e3eb36e5d561085e18c58a8578cd7d73 F src/resolve.c 83cc2d942ee216bc56956c6e6fadb691c1727fa1
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 01540bcd3df3c8f1187158e77986028b1c667258 F src/select.c 6bfbe11e2fef81c5e18d30513ab6c69f171667eb
F src/shell.c aca9d94653decd4496846dee0c7ba83eaf96a46d F src/shell.c 5d527e5d08f05ec2c43ff194ea44bf62b974f4c9
F src/sqlite.h.in eddda5f1967e84336e11f3a5c6fd3be3337d66c1 F src/sqlite.h.in 3b9c6d8e5b3b93e39c266c9534369042c14e9a31
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5
F src/sqliteInt.h a9f727c0d568f64f06ae430e55a074d8dd1ccde4 F src/sqliteInt.h 4b768ec538d5ed20f5ca0196a25c2c029b8513cb
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c a15550a334ca07ac2bc5d32c5f97e3d61be886e8 F src/tclsqlite.c c21f61c56d519b4bcc0dcf453953edba69266854
F src/test1.c 6784fdacb35c33ba564ef749b62c4718fe515484 F src/test1.c 2b0ec224983403312a4d1db8546e1e1c45694251
F src/test2.c 29e7154112f7448d64204e8d31179cf497ecf425 F src/test2.c 29e7154112f7448d64204e8d31179cf497ecf425
F src/test3.c 96aed72a8e1d542fed127e3e8350ae357712fa82 F src/test3.c 96aed72a8e1d542fed127e3e8350ae357712fa82
F src/test4.c cea2c55110241e4674e66d476d29c914627999f5 F src/test4.c cea2c55110241e4674e66d476d29c914627999f5
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013 F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
F src/test6.c a437f76f9874d2563352a7e6cd0d43217663c220 F src/test6.c a437f76f9874d2563352a7e6cd0d43217663c220
F src/test7.c f4b894b7931f8cf9f5cbf37cfa0727703f526a40 F src/test7.c f4b894b7931f8cf9f5cbf37cfa0727703f526a40
F src/test8.c 58ea1d9698f3947e4662107ef98f429e84ae20e0 F src/test8.c f7e729e3e1973f68e6d98f5aa65046e3e2cb0bad
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
F src/test_autoext.c 5c95b5d435eaa09d6c0e7d90371c5ca8cd567701 F src/test_autoext.c 5c95b5d435eaa09d6c0e7d90371c5ca8cd567701
@@ -221,7 +230,6 @@ F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c 8f786bfd0ad48030cf2a06fb1f050e9c60a150d7 F src/test_fs.c 8f786bfd0ad48030cf2a06fb1f050e9c60a150d7
F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170 F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170
F src/test_fuzzer.c 1d26aa965120420bc14807da29d4d4541bfa6148
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
F src/test_intarray.c 07ddcebe4097d400ffca362770f1d883c112387a F src/test_intarray.c 07ddcebe4097d400ffca362770f1d883c112387a
@@ -237,11 +245,9 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c 1ec82e02fd3643899e9a5de9684515e84641c91f F src/test_quota.c 1ec82e02fd3643899e9a5de9684515e84641c91f
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
F src/test_regexp.c 06ae8138d41a793330f62351283dd6f6f21104f4
F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
F src/test_spellfix.c 56dfa6d583ac34f61af0834d7b58d674e7e18e13
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935 F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
@@ -250,14 +256,13 @@ F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4 F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4
F src/test_vfs.c 8e6087a8b3dcc260282074b0efba14b76311120c F src/test_vfs.c 8e6087a8b3dcc260282074b0efba14b76311120c
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2 F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12 F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
F src/trigger.c cd95ac64efa60e39faf9b5597443192ff27a22fa F src/trigger.c cd95ac64efa60e39faf9b5597443192ff27a22fa
F src/update.c beef58f5fd66153ac9cdf6e9f6551f09ee68976c F src/update.c beef58f5fd66153ac9cdf6e9f6551f09ee68976c
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
F src/vacuum.c 2727bdd08847fcb6b2d2da6d14f018910e8645d3 F src/vacuum.c ddf21cc9577c4cb459d08bee9863a78ec000c5bb
F src/vdbe.c 349798f630ce49c2e21a6c30863f195c484cfec5 F src/vdbe.c 349798f630ce49c2e21a6c30863f195c484cfec5
F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683 F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683
F src/vdbeInt.h a6b7a1fbb2b335fd8c3b4b8a696b1ba28eae2191 F src/vdbeInt.h a6b7a1fbb2b335fd8c3b4b8a696b1ba28eae2191
@@ -269,10 +274,10 @@ F src/vdbesort.c 4fad64071ae120c25f39dcac572d716b9cadeb7f
F src/vdbetrace.c 3ad1b4e92b60c082a02ac563da4a2735cc7d297c F src/vdbetrace.c 3ad1b4e92b60c082a02ac563da4a2735cc7d297c
F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d
F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
F src/where.c d54e63087b52c309550aa2defdb20ef27add9f9a F src/where.c 12d4200eb6ae991cad02367c391db076ac1af1b0
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
@@ -287,7 +292,7 @@ F test/analyze3.test c3c7f6c3951900c188cf94b2d5ee3246d6b3ff89
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045 F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e
F test/analyze6.test aa8dae5066bbed35c5f45a507fb87f2d342f2c99 F test/analyze6.test aa8dae5066bbed35c5f45a507fb87f2d342f2c99
F test/analyze7.test d3587aa5af75c9048d031b94fceca2534fa75d1d F test/analyze7.test bd09e89264c664d8d8d2450b6866dcdfae080a13
F test/analyze8.test 4ca170de2ba30ccb1af2c0406803db72262f9691 F test/analyze8.test 4ca170de2ba30ccb1af2c0406803db72262f9691
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
@@ -344,6 +349,7 @@ F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287 F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287
F test/closure01.test 6194a899cdbba561d0439c0d6cc7bcdf4fc413e7
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49 F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
@@ -506,6 +512,7 @@ F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
F test/fts3expr3.test 1bfb762b53a794f990f3dffaae8bbea5736422f7
F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660 F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660
F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887 F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
@@ -539,8 +546,8 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
F test/fuzzer1.test a2e93bb1e19513dd6bf9c63d3d7c4673c983ca19 F test/fuzzer1.test 41bd5aa6ae0cf18d06342a4476e3cad98604ae48
F test/fuzzerfault.test ff2282c81797b6a355f0748d8b54c7287c5d2b25 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
F test/hook.test 777b2541f6dd4f4ca5e8d6b66c1df1b3717aeab6 F test/hook.test 777b2541f6dd4f4ca5e8d6b66c1df1b3717aeab6
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3 F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3
@@ -575,7 +582,7 @@ F test/instr.test a34e1d46a9eefb098a7167ef0e730a4a3d82fba0
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
F test/intpkey.test 7af30f6ae852d8d1c2b70e4bf1551946742e92d8 F test/intpkey.test 7af30f6ae852d8d1c2b70e4bf1551946742e92d8
F test/io.test a4be25a446a99a0604ceecc039ee7363c56e4185 F test/io.test 0147ed5fdbce3286d6128f5f7e3b76ee8352d652
F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8 F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8
F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
@@ -636,7 +643,7 @@ F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6 F test/memdb.test db5260330676de007be8530d6ecc7c9ab2b06ad3
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f
F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9 F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
@@ -652,7 +659,7 @@ F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3 F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3
F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054 F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
F test/mmap1.test 0b5802cf64acaa509ea889b3c708196cc6eb9d31 F test/mmap1.test 8696aa1b0bd88961c2f16af2a3f7a69d701cea50
F test/mmap2.test a5ba639f90b5fc487400a49e158e14e465943e98 F test/mmap2.test a5ba639f90b5fc487400a49e158e14e465943e98
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
@@ -682,8 +689,8 @@ F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6
F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/permutations.test a19a70a80836b5e183e46f4043fb7626446ab5e0 F test/permutations.test 1981ef401ecd5292058c19ee10c94aa17c9039fd
F test/pragma.test 60d29cd3d8098a2c20bf4c072810f99e3bf2757a F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
@@ -696,7 +703,7 @@ F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
F test/regexp1.test 5cbb6e7122ca51260d71079cf9245b63b8f64e1a F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
@@ -731,7 +738,7 @@ F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
F test/selectD.test 03f7c1ea8d5ab3c637cbc30fcbbbac96b988c162 F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718 F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
@@ -763,7 +770,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/spellfix.test 52ae2680b1247c52b9e2b2116de3fd26a78e6bd2 F test/spellfix.test bea537caf587df30d430c2c6a8fe9f64b8712834
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
@@ -796,7 +803,7 @@ F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
F test/tkt-2a5629202f.test 1ab32e084e9fc3d36be6dee2617530846a0eb0b6 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-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58 F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58
F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac
@@ -1010,7 +1017,7 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 5c566388f0cc318b0032ce860f4ac5548e3c265a F test/where7.test 5c566388f0cc318b0032ce860f4ac5548e3c265a
F test/where8.test 02619a9bfc6df7b19979a02852bac09c3c99477a F test/where8.test d9f889e62dccddb9d790b0c84dfc7861e03a162c
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
F test/where9.test 0157862ccf0cfdf1a4622cdf697e5e2f09a8de44 F test/where9.test 0157862ccf0cfdf1a4622cdf697e5e2f09a8de44
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
@@ -1022,9 +1029,9 @@ F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 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-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x
F tool/build-shell.sh a9c34a606e2e522ba9eeca1e07090f67dce8c912 F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
@@ -1047,7 +1054,7 @@ F tool/omittest.tcl 4665982e95a6e5c1bd806cf7bc3dea95be422d77
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
F tool/showdb.c acd24ea035a3bd2ffe266f1ef8a161812c29b2f0 F tool/showdb.c 525ecc443578647703051308ad50a93de6ba2c4b
F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02 F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5 F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
@@ -1067,7 +1074,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P 67b3c0efa7d5e0cb7cc0fc7606ab3f26ea5419fd 1a1cf5aa86734c832d845e07780262a178188d56 P 6994826c0784280f2e9728dfa4185848846d03df b2efe4f225adc5f4c2e3080bf459cc52fff82e18
R 732bd62d8f3cf92b7ff68a9a14e06f6a R 70853c32af7db548acc44e4c7931cc60
U drh U drh
Z d4e35c064e319291a70a72e245362c9b Z ccdd14f93f4b60d77de88619ca7032d3

View File

@@ -1 +1 @@
6994826c0784280f2e9728dfa4185848846d03df 3879ab1b532828fcc12a50a95b6730faebcb69e9

View File

@@ -140,6 +140,7 @@ int sqlite3BtreeNewDb(Btree *p);
#define BTREE_TEXT_ENCODING 5 #define BTREE_TEXT_ENCODING 5
#define BTREE_USER_VERSION 6 #define BTREE_USER_VERSION 6
#define BTREE_INCR_VACUUM 7 #define BTREE_INCR_VACUUM 7
#define BTREE_APPLICATION_ID 8
/* /*
** Values that may be OR'd together to form the second argument of an ** Values that may be OR'd together to form the second argument of an

View File

@@ -1214,6 +1214,7 @@ static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
} }
static int exprIsConst(Expr *p, int initFlag){ static int exprIsConst(Expr *p, int initFlag){
Walker w; Walker w;
memset(&w, 0, sizeof(w));
w.u.i = initFlag; w.u.i = initFlag;
w.xExprCallback = exprNodeIsConstant; w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant; w.xSelectCallback = selectNodeIsConstant;
@@ -3428,8 +3429,8 @@ void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
Walker w; Walker w;
if( pParse->cookieGoto ) return; if( pParse->cookieGoto ) return;
if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return; if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return;
memset(&w, 0, sizeof(w));
w.xExprCallback = evalConstExpr; w.xExprCallback = evalConstExpr;
w.xSelectCallback = 0;
w.pParse = pParse; w.pParse = pParse;
sqlite3WalkExpr(&w, pExpr); sqlite3WalkExpr(&w, pExpr);
} }

View File

@@ -126,7 +126,7 @@
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
#include <errno.h> #include <errno.h>
#ifndef SQLITE_OMIT_WAL #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
@@ -3193,6 +3193,51 @@ static int unixRead(
} }
} }
/*
** Attempt to seek the file-descriptor passed as the first argument to
** absolute offset iOff, then attempt to write nBuf bytes of data from
** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
** return the actual number of bytes written (which may be less than
** nBuf).
*/
static int seekAndWriteFd(
int fd, /* File descriptor to write to */
i64 iOff, /* File offset to begin writing at */
const void *pBuf, /* Copy data from this buffer to the file */
int nBuf, /* Size of buffer pBuf in bytes */
int *piErrno /* OUT: Error number if error occurs */
){
int rc = 0; /* Value returned by system call */
assert( nBuf==(nBuf&0x1ffff) );
nBuf &= 0x1ffff;
TIMER_START;
#if defined(USE_PREAD)
do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
#elif defined(USE_PREAD64)
do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
#else
do{
i64 iSeek = lseek(fd, iOff, SEEK_SET);
SimulateIOError( iSeek-- );
if( iSeek!=iOff ){
if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
return -1;
}
rc = osWrite(fd, pBuf, nBuf);
}while( rc<0 && errno==EINTR );
#endif
TIMER_END;
OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
if( rc<0 && piErrno ) *piErrno = errno;
return rc;
}
/* /*
** Seek to the offset in id->offset then read cnt bytes into pBuf. ** Seek to the offset in id->offset then read cnt bytes into pBuf.
** Return the number of bytes actually read. Update the offset. ** Return the number of bytes actually read. Update the offset.
@@ -3201,39 +3246,7 @@ static int unixRead(
** is set before returning. ** is set before returning.
*/ */
static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
int got; return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
#endif
assert( cnt==(cnt&0x1ffff) );
cnt &= 0x1ffff;
TIMER_START;
#if defined(USE_PREAD)
do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
#elif defined(USE_PREAD64)
do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
#else
do{
newOffset = lseek(id->h, offset, SEEK_SET);
SimulateIOError( newOffset-- );
if( newOffset!=offset ){
if( newOffset == -1 ){
((unixFile*)id)->lastErrno = errno;
}else{
((unixFile*)id)->lastErrno = 0;
}
return -1;
}
got = osWrite(id->h, pBuf, cnt);
}while( got<0 && errno==EINTR );
#endif
TIMER_END;
if( got<0 ){
((unixFile*)id)->lastErrno = errno;
}
OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
} }
@@ -4322,24 +4335,32 @@ static int unixShmMap(
if( sStat.st_size<nByte ){ if( sStat.st_size<nByte ){
/* The requested memory region does not exist. If bExtend is set to /* The requested memory region does not exist. If bExtend is set to
** false, exit early. *pp will be set to NULL and SQLITE_OK returned. ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
**
** Alternatively, if bExtend is true, use ftruncate() to allocate
** the requested memory region.
*/ */
if( !bExtend ) goto shmpage_out; if( !bExtend ){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
if( osFallocate(pShmNode->h, sStat.st_size, nByte)!=0 ){
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "fallocate",
pShmNode->zFilename);
goto shmpage_out; goto shmpage_out;
} }
#else
if( robust_ftruncate(pShmNode->h, nByte) ){ /* Alternatively, if bExtend is true, extend the file. Do this by
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate", ** writing a single byte to the end of each (OS) page being
pShmNode->zFilename); ** allocated or extended. Technically, we need only write to the
goto shmpage_out; ** last page in order to extend the file. But writing to all new
** pages forces the OS to allocate them immediately, which reduces
** the chances of SIGBUS while accessing the mapped region later on.
*/
else{
static const int pgsz = 4096;
int iPg;
/* Write to the last byte of each newly allocated or extended page */
assert( (nByte % pgsz)==0 );
for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
const char *zFile = pShmNode->zFilename;
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
goto shmpage_out;
}
}
} }
#endif
} }
} }
@@ -5266,9 +5287,8 @@ static int fillInUnixFile(
if( h>=0 ) robust_close(pNew, h, __LINE__); if( h>=0 ) robust_close(pNew, h, __LINE__);
h = -1; h = -1;
osUnlink(zFilename); osUnlink(zFilename);
isDelete = 0; pNew->ctrlFlags |= UNIXFILE_DELETE;
} }
if( isDelete ) pNew->ctrlFlags |= UNIXFILE_DELETE;
#endif #endif
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__); if( h>=0 ) robust_close(pNew, h, __LINE__);

View File

@@ -2871,10 +2871,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
return SQLITE_OK; return SQLITE_OK;
} }
#ifndef SQLITE_OMIT_WAL
if( iFrame ){ if( iFrame ){
/* Try to pull the page from the write-ahead log. */ /* Try to pull the page from the write-ahead log. */
rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
}else{ }else
#endif
{
i64 iOffset = (pgno-1)*(i64)pPager->pageSize; i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){ if( rc==SQLITE_IOERR_SHORT_READ ){
@@ -5927,6 +5930,11 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
pPager->aStat[PAGER_STAT_WRITE]++; pPager->aStat[PAGER_STAT_WRITE]++;
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
/* Update the pager's copy of the change-counter. Otherwise, the
** next time a read transaction is opened the cache will be
** flushed (as the change-counter values will not match). */
const void *pCopy = (const void *)&((const char *)zBuf)[24];
memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers));
pPager->changeCountDone = 1; pPager->changeCountDone = 1;
} }
}else{ }else{

View File

@@ -520,7 +520,9 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I)
struct SrcList_item *pOld = F->a; struct SrcList_item *pOld = F->a;
pNew->zName = pOld->zName; pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase; pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
pOld->zName = pOld->zDatabase = 0; pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
} }
sqlite3SrcListDelete(pParse->db, F); sqlite3SrcListDelete(pParse->db, F);
}else{ }else{

View File

@@ -1567,6 +1567,11 @@ void sqlite3Pragma(
** PRAGMA [database.]user_version ** PRAGMA [database.]user_version
** PRAGMA [database.]user_version = <integer> ** PRAGMA [database.]user_version = <integer>
** **
** PRAGMA [database.]freelist_count = <integer>
**
** PRAGMA [database.]application_id
** PRAGMA [database.]application_id = <integer>
**
** The pragma's schema_version and user_version are used to set or get ** The pragma's schema_version and user_version are used to set or get
** the value of the schema-version and user-version, respectively. Both ** the value of the schema-version and user-version, respectively. Both
** the schema-version and the user-version are 32-bit signed integers ** the schema-version and the user-version are 32-bit signed integers
@@ -1588,10 +1593,14 @@ void sqlite3Pragma(
if( sqlite3StrICmp(zLeft, "schema_version")==0 if( sqlite3StrICmp(zLeft, "schema_version")==0
|| sqlite3StrICmp(zLeft, "user_version")==0 || sqlite3StrICmp(zLeft, "user_version")==0
|| sqlite3StrICmp(zLeft, "freelist_count")==0 || sqlite3StrICmp(zLeft, "freelist_count")==0
|| sqlite3StrICmp(zLeft, "application_id")==0
){ ){
int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeUsesBtree(v, iDb);
switch( zLeft[0] ){ switch( zLeft[0] ){
case 'a': case 'A':
iCookie = BTREE_APPLICATION_ID;
break;
case 'f': case 'F': case 'f': case 'F':
iCookie = BTREE_FREE_PAGE_COUNT; iCookie = BTREE_FREE_PAGE_COUNT;
break; break;

View File

@@ -1283,6 +1283,7 @@ int sqlite3ResolveExprNames(
#endif #endif
savedHasAgg = pNC->ncFlags & NC_HasAgg; savedHasAgg = pNC->ncFlags & NC_HasAgg;
pNC->ncFlags &= ~NC_HasAgg; pNC->ncFlags &= ~NC_HasAgg;
memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep; w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep; w.xSelectCallback = resolveSelectStep;
w.pParse = pNC->pParse; w.pParse = pNC->pParse;
@@ -1323,6 +1324,7 @@ void sqlite3ResolveSelectNames(
Walker w; Walker w;
assert( p!=0 ); assert( p!=0 );
memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep; w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep; w.xSelectCallback = resolveSelectStep;
w.pParse = pParse; w.pParse = pParse;

View File

@@ -3576,6 +3576,7 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
*/ */
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w; Walker w;
memset(&w, 0, sizeof(w));
w.xSelectCallback = selectExpander; w.xSelectCallback = selectExpander;
w.xExprCallback = exprWalkNoop; w.xExprCallback = exprWalkNoop;
w.pParse = pParse; w.pParse = pParse;
@@ -3634,9 +3635,11 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
Walker w; Walker w;
memset(&w, 0, sizeof(w));
w.xSelectCallback = selectAddSubqueryTypeInfo; w.xSelectCallback = selectAddSubqueryTypeInfo;
w.xExprCallback = exprWalkNoop; w.xExprCallback = exprWalkNoop;
w.pParse = pParse; w.pParse = pParse;
w.bSelectDepthFirst = 1;
sqlite3WalkSelect(&w, pSelect); sqlite3WalkSelect(&w, pSelect);
#endif #endif
} }
@@ -4047,7 +4050,7 @@ int sqlite3Select(
pItem->addrFillSub = topAddr+1; pItem->addrFillSub = topAddr+1;
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName)); VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
if( pItem->isCorrelated==0 ){ if( pItem->isCorrelated==0 ){
/* If the subquery is no correlated and if we are not inside of /* If the subquery is not correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery ** a trigger, then we only need to compute the value of the subquery
** once. */ ** once. */
onceAddr = sqlite3CodeOnce(pParse); onceAddr = sqlite3CodeOnce(pParse);

View File

@@ -1480,18 +1480,6 @@ static void open_db(struct callback_data *p){
} }
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1); 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 #endif
} }
} }

View File

@@ -1587,7 +1587,9 @@ struct sqlite3_mem_methods {
** page cache implementation into that object.)^ </dd> ** page cache implementation into that object.)^ </dd>
** **
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
** global [error log].
** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
** function with a call signature of void(*)(void*,int,const char*), ** function with a call signature of void(*)(void*,int,const char*),
** and a pointer to void. ^If the function pointer is not NULL, it is ** and a pointer to void. ^If the function pointer is not NULL, it is
** invoked by [sqlite3_log()] to process each logging event. ^If the ** invoked by [sqlite3_log()] to process each logging event. ^If the
@@ -2522,6 +2524,9 @@ int sqlite3_set_authorizer(
** as each triggered subprogram is entered. The callbacks for triggers ** as each triggered subprogram is entered. The callbacks for triggers
** contain a UTF-8 SQL comment that identifies the trigger.)^ ** contain a UTF-8 SQL comment that identifies the trigger.)^
** **
** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit
** the length of [bound parameter] expansion in the output of sqlite3_trace().
**
** ^The callback function registered by sqlite3_profile() is invoked ** ^The callback function registered by sqlite3_profile() is invoked
** as each SQL statement finishes. ^The profile callback contains ** as each SQL statement finishes. ^The profile callback contains
** the original statement text and an estimate of wall-clock time ** the original statement text and an estimate of wall-clock time
@@ -3060,7 +3065,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
** <li> ** <li>
** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
** always used to do, [sqlite3_step()] will automatically recompile the SQL ** always used to do, [sqlite3_step()] will automatically recompile the SQL
** statement and try to run it again. ** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY]
** retries will occur before sqlite3_step() gives up and returns an error.
** </li> ** </li>
** **
** <li> ** <li>
@@ -3264,6 +3270,9 @@ typedef struct sqlite3_context sqlite3_context;
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
** **
** ^The third argument is the value to bind to the parameter. ** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
** **
** ^(In those routines that have a fourth argument, its value is the ** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the parameter. To be clear: the value is the
@@ -6872,7 +6881,7 @@ int sqlite3_strglob(const char *zGlob, const char *zStr);
/* /*
** CAPI3REF: Error Logging Interface ** CAPI3REF: Error Logging Interface
** **
** ^The [sqlite3_log()] interface writes a message into the error log ** ^The [sqlite3_log()] interface writes a message into the [error log]
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
** ^If logging is enabled, the zFormat string and subsequent arguments are ** ^If logging is enabled, the zFormat string and subsequent arguments are
** used with [sqlite3_snprintf()] to generate the final output string. ** used with [sqlite3_snprintf()] to generate the final output string.

View File

@@ -563,7 +563,7 @@ extern const int sqlite3one;
|| defined(_WIN32) \ || defined(_WIN32) \
|| (defined(__APPLE__) && defined(__MACH__)) \ || (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__sun) || defined(__sun)
# define SQLITE_MAX_MMAP_SIZE 2147483648 # define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */
# else # else
# define SQLITE_MAX_MMAP_SIZE 0 # define SQLITE_MAX_MMAP_SIZE 0
# endif # endif
@@ -2600,6 +2600,7 @@ struct Walker {
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
Parse *pParse; /* Parser context. */ Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */ int walkerDepth; /* Number of subqueries */
u8 bSelectDepthFirst; /* Do subqueries first */
union { /* Extra data for callback */ union { /* Extra data for callback */
NameContext *pNC; /* Naming context */ NameContext *pNC; /* Naming context */
int i; /* Integer value */ int i; /* Integer value */

View File

@@ -3829,12 +3829,9 @@ static void init_all(Tcl_Interp *interp){
extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*);
extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*);
extern int SqlitetestSyscall_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*);
extern int Sqlitetestfuzzer_Init(Tcl_Interp*);
extern int Sqlitetestwholenumber_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
extern int TestSession_Init(Tcl_Interp*); extern int TestSession_Init(Tcl_Interp*);
#endif #endif
extern int Sqlitetestregexp_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
extern int Sqlitetestfts3_Init(Tcl_Interp *interp); extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
@@ -3877,12 +3874,9 @@ static void init_all(Tcl_Interp *interp){
Sqlitemultiplex_Init(interp); Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp); SqliteSuperlock_Init(interp);
SqlitetestSyscall_Init(interp); SqlitetestSyscall_Init(interp);
Sqlitetestfuzzer_Init(interp);
Sqlitetestwholenumber_Init(interp);
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
TestSession_Init(interp); TestSession_Init(interp);
#endif #endif
Sqlitetestregexp_Init(interp);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp); Sqlitetestfts3_Init(interp);

View File

@@ -6045,6 +6045,69 @@ static int optimization_control(
return TCL_OK; return TCL_OK;
} }
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** load_static_extension DB NAME ...
**
** Load one or more statically linked extensions.
*/
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_nextchar_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 },
{ "nextchar", sqlite3_nextchar_init },
{ "regexp", sqlite3_regexp_init },
{ "spellfix", sqlite3_spellfix_init },
{ "wholenumber", sqlite3_wholenumber_init },
};
sqlite3 *db;
const char *zName;
int i, j, 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;
for(j=2; j<objc; j++){
zName = Tcl_GetString(objv[j]);
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. ** Register commands with the TCL interpreter.
*/ */
@@ -6266,6 +6329,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#if SQLITE_OS_UNIX #if SQLITE_OS_UNIX
{ "getrusage", test_getrusage }, { "getrusage", test_getrusage },
#endif #endif
{ "load_static_extension", tclLoadStaticExtensionCmd },
}; };
static int bitmask_size = sizeof(Bitmask)*8; static int bitmask_size = sizeof(Bitmask)*8;
int i; int i;

View File

@@ -1370,29 +1370,6 @@ static int declare_vtab(
return TCL_OK; 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 */ #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/* /*
@@ -1406,7 +1383,6 @@ int Sqlitetest8_Init(Tcl_Interp *interp){
void *clientData; void *clientData;
} aObjCmd[] = { } aObjCmd[] = {
{ "register_echo_module", register_echo_module, 0 }, { "register_echo_module", register_echo_module, 0 },
{ "register_spellfix_module", register_spellfix_module, 0 },
{ "sqlite3_declare_vtab", declare_vtab, 0 }, { "sqlite3_declare_vtab", declare_vtab, 0 },
}; };
int i; int i;

View File

@@ -289,6 +289,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */
BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */
BTREE_USER_VERSION, 0, /* Preserve the user version */ BTREE_USER_VERSION, 0, /* Preserve the user version */
BTREE_APPLICATION_ID, 0, /* Preserve the application id */
}; };
assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( 1==sqlite3BtreeIsInTrans(pTemp) );

View File

@@ -43,6 +43,7 @@
# define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalExclusiveMode(y,z) 0
# define sqlite3WalHeapMemory(z) 0 # define sqlite3WalHeapMemory(z) 0
# define sqlite3WalFramesize(z) 0 # define sqlite3WalFramesize(z) 0
# define sqlite3WalFindFrame(x,y,z) 0
#else #else
#define WAL_SAVEPOINT_NDATA 4 #define WAL_SAVEPOINT_NDATA 4

View File

@@ -113,7 +113,9 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
/* /*
** Call sqlite3WalkExpr() for every expression in Select statement p. ** Call sqlite3WalkExpr() for every expression in Select statement p.
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
** on the compound select chain, p->pPrior. ** on the compound select chain, p->pPrior. Invoke the xSelectCallback()
** either before or after the walk of expressions and FROM clause, depending
** on whether pWalker->bSelectDepthFirst is false or true, respectively.
** **
** Return WRC_Continue under normal conditions. Return WRC_Abort if ** Return WRC_Continue under normal conditions. Return WRC_Abort if
** there is an abort request. ** there is an abort request.
@@ -127,14 +129,23 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){
rc = WRC_Continue; rc = WRC_Continue;
pWalker->walkerDepth++; pWalker->walkerDepth++;
while( p ){ while( p ){
rc = pWalker->xSelectCallback(pWalker, p); if( !pWalker->bSelectDepthFirst ){
if( rc ) break; rc = pWalker->xSelectCallback(pWalker, p);
if( rc ) break;
}
if( sqlite3WalkSelectExpr(pWalker, p) if( sqlite3WalkSelectExpr(pWalker, p)
|| sqlite3WalkSelectFrom(pWalker, p) || sqlite3WalkSelectFrom(pWalker, p)
){ ){
pWalker->walkerDepth--; pWalker->walkerDepth--;
return WRC_Abort; return WRC_Abort;
} }
if( pWalker->bSelectDepthFirst ){
rc = pWalker->xSelectCallback(pWalker, p);
/* Depth-first search is currently only used for
** selectAddSubqueryTypeInfo() and that routine always returns
** WRC_Continue (0). So the following branch is never taken. */
if( NEVER(rc) ) break;
}
p = p->pPrior; p = p->pPrior;
} }
pWalker->walkerDepth--; pWalker->walkerDepth--;

View File

@@ -705,7 +705,7 @@ static WhereTerm *findTerm(
continue; continue;
} }
} }
if( pTerm->prereqRight==0 ){ if( pTerm->prereqRight==0 && (pTerm->eOperator&WO_EQ)!=0 ){
pResult = pTerm; pResult = pTerm;
goto findTerm_success; goto findTerm_success;
}else if( pResult==0 ){ }else if( pResult==0 ){
@@ -4883,6 +4883,7 @@ static Bitmask codeOneLoopStart(
assert( (pTerm->prereqRight & newNotReady)!=0 ); assert( (pTerm->prereqRight & newNotReady)!=0 );
pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
if( pAlt==0 ) continue; if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
VdbeNoopComment((v, "begin transitive constraint")); VdbeNoopComment((v, "begin transitive constraint"));
sEq = *pAlt->pExpr; sEq = *pAlt->pExpr;
sEq.pLeft = pE->pLeft; sEq.pLeft = pE->pLeft;

View File

@@ -150,7 +150,7 @@ db close
forcedelete test.db forcedelete test.db
do_test 8_3_names-5.0 { do_test 8_3_names-5.0 {
sqlite3 db file:./test.db?8_3_names=1 sqlite3 db file:./test.db?8_3_names=1
register_wholenumber_module db load_static_extension db wholenumber
db eval { db eval {
PRAGMA journal_mode=WAL; PRAGMA journal_mode=WAL;
CREATE TABLE t1(x); CREATE TABLE t1(x);
@@ -160,7 +160,7 @@ do_test 8_3_names-5.0 {
UPDATE t1 SET x=x*2; UPDATE t1 SET x=x*2;
} }
sqlite3 db2 file:./test.db?8_3_names=1 sqlite3 db2 file:./test.db?8_3_names=1
register_wholenumber_module db2 load_static_extension db2 wholenumber
db2 eval { db2 eval {
BEGIN; BEGIN;
SELECT sum(x) FROM t1; SELECT sum(x) FROM t1;

View File

@@ -26,7 +26,7 @@ ifcapable {!analyze||!vtab} {
# Generate some test data # Generate some test data
# #
do_test analyze7-1.0 { do_test analyze7-1.0 {
register_wholenumber_module db load_static_extension db wholenumber
execsql { execsql {
CREATE TABLE t1(a,b,c,d); CREATE TABLE t1(a,b,c,d);
CREATE INDEX t1a ON t1(a); CREATE INDEX t1a ON t1(a);

224
test/closure01.test Normal file
View 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

210
test/fts3expr3.test Normal file
View File

@@ -0,0 +1,210 @@
# 2009 January 1
#
# 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 implements regression tests for SQLite library. The
# focus of this script is testing the part of the FTS3 expression
# parser that rebalances large expressions.
#
# $Id: fts3expr2.test,v 1.2 2009/06/05 17:09:12 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix fts3expr3
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
set sqlite_fts3_enable_parentheses 1
proc strip_phrase_data {L} {
if {[lindex $L 0] eq "PHRASE"} {
return [list P [lrange $L 3 end]]
}
return [list \
[lindex $L 0] \
[strip_phrase_data [lindex $L 1]] \
[strip_phrase_data [lindex $L 2]] \
]
}
proc test_fts3expr2 {expr} {
strip_phrase_data [
db one {SELECT fts3_exprtest_rebalance('simple', $expr, 'a', 'b', 'c')}
]
}
proc balanced_exprtree_structure {nEntry} {
set L [list]
for {set i 1} {$i <= $nEntry} {incr i} {
lappend L xxx
}
while {[llength $L] > 1} {
set N [list]
if {[llength $L] % 2} {
foreach {a b} [lrange $L 0 end-1] { lappend N [list AND $a $b] }
lappend N [lindex $L end]
} else {
foreach {a b} $L { lappend N [list AND $a $b] }
}
set L $N
}
return [lindex $L 0]
}
proc balanced_and_tree {nEntry} {
set query [balanced_exprtree_structure $nEntry]
if {$query == "xxx"} {
return "P 1"
}
for {set i 1} {$i <= $nEntry} {incr i} {
regsub xxx $query "{P $i}" query
}
return $query
}
proc random_tree_structure {nEntry bParen op} {
set query xxx
for {set i 1} {$i < $nEntry} {incr i} {
set x1 [expr int(rand()*4.0)]
set x2 [expr int(rand()*2.0)]
if {$x1==0 && $bParen} {
set query "($query)"
}
if {$x2} {
set query "xxx $op $query"
} else {
set query "$query $op xxx"
}
}
return $query
}
proc random_and_query {nEntry {bParen 0}} {
set query [random_tree_structure $nEntry $bParen AND]
for {set i 1} {$i <= $nEntry} {incr i} {
regsub xxx $query $i query
}
return $query
}
proc random_or_query {nEntry} {
set query [random_tree_structure $nEntry 1 OR]
for {set i 1} {$i <= $nEntry} {incr i} {
regsub xxx $query $i query
}
return $query
}
proc random_andor_query {nEntry} {
set query [random_tree_structure $nEntry 1 AND]
for {set i 1} {$i <= $nEntry} {incr i} {
regsub xxx $query "([random_or_query $nEntry])" query
}
return $query
}
proc balanced_andor_tree {nEntry} {
set tree [balanced_exprtree_structure $nEntry]
set node "{[balanced_and_tree $nEntry]}"
regsub -all AND $node OR node
regsub -all xxx $tree $node tree
return $tree
}
# Test that queries like "1 AND 2 AND 3 AND 4..." are transformed to
# balanced trees by FTS.
#
for {set i 1} {$i < 100} {incr i} {
do_test 1.$i {
test_fts3expr2 [random_and_query $i]
} [balanced_and_tree $i]
}
# Same again, except with parenthesis inserted at arbitrary points.
#
for {set i 1} {$i < 100} {incr i} {
do_test 2.$i {
test_fts3expr2 [random_and_query $i 1]
} [balanced_and_tree $i]
}
# Now attempt to balance two AND trees joined by an OR.
#
for {set i 1} {$i < 100} {incr i} {
do_test 3.$i {
test_fts3expr2 "[random_and_query $i 1] OR [random_and_query $i 1]"
} [list OR [balanced_and_tree $i] [balanced_and_tree $i]]
}
# Try trees of AND nodes with leaves that are themselves trees of OR nodes.
#
for {set i 2} {$i < 64} {incr i 4} {
do_test 3.$i {
test_fts3expr2 [random_andor_query $i]
} [balanced_andor_tree $i]
}
# These exceed the depth limit.
#
for {set i 65} {$i < 70} {incr i} {
do_test 3.$i {
list [catch {test_fts3expr2 [random_andor_query $i]} msg] $msg
} {1 {Error parsing expression}}
}
# This also exceeds the depth limit.
#
do_test 4.1.1 {
set q "1"
for {set i 2} {$i < 5000} {incr i} {
append q " AND $i"
}
list [catch {test_fts3expr2 $q} msg] $msg
} {1 {Error parsing expression}}
do_test 4.1.2 {
set q "1"
for {set i 2} {$i < 4000} {incr i} {
append q " AND $i"
}
catch {test_fts3expr2 $q}
} {0}
proc create_toggle_tree {nDepth} {
if {$nDepth == 0} { return xxx }
set nNew [expr $nDepth-1]
if {$nDepth % 2} {
return "([create_toggle_tree $nNew]) OR ([create_toggle_tree $nNew])"
}
return "([create_toggle_tree $nNew]) AND ([create_toggle_tree $nNew])"
}
do_test 4.2 {
list [catch {test_fts3expr2 [create_toggle_tree 17]} msg] $msg
} {1 {Error parsing expression}}
set query [random_andor_query 12]
set result [balanced_andor_tree 12]
do_faultsim_test fts3expr3-fault-1 -faults oom-* -body {
test_fts3expr2 $::query
} -test {
faultsim_test_result [list 0 $::result]
}
set sqlite_fts3_enable_parentheses 0
finish_test

View File

@@ -24,12 +24,7 @@ ifcapable !vtab {
set ::testprefix fuzzer1 set ::testprefix fuzzer1
# Test of test code. Only here to make the coverage metric better. load_static_extension db fuzzer
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
# Check configuration errors. # Check configuration errors.
# #

View File

@@ -17,7 +17,7 @@ source $testdir/tester.tcl
ifcapable !vtab { finish_test ; return } ifcapable !vtab { finish_test ; return }
set ::testprefix fuzzerfault set ::testprefix fuzzerfault
register_fuzzer_module db load_static_extension db fuzzer
do_test 1-pre1 { do_test 1-pre1 {
execsql { execsql {
@@ -30,7 +30,7 @@ do_test 1-pre1 {
} {} } {}
do_faultsim_test 1 -prep { do_faultsim_test 1 -prep {
faultsim_restore_and_reopen faultsim_restore_and_reopen
register_fuzzer_module db load_static_extension db fuzzer
} -body { } -body {
execsql { execsql {
CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules);
@@ -43,7 +43,7 @@ do_faultsim_test 1 -prep {
do_test 2-pre1 { do_test 2-pre1 {
faultsim_delete_and_reopen faultsim_delete_and_reopen
register_fuzzer_module db load_static_extension db fuzzer
execsql { execsql {
CREATE TABLE x2_rules(ruleset, cFrom, cTo, cost); CREATE TABLE x2_rules(ruleset, cFrom, cTo, cost);
INSERT INTO x2_rules VALUES(0, 'a', 'x', 1); INSERT INTO x2_rules VALUES(0, 'a', 'x', 1);
@@ -56,7 +56,7 @@ do_test 2-pre1 {
do_faultsim_test 2 -prep { do_faultsim_test 2 -prep {
faultsim_restore_and_reopen faultsim_restore_and_reopen
register_fuzzer_module db load_static_extension db fuzzer
} -body { } -body {
execsql { execsql {
SELECT count(*) FROM x2 WHERE word MATCH 'abc'; SELECT count(*) FROM x2 WHERE word MATCH 'abc';
@@ -78,7 +78,7 @@ do_test 3-pre1 {
do_faultsim_test 3 -prep { do_faultsim_test 3 -prep {
faultsim_restore_and_reopen faultsim_restore_and_reopen
register_fuzzer_module db load_static_extension db fuzzer
} -body { } -body {
execsql { execsql {
CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules);

View File

@@ -16,6 +16,7 @@
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
set ::testprefix io
db close db close
sqlite3_simulate_device sqlite3_simulate_device
@@ -39,6 +40,10 @@ sqlite3 db test.db -vfs devsym
# io-5.* - Test that the default page size is selected and used # io-5.* - Test that the default page size is selected and used
# correctly. # correctly.
# #
# io-6.* - Test that the pager-cache is not being flushed unnecessarily
# after a transaction that uses the special atomic-write path
# is committed.
#
set ::nWrite 0 set ::nWrite 0
proc nWrite {db} { proc nWrite {db} {
@@ -565,5 +570,68 @@ foreach {char sectorsize pgsize} {
} $pgsize } $pgsize
} }
#----------------------------------------------------------------------
#
do_test io-6.1 {
db close
sqlite3_simulate_device -char atomic
forcedelete test.db
sqlite3 db test.db -vfs devsym
execsql {
PRAGMA mmap_size = 0;
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
CREATE TABLE t2(x);
CREATE TABLE t3(x);
CREATE INDEX i3 ON t3(x);
INSERT INTO t3 VALUES(randomblob(100));
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
INSERT INTO t3 SELECT randomblob(100) FROM t3;
}
db_save_and_close
} {}
foreach {tn sql} {
1 { BEGIN;
INSERT INTO t1 VALUES('123');
INSERT INTO t2 VALUES('456');
COMMIT;
}
2 { BEGIN;
INSERT INTO t1 VALUES('123');
COMMIT;
}
} {
db_restore
sqlite3 db test.db -vfs devsym
execsql {
PRAGMA mmap_size = 0;
SELECT x FROM t3 ORDER BY rowid;
SELECT x FROM t3 ORDER BY x;
}
do_execsql_test 6.2.$tn.1 { PRAGMA integrity_check } {ok}
do_execsql_test 6.2.$tn.2 $sql
# Corrupt the database file on disk. This should not matter for the
# purposes of the following "PRAGMA integrity_check", as the entire
# database should be cached in the pager-cache. If corruption is
# reported, it indicates that executing $sql caused the pager cache
# to be flushed. Which is a bug.
hexio_write test.db [expr 1024 * 5] [string repeat 00 2048]
do_execsql_test 6.2.$tn.3 { PRAGMA integrity_check } {ok}
db close
}
sqlite3_simulate_device -char {} -sectorsize 0 sqlite3_simulate_device -char {} -sectorsize 0
finish_test finish_test

View File

@@ -365,7 +365,7 @@ do_test memdb-6.15 {
ifcapable subquery&&vtab { ifcapable subquery&&vtab {
do_test memdb-7.1 { do_test memdb-7.1 {
register_wholenumber_module db load_static_extension db wholenumber
execsql { execsql {
CREATE TABLE t6(x); CREATE TABLE t6(x);
CREATE VIRTUAL TABLE nums USING wholenumber; CREATE VIRTUAL TABLE nums USING wholenumber;

View File

@@ -40,14 +40,20 @@ proc register_rblob_code {dbname seed} {
}] }]
} }
# For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on
# unix and 9 on windows. The difference is that windows only ever maps
# an integer number of OS pages (i.e. creates mappings that are a multiple
# of 4KB in size). Whereas on unix any sized mapping may be created.
#
foreach {t mmap_size nRead c2init} { foreach {t mmap_size nRead c2init} {
1.1 { PRAGMA mmap_size = 67108864 } 4 {PRAGMA mmap_size = 0} 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0}
1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0} 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0}
1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0} 1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0}
1.4 { PRAGMA mmap_size = 67108864 } 4 {PRAGMA mmap_size = 67108864 } 1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 }
1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 } 1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 }
1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 } 1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 }
} { } {
do_multiclient_test tn { do_multiclient_test tn {
sql1 {PRAGMA page_size=1024} sql1 {PRAGMA page_size=1024}
sql1 $mmap_size sql1 $mmap_size

View File

@@ -189,6 +189,7 @@ test_suite "fts3" -prefix "" -description {
fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test
fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test
fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test
fts3expr3.test
fts3near.test fts3query.test fts3shared.test fts3snippet.test fts3near.test fts3query.test fts3shared.test fts3snippet.test
fts3sort.test fts3sort.test
fts3fault.test fts3malloc.test fts3matchinfo.test fts3fault.test fts3malloc.test fts3matchinfo.test

View File

@@ -936,6 +936,16 @@ proc check_temp_store {} {
return "unknown" return "unknown"
} }
# Application_ID
#
do_test pragma-8.3.1 {
execsql {
PRAGMA application_id;
}
} {0}
do_test pragma-8.3.2 {
execsql {PRAGMA Application_ID(12345); PRAGMA application_id;}
} {12345}
# Test temp_store and temp_store_directory pragmas # Test temp_store and temp_store_directory pragmas
# #

View File

@@ -16,7 +16,7 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
do_test regexp1-1.1 { do_test regexp1-1.1 {
sqlite3_add_regexp_func db load_static_extension db regexp
db eval { db eval {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT); CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
INSERT INTO t1 VALUES(1, 'For since by man came death,'); INSERT INTO t1 VALUES(1, 'For since by man came death,');

View File

@@ -152,4 +152,23 @@ for {set i 1} {$i<=2} {incr i} {
} {111 x1 111 x2 222 x3 {}} } {111 x1 111 x2 222 x3 {}}
} }
# The following test was added on 2013-04-24 in order to verify that
# the datatypes and affinities of sub-sub-queries are set prior to computing
# the datatypes and affinities of the parent sub-queries because the
# latter computation depends on the former.
#
do_execsql_test selectD-4.1 {
CREATE TABLE t41(a INTEGER PRIMARY KEY, b INTEGER);
CREATE TABLE t42(d INTEGER PRIMARY KEY, e INTEGER);
CREATE TABLE t43(f INTEGER PRIMARY KEY, g INTEGER);
EXPLAIN QUERY PLAN
SELECT *
FROM t41
LEFT JOIN (SELECT count(*) AS cnt, x1.d
FROM (t42 INNER JOIN t43 ON d=g) AS x1
WHERE x1.d>5
GROUP BY x1.d) AS x2
ON t41.b=x2.d;
} {/.*SEARCH SUBQUERY 1 AS x2 USING AUTOMATIC.*/}
finish_test finish_test

View File

@@ -16,7 +16,7 @@ set testprefix spellfix
ifcapable !vtab { finish_test ; return } ifcapable !vtab { finish_test ; return }
register_spellfix_module db load_static_extension db spellfix nextchar
set vocab { set vocab {
rabbi rabbit rabbits rabble rabid rabies raccoon raccoons race raced racer rabbi rabbit rabbits rabble rabid rabies raccoon raccoons race raced racer
@@ -84,6 +84,26 @@ foreach {tn word res} {
} $res } $res
} }
# Tests of the next_char function.
#
do_test 1.10 {
db eval {
CREATE TABLE vocab(w TEXT PRIMARY KEY);
INSERT INTO vocab SELECT word FROM t1;
}
} {}
do_execsql_test 1.11 {
SELECT next_char('re','vocab','w');
} {a}
do_execsql_test 1.12 {
SELECT next_char('r','vocab','w');
} {ae}
do_execsql_test 1.13 {
SELECT next_char('','vocab','w');
} {r}
do_test 1.14 {
catchsql {SELECT next_char('','xyzzy','a')}
} {1 {no such table: xyzzy}}
do_execsql_test 2.1 { do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t2 USING spellfix1; CREATE VIRTUAL TABLE t2 USING spellfix1;

View File

@@ -46,7 +46,7 @@ for {set ii 1} {$ii<=10} {incr ii} {
db close db close
forcedelete test.db test.db-wal forcedelete test.db test.db-wal
sqlite3 db test.db sqlite3 db test.db
register_wholenumber_module db load_static_extension db wholenumber
db eval { db eval {
PRAGMA journal_mode=WAL; PRAGMA journal_mode=WAL;
CREATE TABLE t1(a,b); CREATE TABLE t1(a,b);

View File

@@ -296,13 +296,27 @@ do_test where8-3.21 {
SELECT a, d FROM t1, (t2) WHERE (a=d OR b=e) AND a<5 ORDER BY a SELECT a, d FROM t1, (t2) WHERE (a=d OR b=e) AND a<5 ORDER BY a
} }
} {1 1 2 2 3 3 4 2 4 4 0 0} } {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.21.1 {
execsql_status {
SELECT a, d FROM t1, ((t2)) AS t3 WHERE (a=d OR b=e) AND a<5 ORDER BY a
}
} {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.21.2 {
execsql_status {
SELECT a, d FROM t1, ((SELECT * FROM t2)) AS t3 WHERE (a=d OR b=e) AND a<5 ORDER BY a
}
} {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.22 { do_test where8-3.22 {
execsql_status { execsql_status {
SELECT a, d FROM ((((((t1))), (((t2)))))) SELECT a, d FROM ((((((t1))), (((t2))))))
WHERE (a=d OR b=e) AND a<5 ORDER BY a WHERE (a=d OR b=e) AND a<5 ORDER BY a
} }
} {1 1 2 2 3 3 4 2 4 4 0 0} } {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.23 {
execsql_status {
SELECT * FROM ((SELECT * FROM t2)) AS t3;
}
} {1 {} I 2 four IV 3 {} IX 4 sixteen XVI 5 {} XXV 6 thirtysix XXXVI 7 fortynine XLIX 8 sixtyeight LXIV 9 eightyone LXXXIX 10 {} C 9 0}
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
# The following tests - where8-4.* - verify that adding or removing # The following tests - where8-4.* - verify that adding or removing

View File

@@ -59,7 +59,7 @@ do_test zerodamage-2.0 {
} }
tv filter xDelete tv filter xDelete
tv script xDeleteCallback tv script xDeleteCallback
register_wholenumber_module db load_static_extension db wholenumber
db eval { db eval {
PRAGMA page_size=1024; PRAGMA page_size=1024;
PRAGMA journal_mode=DELETE; PRAGMA journal_mode=DELETE;

View File

@@ -15,12 +15,8 @@ gcc -o sqlite3 -g -Os -I. \
-DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_STAT3 \
-DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_REGEXP \
-DSQLITE_ENABLE_SPELLFIX -DSQLITE_CORE=1 \
-DHAVE_READLINE \ -DHAVE_READLINE \
-DHAVE_USLEEP=1 \ -DHAVE_USLEEP=1 \
../sqlite/src/shell.c \ ../sqlite/src/shell.c \
../sqlite/src/test_regexp.c \
../sqlite/src/test_spellfix.c \
../sqlite/src/test_vfstrace.c \ ../sqlite/src/test_vfstrace.c \
sqlite3.c -ldl -lreadline -lncurses sqlite3.c -ldl -lreadline -lncurses

View File

@@ -176,7 +176,7 @@ static void print_db_header(void){
print_decode_line(aData, 56, 4, "Text encoding"); print_decode_line(aData, 56, 4, "Text encoding");
print_decode_line(aData, 60, 4, "User version"); print_decode_line(aData, 60, 4, "User version");
print_decode_line(aData, 64, 4, "Incremental-vacuum mode"); print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
print_decode_line(aData, 68, 4, "meta[7]"); print_decode_line(aData, 68, 4, "Application ID");
print_decode_line(aData, 72, 4, "meta[8]"); print_decode_line(aData, 72, 4, "meta[8]");
print_decode_line(aData, 76, 4, "meta[9]"); print_decode_line(aData, 76, 4, "meta[9]");
print_decode_line(aData, 80, 4, "meta[10]"); print_decode_line(aData, 80, 4, "meta[10]");