Merge the latest trunk enhancements into the sessions branch.
FossilOrigin-Name: 8baef58170ff851d0c4387a6888f59b487b4f33c
This commit is contained in:
commit
efb1ca3738
459
ext/fts3/fts3.c
459
ext/fts3/fts3.c
@ -438,7 +438,7 @@ static void fts3GetReverseVarint(
|
||||
sqlite3_int64 *pVal
|
||||
){
|
||||
sqlite3_int64 iVal;
|
||||
char *p = *pp;
|
||||
char *p;
|
||||
|
||||
/* Pointer p now points at the first byte past the varint we are
|
||||
** interested in. So, unless the doclist is corrupt, the 0x80 bit is
|
||||
@ -468,6 +468,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(p->zSegmentsTbl);
|
||||
sqlite3_free(p->zReadExprlist);
|
||||
sqlite3_free(p->zWriteExprlist);
|
||||
sqlite3_free(p->zContentTbl);
|
||||
|
||||
/* Invoke the tokenizer destructor to free the tokenizer. */
|
||||
p->pTokenizer->pModule->xDestroy(p->pTokenizer);
|
||||
@ -507,16 +508,19 @@ static void fts3DbExec(
|
||||
** The xDestroy() virtual table method.
|
||||
*/
|
||||
static int fts3DestroyMethod(sqlite3_vtab *pVtab){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Fts3Table *p = (Fts3Table *)pVtab;
|
||||
sqlite3 *db = p->db;
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */
|
||||
sqlite3 *db = p->db; /* Database handle */
|
||||
|
||||
/* Drop the shadow tables */
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName);
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName);
|
||||
}
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName);
|
||||
|
||||
/* If everything has worked, invoke fts3DisconnectMethod() to free the
|
||||
** memory associated with the Fts3Table structure and return SQLITE_OK.
|
||||
@ -578,23 +582,27 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
|
||||
static int fts3CreateTables(Fts3Table *p){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int i; /* Iterator variable */
|
||||
char *zContentCols; /* Columns of %_content table */
|
||||
sqlite3 *db = p->db; /* The database connection */
|
||||
|
||||
/* Create a list of user columns for the content table */
|
||||
zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
|
||||
for(i=0; zContentCols && i<p->nColumn; i++){
|
||||
char *z = p->azColumn[i];
|
||||
zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
|
||||
}
|
||||
if( zContentCols==0 ) rc = SQLITE_NOMEM;
|
||||
if( p->zContentTbl==0 ){
|
||||
char *zContentCols; /* Columns of %_content table */
|
||||
|
||||
/* Create a list of user columns for the content table */
|
||||
zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
|
||||
for(i=0; zContentCols && i<p->nColumn; i++){
|
||||
char *z = p->azColumn[i];
|
||||
zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
|
||||
}
|
||||
if( zContentCols==0 ) rc = SQLITE_NOMEM;
|
||||
|
||||
/* Create the content table */
|
||||
fts3DbExec(&rc, db,
|
||||
"CREATE TABLE %Q.'%q_content'(%s)",
|
||||
p->zDb, p->zName, zContentCols
|
||||
);
|
||||
sqlite3_free(zContentCols);
|
||||
}
|
||||
|
||||
/* Create the content table */
|
||||
fts3DbExec(&rc, db,
|
||||
"CREATE TABLE %Q.'%q_content'(%s)",
|
||||
p->zDb, p->zName, zContentCols
|
||||
);
|
||||
sqlite3_free(zContentCols);
|
||||
/* Create other tables */
|
||||
fts3DbExec(&rc, db,
|
||||
"CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
|
||||
@ -745,8 +753,8 @@ static char *fts3QuoteId(char const *zInput){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a list of comma separated SQL expressions that could be used
|
||||
** in a SELECT statement such as the following:
|
||||
** Return a list of comma separated SQL expressions and a FROM clause that
|
||||
** could be used in a SELECT statement such as the following:
|
||||
**
|
||||
** SELECT <list of expressions> FROM %_content AS x ...
|
||||
**
|
||||
@ -757,7 +765,7 @@ static char *fts3QuoteId(char const *zInput){
|
||||
** table has the three user-defined columns "a", "b", and "c", the following
|
||||
** string is returned:
|
||||
**
|
||||
** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c')"
|
||||
** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x"
|
||||
**
|
||||
** The pointer returned points to a buffer allocated by sqlite3_malloc(). It
|
||||
** is the responsibility of the caller to eventually free it.
|
||||
@ -773,16 +781,28 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
||||
char *zFunction;
|
||||
int i;
|
||||
|
||||
if( !zFunc ){
|
||||
zFunction = "";
|
||||
if( p->zContentTbl==0 ){
|
||||
if( !zFunc ){
|
||||
zFunction = "";
|
||||
}else{
|
||||
zFree = zFunction = fts3QuoteId(zFunc);
|
||||
}
|
||||
fts3Appendf(pRc, &zRet, "docid");
|
||||
for(i=0; i<p->nColumn; i++){
|
||||
fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
|
||||
}
|
||||
sqlite3_free(zFree);
|
||||
}else{
|
||||
zFree = zFunction = fts3QuoteId(zFunc);
|
||||
fts3Appendf(pRc, &zRet, "rowid");
|
||||
for(i=0; i<p->nColumn; i++){
|
||||
fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]);
|
||||
}
|
||||
}
|
||||
fts3Appendf(pRc, &zRet, "docid");
|
||||
for(i=0; i<p->nColumn; i++){
|
||||
fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
|
||||
}
|
||||
sqlite3_free(zFree);
|
||||
fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x",
|
||||
p->zDb,
|
||||
(p->zContentTbl ? p->zContentTbl : p->zName),
|
||||
(p->zContentTbl ? "" : "_content")
|
||||
);
|
||||
return zRet;
|
||||
}
|
||||
|
||||
@ -839,7 +859,7 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
||||
** This function is used when parsing the "prefix=" FTS4 parameter.
|
||||
*/
|
||||
static int fts3GobbleInt(const char **pp, int *pnOut){
|
||||
const char *p = *pp; /* Iterator pointer */
|
||||
const char *p; /* Iterator pointer */
|
||||
int nInt = 0; /* Output value */
|
||||
|
||||
for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
|
||||
@ -906,6 +926,91 @@ static int fts3PrefixParameter(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when initializing an FTS4 table that uses the
|
||||
** content=xxx option. It determines the number of and names of the columns
|
||||
** of the new FTS4 table.
|
||||
**
|
||||
** The third argument passed to this function is the value passed to the
|
||||
** config=xxx option (i.e. "xxx"). This function queries the database for
|
||||
** a table of that name. If found, the output variables are populated
|
||||
** as follows:
|
||||
**
|
||||
** *pnCol: Set to the number of columns table xxx has,
|
||||
**
|
||||
** *pnStr: Set to the total amount of space required to store a copy
|
||||
** of each columns name, including the nul-terminator.
|
||||
**
|
||||
** *pazCol: Set to point to an array of *pnCol strings. Each string is
|
||||
** the name of the corresponding column in table xxx. The array
|
||||
** and its contents are allocated using a single allocation. It
|
||||
** is the responsibility of the caller to free this allocation
|
||||
** by eventually passing the *pazCol value to sqlite3_free().
|
||||
**
|
||||
** If the table cannot be found, an error code is returned and the output
|
||||
** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is
|
||||
** returned (and the output variables are undefined).
|
||||
*/
|
||||
static int fts3ContentColumns(
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */
|
||||
const char *zTbl, /* Name of content table */
|
||||
const char ***pazCol, /* OUT: Malloc'd array of column names */
|
||||
int *pnCol, /* OUT: Size of array *pazCol */
|
||||
int *pnStr /* OUT: Bytes of string content */
|
||||
){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
char *zSql; /* "SELECT *" statement on zTbl */
|
||||
sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */
|
||||
|
||||
zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl);
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
const char **azCol; /* Output array */
|
||||
int nStr = 0; /* Size of all column names (incl. 0x00) */
|
||||
int nCol; /* Number of table columns */
|
||||
int i; /* Used to iterate through columns */
|
||||
|
||||
/* Loop through the returned columns. Set nStr to the number of bytes of
|
||||
** space required to store a copy of each column name, including the
|
||||
** nul-terminator byte. */
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
for(i=0; i<nCol; i++){
|
||||
const char *zCol = sqlite3_column_name(pStmt, i);
|
||||
nStr += strlen(zCol) + 1;
|
||||
}
|
||||
|
||||
/* Allocate and populate the array to return. */
|
||||
azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
|
||||
if( azCol==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
char *p = (char *)&azCol[nCol];
|
||||
for(i=0; i<nCol; i++){
|
||||
const char *zCol = sqlite3_column_name(pStmt, i);
|
||||
int n = strlen(zCol)+1;
|
||||
memcpy(p, zCol, n);
|
||||
azCol[i] = p;
|
||||
p += n;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
/* Set the output variables. */
|
||||
*pnCol = nCol;
|
||||
*pnStr = nStr;
|
||||
*pazCol = azCol;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is the implementation of both the xConnect and xCreate
|
||||
** methods of the FTS3 virtual table.
|
||||
@ -950,6 +1055,7 @@ static int fts3InitVtab(
|
||||
char *zPrefix = 0; /* Prefix parameter value (or NULL) */
|
||||
char *zCompress = 0; /* compress=? parameter (or NULL) */
|
||||
char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
|
||||
char *zContent = 0; /* content=? parameter (or NULL) */
|
||||
|
||||
assert( strlen(argv[0])==4 );
|
||||
assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
|
||||
@ -993,13 +1099,13 @@ static int fts3InitVtab(
|
||||
struct Fts4Option {
|
||||
const char *zOpt;
|
||||
int nOpt;
|
||||
char **pzVar;
|
||||
} aFts4Opt[] = {
|
||||
{ "matchinfo", 9, 0 }, /* 0 -> MATCHINFO */
|
||||
{ "prefix", 6, 0 }, /* 1 -> PREFIX */
|
||||
{ "compress", 8, 0 }, /* 2 -> COMPRESS */
|
||||
{ "uncompress", 10, 0 }, /* 3 -> UNCOMPRESS */
|
||||
{ "order", 5, 0 } /* 4 -> ORDER */
|
||||
{ "matchinfo", 9 }, /* 0 -> MATCHINFO */
|
||||
{ "prefix", 6 }, /* 1 -> PREFIX */
|
||||
{ "compress", 8 }, /* 2 -> COMPRESS */
|
||||
{ "uncompress", 10 }, /* 3 -> UNCOMPRESS */
|
||||
{ "order", 5 }, /* 4 -> ORDER */
|
||||
{ "content", 7 } /* 5 -> CONTENT */
|
||||
};
|
||||
|
||||
int iOpt;
|
||||
@ -1045,13 +1151,20 @@ static int fts3InitVtab(
|
||||
|
||||
case 4: /* ORDER */
|
||||
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
||||
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3))
|
||||
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
||||
){
|
||||
*pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
|
||||
break;
|
||||
|
||||
default: /* CONTENT */
|
||||
assert( iOpt==5 );
|
||||
sqlite3_free(zUncompress);
|
||||
zContent = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_free(zVal);
|
||||
@ -1064,6 +1177,26 @@ static int fts3InitVtab(
|
||||
aCol[nCol++] = z;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a content=xxx option was specified, the following:
|
||||
**
|
||||
** 1. Ignore any compress= and uncompress= options.
|
||||
**
|
||||
** 2. If no column names were specified as part of the CREATE VIRTUAL
|
||||
** TABLE statement, use all columns from the content table.
|
||||
*/
|
||||
if( rc==SQLITE_OK && zContent ){
|
||||
sqlite3_free(zCompress);
|
||||
sqlite3_free(zUncompress);
|
||||
zCompress = 0;
|
||||
zUncompress = 0;
|
||||
if( nCol==0 ){
|
||||
sqlite3_free((void*)aCol);
|
||||
aCol = 0;
|
||||
rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
|
||||
}
|
||||
assert( rc!=SQLITE_OK || nCol>0 );
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto fts3_init_out;
|
||||
|
||||
if( nCol==0 ){
|
||||
@ -1108,6 +1241,8 @@ static int fts3InitVtab(
|
||||
p->bHasDocsize = (isFts4 && bNoDocsize==0);
|
||||
p->bHasStat = isFts4;
|
||||
p->bDescIdx = bDescIdx;
|
||||
p->zContentTbl = zContent;
|
||||
zContent = 0;
|
||||
TESTONLY( p->inTransaction = -1 );
|
||||
TESTONLY( p->mxSavepoint = -1 );
|
||||
|
||||
@ -1169,6 +1304,7 @@ fts3_init_out:
|
||||
sqlite3_free(aIndex);
|
||||
sqlite3_free(zCompress);
|
||||
sqlite3_free(zUncompress);
|
||||
sqlite3_free(zContent);
|
||||
sqlite3_free((void *)aCol);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( p ){
|
||||
@ -1320,35 +1456,64 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then
|
||||
** compose and prepare an SQL statement of the form:
|
||||
**
|
||||
** "SELECT <columns> FROM %_content WHERE rowid = ?"
|
||||
**
|
||||
** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
|
||||
** it. If an error occurs, return an SQLite error code.
|
||||
**
|
||||
** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
|
||||
*/
|
||||
static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->pStmt==0 ){
|
||||
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
|
||||
char *zSql;
|
||||
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
*ppStmt = pCsr->pStmt;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Position the pCsr->pStmt statement so that it is on the row
|
||||
** of the %_content table that contains the last match. Return
|
||||
** SQLITE_OK on success.
|
||||
*/
|
||||
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->isRequireSeek ){
|
||||
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
|
||||
pCsr->isRequireSeek = 0;
|
||||
if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
int rc = sqlite3_reset(pCsr->pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* If no row was found and no error has occured, then the %_content
|
||||
** table is missing a row that is present in the full-text index.
|
||||
** The data structures are corrupt.
|
||||
*/
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
rc = fts3CursorSeekStmt(pCsr, &pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
|
||||
pCsr->isRequireSeek = 0;
|
||||
if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
|
||||
/* If no row was found and no error has occured, then the %_content
|
||||
** table is missing a row that is present in the full-text index.
|
||||
** The data structures are corrupt. */
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
pCsr->isEof = 1;
|
||||
}
|
||||
}
|
||||
pCsr->isEof = 1;
|
||||
if( pContext ){
|
||||
sqlite3_result_error_code(pContext, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK && pContext ){
|
||||
sqlite3_result_error_code(pContext, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1398,7 +1563,7 @@ static int fts3ScanInteriorNode(
|
||||
zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
|
||||
zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
|
||||
if( zCsr>zEnd ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
while( zCsr<zEnd && (piFirst || piLast) ){
|
||||
@ -1416,7 +1581,7 @@ static int fts3ScanInteriorNode(
|
||||
zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
|
||||
|
||||
if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
if( nPrefix+nSuffix>nAlloc ){
|
||||
@ -1429,6 +1594,7 @@ static int fts3ScanInteriorNode(
|
||||
}
|
||||
zBuffer = zNew;
|
||||
}
|
||||
assert( zBuffer );
|
||||
memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
|
||||
nBuffer = nPrefix + nSuffix;
|
||||
zCsr += nSuffix;
|
||||
@ -1787,7 +1953,7 @@ static int fts3PoslistPhraseMerge(
|
||||
char **pp1, /* IN/OUT: Left input list */
|
||||
char **pp2 /* IN/OUT: Right input list */
|
||||
){
|
||||
char *p = (pp ? *pp : 0);
|
||||
char *p = *pp;
|
||||
char *p1 = *pp1;
|
||||
char *p2 = *pp2;
|
||||
int iCol1 = 0;
|
||||
@ -1796,7 +1962,7 @@ static int fts3PoslistPhraseMerge(
|
||||
/* Never set both isSaveLeft and isExact for the same invocation. */
|
||||
assert( isSaveLeft==0 || isExact==0 );
|
||||
|
||||
assert( *p1!=0 && *p2!=0 );
|
||||
assert( p!=0 && *p1!=0 && *p2!=0 );
|
||||
if( *p1==POS_COLUMN ){
|
||||
p1++;
|
||||
p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
|
||||
@ -1813,7 +1979,7 @@ static int fts3PoslistPhraseMerge(
|
||||
sqlite3_int64 iPos1 = 0;
|
||||
sqlite3_int64 iPos2 = 0;
|
||||
|
||||
if( pp && iCol1 ){
|
||||
if( iCol1 ){
|
||||
*p++ = POS_COLUMN;
|
||||
p += sqlite3Fts3PutVarint(p, iCol1);
|
||||
}
|
||||
@ -1828,16 +1994,10 @@ static int fts3PoslistPhraseMerge(
|
||||
|| (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
|
||||
){
|
||||
sqlite3_int64 iSave;
|
||||
if( !pp ){
|
||||
fts3PoslistCopy(0, &p2);
|
||||
fts3PoslistCopy(0, &p1);
|
||||
*pp1 = p1;
|
||||
*pp2 = p2;
|
||||
return 1;
|
||||
}
|
||||
iSave = isSaveLeft ? iPos1 : iPos2;
|
||||
fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2;
|
||||
pSave = 0;
|
||||
assert( p );
|
||||
}
|
||||
if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){
|
||||
if( (*p2&0xFE)==0 ) break;
|
||||
@ -1886,7 +2046,7 @@ static int fts3PoslistPhraseMerge(
|
||||
fts3PoslistCopy(0, &p1);
|
||||
*pp1 = p1;
|
||||
*pp2 = p2;
|
||||
if( !pp || *pp==p ){
|
||||
if( *pp==p ){
|
||||
return 0;
|
||||
}
|
||||
*p++ = 0x00;
|
||||
@ -2189,6 +2349,56 @@ static void fts3DoclistPhraseMerge(
|
||||
*pnRight = p - aOut;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument pList points to a position list nList bytes in size. This
|
||||
** function checks to see if the position list contains any entries for
|
||||
** a token in position 0 (of any column). If so, it writes argument iDelta
|
||||
** to the output buffer pOut, followed by a position list consisting only
|
||||
** of the entries from pList at position 0, and terminated by an 0x00 byte.
|
||||
** The value returned is the number of bytes written to pOut (if any).
|
||||
*/
|
||||
int sqlite3Fts3FirstFilter(
|
||||
sqlite3_int64 iDelta, /* Varint that may be written to pOut */
|
||||
char *pList, /* Position list (no 0x00 term) */
|
||||
int nList, /* Size of pList in bytes */
|
||||
char *pOut /* Write output here */
|
||||
){
|
||||
int nOut = 0;
|
||||
int bWritten = 0; /* True once iDelta has been written */
|
||||
char *p = pList;
|
||||
char *pEnd = &pList[nList];
|
||||
|
||||
if( *p!=0x01 ){
|
||||
if( *p==0x02 ){
|
||||
nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta);
|
||||
pOut[nOut++] = 0x02;
|
||||
bWritten = 1;
|
||||
}
|
||||
fts3ColumnlistCopy(0, &p);
|
||||
}
|
||||
|
||||
while( p<pEnd && *p==0x01 ){
|
||||
sqlite3_int64 iCol;
|
||||
p++;
|
||||
p += sqlite3Fts3GetVarint(p, &iCol);
|
||||
if( *p==0x02 ){
|
||||
if( bWritten==0 ){
|
||||
nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta);
|
||||
bWritten = 1;
|
||||
}
|
||||
pOut[nOut++] = 0x01;
|
||||
nOut += sqlite3Fts3PutVarint(&pOut[nOut], iCol);
|
||||
pOut[nOut++] = 0x02;
|
||||
}
|
||||
fts3ColumnlistCopy(0, &p);
|
||||
}
|
||||
if( bWritten ){
|
||||
pOut[nOut++] = 0x00;
|
||||
}
|
||||
|
||||
return nOut;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Merge all doclists in the TermSelect.aaOutput[] array into a single
|
||||
@ -2545,6 +2755,7 @@ static int fts3TermSelect(
|
||||
|
||||
filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS
|
||||
| (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0)
|
||||
| (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0)
|
||||
| (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
|
||||
filter.iCol = iColumn;
|
||||
filter.zTerm = pTok->z;
|
||||
@ -2685,8 +2896,8 @@ static int fts3FilterMethod(
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn,
|
||||
iCol, zQuery, -1, &pCsr->pExpr
|
||||
rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat,
|
||||
p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_ERROR ){
|
||||
@ -2713,23 +2924,24 @@ static int fts3FilterMethod(
|
||||
** row by docid.
|
||||
*/
|
||||
if( idxNum==FTS3_FULLSCAN_SEARCH ){
|
||||
const char *zSort = (pCsr->bDesc ? "DESC" : "ASC");
|
||||
const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s";
|
||||
zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort);
|
||||
}else{
|
||||
const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?";
|
||||
zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName);
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT %s ORDER BY rowid %s",
|
||||
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
|
||||
);
|
||||
if( zSql ){
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}else if( idxNum==FTS3_DOCID_SEARCH ){
|
||||
rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
|
||||
}
|
||||
}
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
if( idxNum==FTS3_DOCID_SEARCH ){
|
||||
rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
return fts3NextMethod(pCursor);
|
||||
}
|
||||
|
||||
@ -2781,7 +2993,7 @@ static int fts3ColumnMethod(
|
||||
sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
|
||||
}else{
|
||||
rc = fts3CursorSeek(0, pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
|
||||
sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
|
||||
}
|
||||
}
|
||||
@ -2865,7 +3077,7 @@ static int fts3RollbackMethod(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static void fts3ReversePoslist(char *pStart, char **ppPoslist){
|
||||
char *p = &(*ppPoslist)[-2];
|
||||
char c;
|
||||
char c = 0;
|
||||
|
||||
while( p>pStart && (c=*p--)==0 );
|
||||
while( p>pStart && (*p & 0x80) | c ){
|
||||
@ -3074,15 +3286,22 @@ static int fts3RenameMethod(
|
||||
sqlite3 *db = p->db; /* Database connection */
|
||||
int rc; /* Return Code */
|
||||
|
||||
/* As it happens, the pending terms table is always empty here. This is
|
||||
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
|
||||
** always opens a savepoint transaction. And the xSavepoint() method
|
||||
** flushes the pending terms table. But leave the (no-op) call to
|
||||
** PendingTermsFlush() in in case that changes.
|
||||
*/
|
||||
assert( p->nPendingData==0 );
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db,
|
||||
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
|
||||
p->zDb, p->zName, zName
|
||||
);
|
||||
}
|
||||
|
||||
fts3DbExec(&rc, db,
|
||||
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
|
||||
p->zDb, p->zName, zName
|
||||
);
|
||||
if( p->bHasDocsize ){
|
||||
fts3DbExec(&rc, db,
|
||||
"ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
|
||||
@ -3441,21 +3660,20 @@ static int fts3EvalPhraseLoad(
|
||||
*/
|
||||
static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
||||
int iToken; /* Used to iterate through phrase tokens */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
char *aPoslist = 0; /* Position list for deferred tokens */
|
||||
int nPoslist = 0; /* Number of bytes in aPoslist */
|
||||
int iPrev = -1; /* Token number of previous deferred token */
|
||||
|
||||
assert( pPhrase->doclist.bFreeList==0 );
|
||||
|
||||
for(iToken=0; rc==SQLITE_OK && iToken<pPhrase->nToken; iToken++){
|
||||
for(iToken=0; iToken<pPhrase->nToken; iToken++){
|
||||
Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
|
||||
Fts3DeferredToken *pDeferred = pToken->pDeferred;
|
||||
|
||||
if( pDeferred ){
|
||||
char *pList;
|
||||
int nList;
|
||||
rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
|
||||
int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
if( pList==0 ){
|
||||
@ -3556,6 +3774,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
|
||||
&& p->nToken==1
|
||||
&& pFirst->pSegcsr
|
||||
&& pFirst->pSegcsr->bLookup
|
||||
&& pFirst->bFirst==0
|
||||
){
|
||||
/* Use the incremental approach. */
|
||||
int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
|
||||
@ -3785,7 +4004,7 @@ static void fts3EvalTokenCosts(
|
||||
Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */
|
||||
int *pRc /* IN/OUT: Error code */
|
||||
){
|
||||
if( *pRc==SQLITE_OK && pExpr ){
|
||||
if( *pRc==SQLITE_OK ){
|
||||
if( pExpr->eType==FTSQUERY_PHRASE ){
|
||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||
int i;
|
||||
@ -3799,6 +4018,11 @@ static void fts3EvalTokenCosts(
|
||||
*pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl);
|
||||
}
|
||||
}else if( pExpr->eType!=FTSQUERY_NOT ){
|
||||
assert( pExpr->eType==FTSQUERY_OR
|
||||
|| pExpr->eType==FTSQUERY_AND
|
||||
|| pExpr->eType==FTSQUERY_NEAR
|
||||
);
|
||||
assert( pExpr->pLeft && pExpr->pRight );
|
||||
if( pExpr->eType==FTSQUERY_OR ){
|
||||
pRoot = pExpr->pLeft;
|
||||
**ppOr = pRoot;
|
||||
@ -3859,7 +4083,7 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
}
|
||||
if( nDoc==0 || nByte==0 ){
|
||||
sqlite3_reset(pStmt);
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
pCsr->nDoc = nDoc;
|
||||
@ -3903,6 +4127,15 @@ static int fts3EvalSelectDeferred(
|
||||
int nMinEst = 0; /* The minimum count for any phrase so far. */
|
||||
int nLoad4 = 1; /* (Phrases that will be loaded)^4. */
|
||||
|
||||
/* Tokens are never deferred for FTS tables created using the content=xxx
|
||||
** option. The reason being that it is not guaranteed that the content
|
||||
** table actually contains the same data as the index. To prevent this from
|
||||
** causing any problems, the deferred token optimization is completely
|
||||
** disabled for content=xxx tables. */
|
||||
if( pTab->zContentTbl ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Count the tokens in this AND/NEAR cluster. If none of the doclists
|
||||
** associated with the tokens spill onto overflow pages, or if there is
|
||||
** only 1 token, exit early. No tokens to defer in this case. */
|
||||
@ -3965,7 +4198,11 @@ static int fts3EvalSelectDeferred(
|
||||
fts3SegReaderCursorFree(pToken->pSegcsr);
|
||||
pToken->pSegcsr = 0;
|
||||
}else{
|
||||
nLoad4 = nLoad4*4;
|
||||
/* Set nLoad4 to the value of (4^nOther) for the next iteration of the
|
||||
** for-loop. Except, limit the value to 2^24 to prevent it from
|
||||
** overflowing the 32-bit integer it is stored in. */
|
||||
if( ii<12 ) nLoad4 = nLoad4*4;
|
||||
|
||||
if( ii==0 || pTC->pPhrase->nToken>1 ){
|
||||
/* Either this is the cheapest token in the entire query, or it is
|
||||
** part of a multi-token phrase. Either way, the entire doclist will
|
||||
@ -4335,8 +4572,11 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
aPoslist = pExpr->pRight->pPhrase->doclist.pList;
|
||||
nToken = pExpr->pRight->pPhrase->nToken;
|
||||
for(p=pExpr->pLeft; p && res; p=p->pLeft){
|
||||
int nNear = p->pParent->nNear;
|
||||
Fts3Phrase *pPhrase = (
|
||||
int nNear;
|
||||
Fts3Phrase *pPhrase;
|
||||
assert( p->pParent && p->pParent->pLeft==p );
|
||||
nNear = p->pParent->nNear;
|
||||
pPhrase = (
|
||||
p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
|
||||
);
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
@ -4826,6 +5066,15 @@ void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return SQLITE_CORRUPT_VTAB.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3Fts3Corrupt(){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SQLITE_CORE
|
||||
/*
|
||||
** Initialize API pointer table, if required.
|
||||
|
@ -157,6 +157,13 @@ typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */
|
||||
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3Fts3Corrupt(void);
|
||||
# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt()
|
||||
#else
|
||||
# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB
|
||||
#endif
|
||||
|
||||
typedef struct Fts3Table Fts3Table;
|
||||
typedef struct Fts3Cursor Fts3Cursor;
|
||||
typedef struct Fts3Expr Fts3Expr;
|
||||
@ -184,6 +191,7 @@ struct Fts3Table {
|
||||
int nColumn; /* number of named columns in virtual table */
|
||||
char **azColumn; /* column names. malloced */
|
||||
sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
|
||||
char *zContentTbl; /* content=xxx option, or NULL */
|
||||
|
||||
/* Precompiled statements used by the implementation. Each of these
|
||||
** statements is run and reset within a single virtual table API call.
|
||||
@ -224,7 +232,7 @@ struct Fts3Table {
|
||||
int nPendingData; /* Current bytes of pending data */
|
||||
sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
/* State variables used for validating that the transaction control
|
||||
** methods of the virtual table are called at appropriate times. These
|
||||
** values do not contribution to the FTS computation; they are used for
|
||||
@ -309,6 +317,7 @@ struct Fts3PhraseToken {
|
||||
char *z; /* Text of the token */
|
||||
int n; /* Number of bytes in buffer z */
|
||||
int isPrefix; /* True if token ends with a "*" character */
|
||||
int bFirst; /* True if token must appear at position 0 */
|
||||
|
||||
/* Variables above this point are populated when the expression is
|
||||
** parsed (by code in fts3_expr.c). Below this point the variables are
|
||||
@ -427,6 +436,7 @@ int sqlite3Fts3SegReaderCursor(
|
||||
#define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
|
||||
#define FTS3_SEGMENT_PREFIX 0x00000008
|
||||
#define FTS3_SEGMENT_SCAN 0x00000010
|
||||
#define FTS3_SEGMENT_FIRST 0x00000020
|
||||
|
||||
/* Type passed as 4th argument to SegmentReaderIterate() */
|
||||
struct Fts3SegFilter {
|
||||
@ -466,8 +476,8 @@ int sqlite3Fts3GetVarint32(const char *, int *);
|
||||
int sqlite3Fts3VarintLen(sqlite3_uint64);
|
||||
void sqlite3Fts3Dequote(char *);
|
||||
void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
|
||||
|
||||
int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
|
||||
int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
|
||||
|
||||
/* fts3_tokenizer.c */
|
||||
const char *sqlite3Fts3NextToken(const char *, int *);
|
||||
@ -486,7 +496,7 @@ void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
|
||||
|
||||
/* fts3_expr.c */
|
||||
int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
|
||||
char **, int, int, const char *, int, Fts3Expr **
|
||||
char **, int, int, int, const char *, int, Fts3Expr **
|
||||
);
|
||||
void sqlite3Fts3ExprFree(Fts3Expr *);
|
||||
#ifdef SQLITE_TEST
|
||||
|
@ -93,6 +93,7 @@ typedef struct ParseContext ParseContext;
|
||||
struct ParseContext {
|
||||
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
|
||||
const 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 */
|
||||
int isNot; /* True if getNextNode() sees a unary - */
|
||||
@ -180,9 +181,21 @@ static int getNextToken(
|
||||
pRet->pPhrase->aToken[0].isPrefix = 1;
|
||||
iEnd++;
|
||||
}
|
||||
if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
|
||||
pParse->isNot = 1;
|
||||
|
||||
while( 1 ){
|
||||
if( !sqlite3_fts3_enable_parentheses
|
||||
&& iStart>0 && z[iStart-1]=='-'
|
||||
){
|
||||
pParse->isNot = 1;
|
||||
iStart--;
|
||||
}else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){
|
||||
pRet->pPhrase->aToken[0].bFirst = 1;
|
||||
iStart--;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
nConsumed = iEnd;
|
||||
}
|
||||
@ -281,6 +294,7 @@ static int getNextString(
|
||||
|
||||
pToken->n = nByte;
|
||||
pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
|
||||
pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
|
||||
nToken = ii+1;
|
||||
}
|
||||
}
|
||||
@ -302,8 +316,12 @@ static int getNextString(
|
||||
p->pPhrase->nToken = nToken;
|
||||
|
||||
zBuf = (char *)&p->pPhrase->aToken[nToken];
|
||||
memcpy(zBuf, zTemp, nTemp);
|
||||
sqlite3_free(zTemp);
|
||||
if( zTemp ){
|
||||
memcpy(zBuf, zTemp, nTemp);
|
||||
sqlite3_free(zTemp);
|
||||
}else{
|
||||
assert( nTemp==0 );
|
||||
}
|
||||
|
||||
for(jj=0; jj<p->pPhrase->nToken; jj++){
|
||||
p->pPhrase->aToken[jj].z = zBuf;
|
||||
@ -728,6 +746,7 @@ exprparse_out:
|
||||
int sqlite3Fts3ExprParse(
|
||||
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
|
||||
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 */
|
||||
@ -741,6 +760,7 @@ int sqlite3Fts3ExprParse(
|
||||
sParse.nCol = nCol;
|
||||
sParse.iDefaultCol = iDefaultCol;
|
||||
sParse.nNest = 0;
|
||||
sParse.bFts4 = bFts4;
|
||||
if( z==0 ){
|
||||
*ppExpr = 0;
|
||||
return SQLITE_OK;
|
||||
@ -930,7 +950,7 @@ static void fts3ExprTest(
|
||||
}
|
||||
|
||||
rc = sqlite3Fts3ExprParse(
|
||||
pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
|
||||
pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
|
||||
);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
|
||||
sqlite3_result_error(context, "Error parsing expression", -1);
|
||||
|
@ -368,6 +368,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
int iFirst = 0;
|
||||
pPhrase->pList = pCsr;
|
||||
fts3GetDeltaPosition(&pCsr, &iFirst);
|
||||
assert( iFirst>=0 );
|
||||
pPhrase->pHead = pCsr;
|
||||
pPhrase->pTail = pCsr;
|
||||
pPhrase->iHead = iFirst;
|
||||
@ -848,7 +849,7 @@ static int fts3MatchinfoSelectDoctotal(
|
||||
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
if( nDoc==0 ) return SQLITE_CORRUPT_VTAB;
|
||||
if( nDoc==0 ) return FTS_CORRUPT_VTAB;
|
||||
*pnDoc = (u32)nDoc;
|
||||
|
||||
if( paLen ) *paLen = a;
|
||||
@ -1409,7 +1410,7 @@ void sqlite3Fts3Offsets(
|
||||
|
||||
if( !pTerm ){
|
||||
/* All offsets for this column have been gathered. */
|
||||
break;
|
||||
rc = SQLITE_DONE;
|
||||
}else{
|
||||
assert( iCurrent<=iMinPos );
|
||||
if( 0==(0xFE&*pTerm->pList) ){
|
||||
@ -1426,8 +1427,8 @@ void sqlite3Fts3Offsets(
|
||||
"%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
|
||||
);
|
||||
rc = fts3StringAppend(&res, aBuffer, -1);
|
||||
}else if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
}else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ static int fts3SqlStmt(
|
||||
/* 4 */ "DELETE FROM %Q.'%q_segdir'",
|
||||
/* 5 */ "DELETE FROM %Q.'%q_docsize'",
|
||||
/* 6 */ "DELETE FROM %Q.'%q_stat'",
|
||||
/* 7 */ "SELECT %s FROM %Q.'%q_content' AS x WHERE rowid=?",
|
||||
/* 7 */ "SELECT %s WHERE rowid=?",
|
||||
/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
|
||||
/* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
|
||||
/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
|
||||
@ -298,7 +298,7 @@ static int fts3SqlStmt(
|
||||
if( eStmt==SQL_CONTENT_INSERT ){
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
|
||||
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist, p->zDb, p->zName);
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
|
||||
}else{
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
|
||||
}
|
||||
@ -341,7 +341,7 @@ static int fts3SelectDocsize(
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT_VTAB;
|
||||
if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB;
|
||||
pStmt = 0;
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
@ -409,17 +409,24 @@ static void fts3SqlExec(
|
||||
** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can
|
||||
** still happen if the user reads data directly from the %_segments or
|
||||
** %_segdir tables instead of going through FTS3 though.
|
||||
**
|
||||
** This reasoning does not apply to a content=xxx table.
|
||||
*/
|
||||
int sqlite3Fts3ReadLock(Fts3Table *p){
|
||||
int rc; /* Return code */
|
||||
sqlite3_stmt *pStmt; /* Statement used to obtain lock */
|
||||
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_null(pStmt, 1);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( p->zContentTbl==0 ){
|
||||
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_null(pStmt, 1);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -780,6 +787,18 @@ static int fts3InsertData(
|
||||
int rc; /* Return code */
|
||||
sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */
|
||||
|
||||
if( p->zContentTbl ){
|
||||
sqlite3_value *pRowid = apVal[p->nColumn+3];
|
||||
if( sqlite3_value_type(pRowid)==SQLITE_NULL ){
|
||||
pRowid = apVal[1];
|
||||
}
|
||||
if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
*piDocid = sqlite3_value_int64(pRowid);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Locate the statement handle used to insert data into the %_content
|
||||
** table. The SQL for this statement is:
|
||||
**
|
||||
@ -830,14 +849,16 @@ static int fts3InsertData(
|
||||
** Remove all data from the FTS3 table. Clear the hash table containing
|
||||
** pending terms.
|
||||
*/
|
||||
static int fts3DeleteAll(Fts3Table *p){
|
||||
static int fts3DeleteAll(Fts3Table *p, int bContent){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
|
||||
/* Discard the contents of the pending-terms hash table. */
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
|
||||
/* Delete everything from the %_content, %_segments and %_segdir tables. */
|
||||
fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
|
||||
/* Delete everything from the shadow tables. Except, leave %_content as
|
||||
** is if bContent is false. */
|
||||
assert( p->zContentTbl==0 || bContent==0 );
|
||||
if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
|
||||
fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0);
|
||||
fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
|
||||
if( p->bHasDocsize ){
|
||||
@ -1145,7 +1166,7 @@ static int fts3SegReaderNext(
|
||||
if( nPrefix<0 || nSuffix<=0
|
||||
|| &pNext[nSuffix]>&pReader->aNode[pReader->nNode]
|
||||
){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
if( nPrefix+nSuffix>pReader->nTermAlloc ){
|
||||
@ -1175,7 +1196,7 @@ static int fts3SegReaderNext(
|
||||
if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode]
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -2125,12 +2146,18 @@ static void fts3SegWriterFree(SegmentWriter *pWriter){
|
||||
static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
*pisEmpty = sqlite3_column_int(pStmt, 0);
|
||||
if( p->zContentTbl ){
|
||||
/* If using the content=xxx option, assume the table is never empty */
|
||||
*pisEmpty = 0;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
*pisEmpty = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
rc = sqlite3_reset(pStmt);
|
||||
}
|
||||
rc = sqlite3_reset(pStmt);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -2482,6 +2509,7 @@ int sqlite3Fts3SegReaderStep(
|
||||
int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER);
|
||||
int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX);
|
||||
int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN);
|
||||
int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST);
|
||||
|
||||
Fts3SegReader **apSegment = pCsr->apSegment;
|
||||
int nSegment = pCsr->nSegment;
|
||||
@ -2541,6 +2569,7 @@ int sqlite3Fts3SegReaderStep(
|
||||
assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
|
||||
if( nMerge==1
|
||||
&& !isIgnoreEmpty
|
||||
&& !isFirst
|
||||
&& (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
|
||||
){
|
||||
pCsr->nDoclist = apSegment[0]->nDoclist;
|
||||
@ -2606,12 +2635,24 @@ int sqlite3Fts3SegReaderStep(
|
||||
}
|
||||
pCsr->aBuffer = aNew;
|
||||
}
|
||||
nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
|
||||
iPrev = iDocid;
|
||||
if( isRequirePos ){
|
||||
memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
|
||||
nDoclist += nList;
|
||||
pCsr->aBuffer[nDoclist++] = '\0';
|
||||
|
||||
if( isFirst ){
|
||||
char *a = &pCsr->aBuffer[nDoclist];
|
||||
int nWrite;
|
||||
|
||||
nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a);
|
||||
if( nWrite ){
|
||||
iPrev = iDocid;
|
||||
nDoclist += nWrite;
|
||||
}
|
||||
}else{
|
||||
nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
|
||||
iPrev = iDocid;
|
||||
if( isRequirePos ){
|
||||
memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
|
||||
nDoclist += nList;
|
||||
pCsr->aBuffer[nDoclist++] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2787,9 +2828,9 @@ static void fts3DecodeIntArray(
|
||||
** a blob of varints.
|
||||
*/
|
||||
static void fts3InsertDocsize(
|
||||
int *pRC, /* Result code */
|
||||
Fts3Table *p, /* Table into which to insert */
|
||||
u32 *aSz /* Sizes of each column */
|
||||
int *pRC, /* Result code */
|
||||
Fts3Table *p, /* Table into which to insert */
|
||||
u32 *aSz /* Sizes of each column, in tokens */
|
||||
){
|
||||
char *pBlob; /* The BLOB encoding of the document size */
|
||||
int nBlob; /* Number of bytes in the BLOB */
|
||||
@ -2911,6 +2952,86 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
|
||||
return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when the user executes the following statement:
|
||||
**
|
||||
** INSERT INTO <tbl>(<tbl>) VALUES('rebuild');
|
||||
**
|
||||
** The entire FTS index is discarded and rebuilt. If the table is one
|
||||
** created using the content=xxx option, then the new index is based on
|
||||
** the current contents of the xxx table. Otherwise, it is rebuilt based
|
||||
** on the contents of the %_content table.
|
||||
*/
|
||||
static int fts3DoRebuild(Fts3Table *p){
|
||||
int rc; /* Return Code */
|
||||
|
||||
rc = fts3DeleteAll(p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
u32 *aSz = 0;
|
||||
u32 *aSzIns = 0;
|
||||
u32 *aSzDel = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int nEntry = 0;
|
||||
|
||||
/* Compose and prepare an SQL statement to loop through the content table */
|
||||
char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int nByte = sizeof(u32) * (p->nColumn+1)*3;
|
||||
aSz = (u32 *)sqlite3_malloc(nByte);
|
||||
if( aSz==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(aSz, 0, nByte);
|
||||
aSzIns = &aSz[p->nColumn+1];
|
||||
aSzDel = &aSzIns[p->nColumn+1];
|
||||
}
|
||||
}
|
||||
|
||||
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int iCol;
|
||||
rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0));
|
||||
aSz[p->nColumn] = 0;
|
||||
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
|
||||
const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
|
||||
rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]);
|
||||
aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1);
|
||||
}
|
||||
if( p->bHasDocsize ){
|
||||
fts3InsertDocsize(&rc, p, aSz);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}else{
|
||||
nEntry++;
|
||||
for(iCol=0; iCol<=p->nColumn; iCol++){
|
||||
aSzIns[iCol] += aSz[iCol];
|
||||
}
|
||||
}
|
||||
}
|
||||
if( p->bHasStat ){
|
||||
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry);
|
||||
}
|
||||
sqlite3_free(aSz);
|
||||
|
||||
if( pStmt ){
|
||||
int rc2 = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Handle a 'special' INSERT of the form:
|
||||
**
|
||||
@ -2928,6 +3049,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
return SQLITE_NOMEM;
|
||||
}else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
|
||||
rc = fts3DoOptimize(p, 0);
|
||||
}else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){
|
||||
rc = fts3DoRebuild(p);
|
||||
#ifdef SQLITE_TEST
|
||||
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
|
||||
p->nNodeSize = atoi(&zVal[9]);
|
||||
@ -3008,6 +3131,7 @@ int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
|
||||
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
|
||||
Fts3PhraseToken *pPT = pDef->pToken;
|
||||
if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
|
||||
&& (pPT->bFirst==0 || iPos==0)
|
||||
&& (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
|
||||
&& (0==memcmp(zToken, pPT->z, pPT->n))
|
||||
){
|
||||
@ -3099,14 +3223,18 @@ static int fts3DeleteByRowid(
|
||||
/* Deleting this row means the whole table is empty. In this case
|
||||
** delete the contents of all three tables and throw away any
|
||||
** data in the pendingTerms hash table. */
|
||||
rc = fts3DeleteAll(p);
|
||||
rc = fts3DeleteAll(p, 1);
|
||||
*pnDoc = *pnDoc - 1;
|
||||
}else{
|
||||
sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
|
||||
rc = fts3PendingTermsDocid(p, iRemove);
|
||||
fts3DeleteTerms(&rc, p, pRowid, aSzDel);
|
||||
fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
|
||||
if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
|
||||
if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
|
||||
}else{
|
||||
*pnDoc = *pnDoc - 1;
|
||||
}
|
||||
if( p->bHasDocsize ){
|
||||
fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
|
||||
}
|
||||
@ -3129,7 +3257,6 @@ int sqlite3Fts3UpdateMethod(
|
||||
Fts3Table *p = (Fts3Table *)pVtab;
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
int isRemove = 0; /* True for an UPDATE or DELETE */
|
||||
sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */
|
||||
u32 *aSzIns = 0; /* Sizes of inserted documents */
|
||||
u32 *aSzDel; /* Sizes of deleted documents */
|
||||
int nChng = 0; /* Net change in number of documents */
|
||||
@ -3167,7 +3294,7 @@ int sqlite3Fts3UpdateMethod(
|
||||
** detect the conflict and return SQLITE_CONSTRAINT before beginning to
|
||||
** modify the database file.
|
||||
*/
|
||||
if( nArg>1 ){
|
||||
if( nArg>1 && p->zContentTbl==0 ){
|
||||
/* Find the value object that holds the new rowid value. */
|
||||
sqlite3_value *pNewRowid = apVal[3+p->nColumn];
|
||||
if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){
|
||||
@ -3212,19 +3339,21 @@ int sqlite3Fts3UpdateMethod(
|
||||
assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER );
|
||||
rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel);
|
||||
isRemove = 1;
|
||||
iRemove = sqlite3_value_int64(apVal[0]);
|
||||
}
|
||||
|
||||
/* If this is an INSERT or UPDATE operation, insert the new record. */
|
||||
if( nArg>1 && rc==SQLITE_OK ){
|
||||
if( bInsertDone==0 ){
|
||||
rc = fts3InsertData(p, apVal, pRowid);
|
||||
if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT_VTAB;
|
||||
if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){
|
||||
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
|
||||
rc = fts3PendingTermsDocid(p, *pRowid);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( p->iPrevDocid==*pRowid );
|
||||
rc = fts3InsertTerms(p, apVal, aSzIns);
|
||||
}
|
||||
if( p->bHasDocsize ){
|
||||
|
@ -1268,7 +1268,8 @@ static int rtreeFilter(
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc);
|
||||
assert( (idxStr==0 && argc==0) || (int)strlen(idxStr)==argc*2 );
|
||||
assert( (idxStr==0 && argc==0)
|
||||
|| (idxStr && (int)strlen(idxStr)==argc*2) );
|
||||
for(ii=0; ii<argc; ii++){
|
||||
RtreeConstraint *p = &pCsr->aConstraint[ii];
|
||||
p->op = idxStr[ii*2];
|
||||
@ -1569,7 +1570,10 @@ static int ChooseLeaf(
|
||||
|
||||
float fMinGrowth = 0.0;
|
||||
float fMinArea = 0.0;
|
||||
#if VARIANT_RSTARTREE_CHOOSESUBTREE
|
||||
float fMinOverlap = 0.0;
|
||||
float overlap;
|
||||
#endif
|
||||
|
||||
int nCell = NCELL(pNode);
|
||||
RtreeCell cell;
|
||||
@ -1601,7 +1605,6 @@ static int ChooseLeaf(
|
||||
int bBest = 0;
|
||||
float growth;
|
||||
float area;
|
||||
float overlap = 0.0;
|
||||
nodeGetCell(pRtree, pNode, iCell, &cell);
|
||||
growth = cellGrowth(pRtree, &cell, pCell);
|
||||
area = cellArea(pRtree, &cell);
|
||||
@ -1609,6 +1612,8 @@ static int ChooseLeaf(
|
||||
#if VARIANT_RSTARTREE_CHOOSESUBTREE
|
||||
if( ii==(pRtree->iDepth-1) ){
|
||||
overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell);
|
||||
}else{
|
||||
overlap = 0.0;
|
||||
}
|
||||
if( (iCell==0)
|
||||
|| (overlap<fMinOverlap)
|
||||
@ -1616,6 +1621,7 @@ static int ChooseLeaf(
|
||||
|| (overlap==fMinOverlap && growth==fMinGrowth && area<fMinArea)
|
||||
){
|
||||
bBest = 1;
|
||||
fMinOverlap = overlap;
|
||||
}
|
||||
#else
|
||||
if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
|
||||
@ -1623,7 +1629,6 @@ static int ChooseLeaf(
|
||||
}
|
||||
#endif
|
||||
if( bBest ){
|
||||
fMinOverlap = overlap;
|
||||
fMinGrowth = growth;
|
||||
fMinArea = area;
|
||||
iBest = cell.iRowid;
|
||||
|
6
main.mk
6
main.mk
@ -365,6 +365,9 @@ sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
|
||||
$(TOP)/src/shell.c \
|
||||
libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
|
||||
|
||||
sqlite3.o: sqlite3.c
|
||||
$(TCCX) -c sqlite3.c
|
||||
|
||||
# This target creates a directory named "tsrc" and fills it with
|
||||
# copies of all of the C source code and header files needed to
|
||||
# build on the target system. Some of the C source code and header
|
||||
@ -597,7 +600,8 @@ install: sqlite3 libsqlite3.a sqlite3.h
|
||||
|
||||
clean:
|
||||
rm -f *.o sqlite3 sqlite3.exe libsqlite3.a sqlite3.h opcodes.*
|
||||
rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h
|
||||
rm -f lemon lemon.exe lempar.c parse.* sqlite*.tar.gz
|
||||
rm -f mkkeywordhash mkkeywordhash.exe keywordhash.h
|
||||
rm -f $(PUBLISH)
|
||||
rm -f *.da *.bb *.bbg gmon.out
|
||||
rm -rf tsrc target_source
|
||||
|
124
manifest
124
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\sall\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch\s-\sespecially\nthe\sSQLITE_ENABLE_STAT3\senhancements.
|
||||
D 2011-10-11T12:58:38.127
|
||||
C Merge\sthe\slatest\strunk\senhancements\sinto\sthe\ssessions\sbranch.
|
||||
D 2011-10-21T17:08:23.879
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in a162fe39e249b8ed4a65ee947c30152786cfe897
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -62,29 +62,29 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 195e4da669741c1f097434ec48c0ba5739193af9
|
||||
F ext/fts3/fts3.c 246ef2d0cef67517d156d39c9247cd6c432f0d79
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 30063fdd0bc433b5db1532e3a363cb0f2f7e8eb3
|
||||
F ext/fts3/fts3Int.h def7a900f98c5ab5fa4772e922bfa219d5097f05
|
||||
F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691
|
||||
F ext/fts3/fts3_expr.c 23791de01b3a5d313d76e02befd2601d4096bc2b
|
||||
F ext/fts3/fts3_expr.c f5df26bddf46a5916b2a5f80c4027996e92b7b15
|
||||
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||
F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa
|
||||
F ext/fts3/fts3_porter.c 8d946908f4812c005d3d33fcbe78418b1f4eb70c
|
||||
F ext/fts3/fts3_snippet.c 58b2ba2b934c1e2a2f6ac857d7f3c7e1a14b4532
|
||||
F ext/fts3/fts3_snippet.c 1f9ee6a8e0e242649645968dcec4deb253d86c2a
|
||||
F ext/fts3/fts3_term.c a5457992723455a58804cb75c8cbd8978db5c2ef
|
||||
F ext/fts3/fts3_test.c 24fa13f330db011500acb95590da9eee24951894
|
||||
F ext/fts3/fts3_tokenizer.c 9ff7ec66ae3c5c0340fa081958e64f395c71a106
|
||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||
F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68
|
||||
F ext/fts3/fts3_write.c 194829c8fd024a448fc899e5ff02a8ed06595529
|
||||
F ext/fts3/fts3_write.c c097228bff4d33c6b8a270c9717b9f8339068776
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c b431c54d1ed05f04f2987e8a4fbb931acb40c312
|
||||
F ext/rtree/rtree.c 692e9192d148f318b3dca9f744600346a175eedd
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@ -116,7 +116,7 @@ F ext/session/sqlite3session.h f374c9c4c96e08f67ac418871c29d423245c7673
|
||||
F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk 57f16530780b158e99c4983debabeb50b2331a57
|
||||
F main.mk 0f09cc961194da519af6bdd3004bb3ec9ebddc80
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@ -133,22 +133,22 @@ F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
|
||||
F src/analyze.c 682fd999a01c897a682365a459190758b83de836
|
||||
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 4fd4440c8f81339d8eb8e5d2df54b68d79e94f2f
|
||||
F src/backup.c 4368158da74d4711888e03264105c5c527d76caf
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c b53e009bccb4cfcbcde074f586f0c1c6712a0e12
|
||||
F src/btree.c 32199e2d939233ade25340eaba450f818b37c079
|
||||
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
|
||||
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
|
||||
F src/build.c 119937b0ae1ff4dcec8fdea53771acc95bafca51
|
||||
F src/build.c ae152efb9c2d6615b14adb7a5f2c51483d4d55df
|
||||
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 829f3261d3db48e3d87891bc887208734734c2e4
|
||||
F src/date.c a3c6842bad7ae632281811de112a8ba63ff08ab3
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 614d6e012aa5b624e78f3b556243497825de196b
|
||||
F src/expr.c f4dcaeb8252c4b16fcdc245660f70ed366bc6cdd
|
||||
F src/expr.c fbf116f90cabc917ae50bba24a73a0b55519a0c8
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 9f00ea98f6b360d477b5a78b5b59a1fbde82431c
|
||||
F src/func.c 59bb046d7e3df1ab512ac339ccb0a6f996a17cb7
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9
|
||||
F src/global.c e230227de13601714b29f9363028514aada5ae2f
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
@ -156,9 +156,9 @@ F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 25b1bdb27db651ccc9cef37aa691be65d6be9cda
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 99a161b27a499fc8ad40745b7b1900a26f0a5f51
|
||||
F src/main.c 13b9a1d38084dd4996ad5f759c4b0e1fc1c010c0
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
F src/loadext.c d0d2022a5a07274d408820b978b9e549189d314f
|
||||
F src/main.c 61e6886a0606b46fc4b38c2d8585ef55afcf9662
|
||||
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
|
||||
@ -167,39 +167,39 @@ F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
|
||||
F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6
|
||||
F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
|
||||
F src/mutex.h fe2ef5e1c4dae531d5a544f9241f19c56d26803d
|
||||
F src/mutex.h 2a79e0c10c26412546b501ee0f3d92b42decf63e
|
||||
F src/mutex_noop.c d5cfbca87168c661a0b118cd8e329a908e453151
|
||||
F src/mutex_os2.c 882d735098c07c8c6a5472b8dd66e19675fe117f
|
||||
F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
|
||||
F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 3b3f69c34be7f998f5ea6bd46a2fe8a2b7fa8f70
|
||||
F src/os.c 5d9b02782ed36345348d6fe21d7762ed3a9cfd2a
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c 9da63854b702e0855ce13711a80d8bdcc5b69549
|
||||
F src/os_win.c fbe47c7fdc9a846a772bbf98719c328becad5f8a
|
||||
F src/pager.c 8a6ac3e0d9694412076e2273e3c81e9c4e08758f
|
||||
F src/pager.h dbcaa791e8b6c3a6b77c168c5c27deec289fb176
|
||||
F src/os_unix.c ddda0b1c5ae536669634d7bff31b3f8f4d654866
|
||||
F src/os_win.c 49d418916428a59d773f39993db0ecde56ab4c37
|
||||
F src/pager.c ad62daa0c21e27ae332b3ceb4f579a2a97046ddc
|
||||
F src/pager.h 9f81b08efb06db4ba8be69446e10b005c351373d
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 24f5e85a78514584b46190260ba7ab0a66312197
|
||||
F src/pragma.c 68d7db4fc9de8bcfae94c1d43120531ec252b9c0
|
||||
F src/pragma.c da8ef96b3eec351e81e0061c39810e548bcc96d7
|
||||
F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4
|
||||
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
|
||||
F src/printf.c 03104cbff6959ff45df69dc9060ba6212f60a869
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
|
||||
F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c d9b7d20b0365f80761846f00ef3638d4b33eeaf2
|
||||
F src/shell.c e8fe1251aee84baa2fb232ce83d938de25aa650f
|
||||
F src/sqlite.h.in 1d5116f51910cc59187b100557feacd8341b633d
|
||||
F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6
|
||||
F src/shell.c f0ab793261ab045a0b8c47fa2707e8a894d2898f
|
||||
F src/sqlite.h.in 42693f5fc57345ee4bfc9ab4b65a1637c8fd2034
|
||||
F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
|
||||
F src/sqliteInt.h 0d9d61edf5be116d34f6f980cb0db70375e152ad
|
||||
F src/sqliteInt.h bdf2d6a2c2908864fd75a242b35ded2cf3a0f395
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 8adc2f2bc8a155f2a340242df6d82112a629ed7c
|
||||
F src/tclsqlite.c b9615cb7f32113724f0b9e89dd1b2adc927991ae
|
||||
F src/test1.c 0f41b7c67719207a5de24b009e172c4dcf189827
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
|
||||
@ -246,24 +246,24 @@ F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705
|
||||
F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
|
||||
F src/update.c 2d67e24d5a44d8b1c0839bf2ee0c391593e852bf
|
||||
F src/update.c 7509519281d566553cb2e8561541d49a2c054ed4
|
||||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c 06302ffd2b80408d4f6c7af71f7090e0cf8d8ff7
|
||||
F src/util.c df83983bd57057df4951516880066b42b7055269
|
||||
F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
|
||||
F src/vdbe.c a4d43779fd31b00cc7c6e1717e4b6cfacf499e66
|
||||
F src/vdbe.c 9cccccebf82571837b03e0b7bdc22a2651c368c5
|
||||
F src/vdbe.h 226d4bc726b3597c35be155a4342db290601d67c
|
||||
F src/vdbeInt.h 1400515b37a4863cdda4601abc0f76eca846c9f5
|
||||
F src/vdbeapi.c c969d467817ca90f99f3d3b46d115fbec08aeb4c
|
||||
F src/vdbeaux.c 2339c8c4d88aba3709f810e8aab7731eecae7aed
|
||||
F src/vdbeaux.c c2e9565d942bf9258155f62ec4c80197d5e449f5
|
||||
F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381
|
||||
F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
|
||||
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
|
||||
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
|
||||
F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
|
||||
F src/wal.c 3154756177d6219e233d84291d5b05f4e06ff5e9
|
||||
F src/wal.c 9658df8d404b82e6b2d40fd05944463214e2d935
|
||||
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 12939ac49f5122eb11b5ca4c35b2fdd8eaae9833
|
||||
F src/where.c 922145a39cf91a5dbb83bbc54f0e316f52023fa2
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
@ -420,6 +420,7 @@ F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
|
||||
F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49
|
||||
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
|
||||
F test/fts1b.test 5d8a01aefbecc8b7442b36c94c05eb7a845462d5
|
||||
F test/fts1c.test 85a525ce7428907469b4cce13d5563ce542ce64c
|
||||
@ -470,7 +471,7 @@ F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
|
||||
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
|
||||
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
|
||||
F test/fts3ao.test 60a15590d3c8578e943e4a149524b16b9bc1be92
|
||||
F test/fts3ao.test e7b80272efcced57d1d087a9da5c690dd7c21fd9
|
||||
F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3
|
||||
F test/fts3auto.test c1a30b37002b7c764a96937fbc71065b73d69494
|
||||
F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0
|
||||
@ -481,24 +482,26 @@ F test/fts3conf.test 8e65ea56f88ced6cdd2252bdddb1a8327ae5af7e
|
||||
F test/fts3corrupt.test 7b0f91780ca36118d73324ec803187208ad33b32
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
|
||||
F test/fts3defer.test 7c8a38d5f617d7b52ae1c43ed73c536e7e895a35
|
||||
F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a
|
||||
F test/fts3defer.test 2ea3fa028f8d9523f9c33dd8acc4555d567ea4ac
|
||||
F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81
|
||||
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
|
||||
F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d
|
||||
F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
|
||||
F test/fts3matchinfo.test 08a82d18cc08abb28aec41d412b4c2ef25ba6a5f
|
||||
F test/fts3fault2.test b62a2bc843c20414405f80e5eeb78e39bc68fe53
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3malloc.test b86ea33db9e8c58c0c2f8027a9fcadaf6a1568be
|
||||
F test/fts3matchinfo.test 6507fe1c342e542300d65ea637d4110eccf894e6
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
F test/fts3prefix.test 36246609111ec1683f7ea5ed27666ce2cefb5676
|
||||
F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1
|
||||
F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2
|
||||
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
|
||||
F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2
|
||||
F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2
|
||||
F test/fts3sort.test 9a5176c9317bb545ec5f144d62e6fedb4da6c66e
|
||||
F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
|
||||
F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68
|
||||
F test/fts4content.test c5f531ecfc3d446b90032cae212549dbbb18dd78
|
||||
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
|
||||
@ -615,7 +618,7 @@ F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
|
||||
F test/multiplex.test 9df8bf738b3b97c718fceb3fadb30900ba494418
|
||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2
|
||||
F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 9503e51b9a272a5405c205ad61b7623d5a9ca489
|
||||
F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a
|
||||
@ -633,10 +636,10 @@ F test/pageropt.test 9191867ed19a2b3db6c42d1b36b6fbc657cd1ab0
|
||||
F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/permutations.test 97d576e6384f1779e4428516a48458ce8cf7dfd1
|
||||
F test/pragma.test c8108e01da04f16e67e5754e610bc62c1b993f6c
|
||||
F test/permutations.test 6f650848f527507771eb8a447d5969a8d14e2040
|
||||
F test/pragma.test 1ea0c85be853135bb7468e6eed48ee12b04794d4
|
||||
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
@ -762,6 +765,7 @@ F test/tkt-f3e5abed55.test 669bb076f2ac573c7398ce00f40cd0ca502043a9
|
||||
F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
|
||||
F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7
|
||||
F test/tkt-f973c7ac31.test 1da0ed15ec2c7749fb5ce2828cd69d07153ad9f4
|
||||
F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035
|
||||
F test/tkt-fc62af4523.test 72825d3febdedcd5593a27989fc05accdbfc2bb4
|
||||
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
|
||||
F test/tkt1443.test bacc311da5c96a227bf8c167e77a30c99f8e8368
|
||||
@ -830,7 +834,7 @@ F test/tkt3761.test b95ea9c98f21cf91325f18a984887e62caceab33
|
||||
F test/tkt3762.test 2a9f3b03df44ec49ec0cfa8d5da6574c2a7853df
|
||||
F test/tkt3773.test 430b06567ce40285dfd2c4834a2a61816403efeb
|
||||
F test/tkt3791.test a6624b9a80b216a26cf473607f42f3e51898c267
|
||||
F test/tkt3793.test 754b73f0e6a9349c70dc57e522cf3247272ecd5d
|
||||
F test/tkt3793.test d90ffd75c52413908d15e1c44fc2ea9c80fcc449
|
||||
F test/tkt3810.test 90fa0635dfa7da9680c8cd3513350a49b3a8ae12
|
||||
F test/tkt3824.test 150aa00bb6220672e5f0eb14dc8eaa36750425f0
|
||||
F test/tkt3832.test 2300d10d57562b89875b72148338ac3e14f8847d
|
||||
@ -918,13 +922,13 @@ F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
|
||||
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
|
||||
F test/walpersist.test fd40d33765b2693f721c90c66d97f99757559006
|
||||
F test/walro.test 412d0809300b94ba142440e94d6a30eabf2220b7
|
||||
F test/walro.test e6bb27762c9f22601cbb8bff6e0acfd124e74b63
|
||||
F test/walshared.test 6dda2293880c300baf5d791c307f653094585761
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test a2ed5270eb695284d4ad27d252517bdc3317ee2a
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where3.test 8e1175c7ef710c70502858fc4fb08d784b3620b9
|
||||
F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@ -954,7 +958,7 @@ F tool/mksqlite3c.tcl 9fbac513cd9d5ac95ad55630f49bb16c5347ab75
|
||||
F tool/mksqlite3h.tcl 78013ad79a5e492e5f764f3c7a8ef834255061f8
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
|
||||
F tool/omittest.tcl 8086c014cbae90f1f2b564d59d05a5e4ac1783c9
|
||||
F tool/omittest.tcl 72a49b8a9a8b0bf213a438180307a0df836d4380
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
|
||||
@ -975,11 +979,13 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||
F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
|
||||
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
||||
F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f
|
||||
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P 98619a23fd11a5eb319687adfdacc91ff2db896c 9325c1a8c413dfbf0381190d8347f0a446ae5f5b
|
||||
R d253d1168c1ea36796b51c0ccbb3736e
|
||||
P 403431cac6b039b0693915c5422f08dc60dae230 76de9914bed11abda3898928633ad09d5a284f84
|
||||
R ab14a959a3d450010ae943a82abd757a
|
||||
U drh
|
||||
Z eba0cc6baac730dcbeed3fe014c48887
|
||||
Z 7ff2c714c610eb8c2779c328e2695599
|
||||
|
@ -1 +1 @@
|
||||
403431cac6b039b0693915c5422f08dc60dae230
|
||||
8baef58170ff851d0c4387a6888f59b487b4f33c
|
@ -543,14 +543,14 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
*/
|
||||
int sqlite3_backup_finish(sqlite3_backup *p){
|
||||
sqlite3_backup **pp; /* Ptr to head of pagers backup list */
|
||||
sqlite3_mutex *mutex; /* Mutex to protect source database */
|
||||
MUTEX_LOGIC( sqlite3_mutex *mutex; ) /* Mutex to protect source database */
|
||||
int rc; /* Value to return */
|
||||
|
||||
/* Enter the mutexes */
|
||||
if( p==0 ) return SQLITE_OK;
|
||||
sqlite3_mutex_enter(p->pSrcDb->mutex);
|
||||
sqlite3BtreeEnter(p->pSrc);
|
||||
mutex = p->pSrcDb->mutex;
|
||||
MUTEX_LOGIC( mutex = p->pSrcDb->mutex; )
|
||||
if( p->pDestDb ){
|
||||
sqlite3_mutex_enter(p->pDestDb->mutex);
|
||||
}
|
||||
@ -704,6 +704,8 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
||||
rc = sqlite3_backup_finish(&b);
|
||||
if( rc==SQLITE_OK ){
|
||||
pTo->pBt->pageSizeFixed = 0;
|
||||
}else{
|
||||
sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
|
||||
}
|
||||
|
||||
assert( sqlite3BtreeIsInTrans(pTo)==0 );
|
||||
|
24
src/btree.c
24
src/btree.c
@ -1766,17 +1766,19 @@ int sqlite3BtreeOpen(
|
||||
if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
|
||||
int nFullPathname = pVfs->mxPathname+1;
|
||||
char *zFullPathname = sqlite3Malloc(nFullPathname);
|
||||
sqlite3_mutex *mutexShared;
|
||||
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
|
||||
p->sharable = 1;
|
||||
if( !zFullPathname ){
|
||||
sqlite3_free(p);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname);
|
||||
#if SQLITE_THREADSAFE
|
||||
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
|
||||
sqlite3_mutex_enter(mutexOpen);
|
||||
mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutexShared);
|
||||
#endif
|
||||
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
|
||||
assert( pBt->nRef>0 );
|
||||
if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager))
|
||||
@ -1882,9 +1884,9 @@ int sqlite3BtreeOpen(
|
||||
/* Add the new BtShared object to the linked list sharable BtShareds.
|
||||
*/
|
||||
if( p->sharable ){
|
||||
sqlite3_mutex *mutexShared;
|
||||
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
|
||||
pBt->nRef = 1;
|
||||
mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
|
||||
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
|
||||
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
|
||||
if( pBt->mutex==0 ){
|
||||
@ -1966,12 +1968,12 @@ btree_open_out:
|
||||
*/
|
||||
static int removeFromSharingList(BtShared *pBt){
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3_mutex *pMaster;
|
||||
MUTEX_LOGIC( sqlite3_mutex *pMaster; )
|
||||
BtShared *pList;
|
||||
int removed = 0;
|
||||
|
||||
assert( sqlite3_mutex_notheld(pBt->mutex) );
|
||||
pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
||||
sqlite3_mutex_enter(pMaster);
|
||||
pBt->nRef--;
|
||||
if( pBt->nRef<=0 ){
|
||||
@ -4585,7 +4587,6 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( c==0 ){
|
||||
if( pPage->intKey && !pPage->leaf ){
|
||||
lwr = idx;
|
||||
upr = lwr - 1;
|
||||
break;
|
||||
}else{
|
||||
*pRes = 0;
|
||||
@ -4603,7 +4604,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2);
|
||||
}
|
||||
assert( lwr==upr+1 );
|
||||
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
||||
assert( pPage->isInit );
|
||||
if( pPage->leaf ){
|
||||
chldPg = 0;
|
||||
@ -4868,6 +4869,8 @@ static int allocateBtreePage(
|
||||
pTrunk = 0;
|
||||
goto end_allocate_page;
|
||||
}
|
||||
assert( pTrunk!=0 );
|
||||
assert( pTrunk->aData!=0 );
|
||||
|
||||
k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */
|
||||
if( k==0 && !searchList ){
|
||||
@ -5995,13 +5998,15 @@ static int balance_nonroot(
|
||||
** four bytes of the divider cell. So the pointer is safe to use
|
||||
** later on.
|
||||
**
|
||||
** Unless SQLite is compiled in secure-delete mode. In this case,
|
||||
** But not if we are in secure-delete mode. In secure-delete mode,
|
||||
** the dropCell() routine will overwrite the entire cell with zeroes.
|
||||
** In this case, temporarily copy the cell into the aOvflSpace[]
|
||||
** buffer. It will be copied out again as soon as the aSpace[] buffer
|
||||
** is allocated. */
|
||||
if( pBt->secureDelete ){
|
||||
int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
|
||||
int iOff;
|
||||
|
||||
iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
|
||||
if( (iOff+szNew[i])>(int)pBt->usableSize ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
||||
@ -6421,6 +6426,7 @@ static int balance_nonroot(
|
||||
/* Cell i is the cell immediately following the last cell on old
|
||||
** sibling page j. If the siblings are not leaf pages of an
|
||||
** intkey b-tree, then cell i was a divider cell. */
|
||||
assert( j+1 < ArraySize(apCopy) );
|
||||
pOld = apCopy[++j];
|
||||
iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
|
||||
if( pOld->nOverflow ){
|
||||
|
24
src/build.c
24
src/build.c
@ -2342,13 +2342,15 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
Table *pTab = pIndex->pTable; /* The table that is indexed */
|
||||
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
|
||||
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
|
||||
int iSorter = iTab; /* Cursor opened by OpenSorter (if in use) */
|
||||
int iSorter; /* Cursor opened by OpenSorter (if in use) */
|
||||
int addr1; /* Address of top of loop */
|
||||
int addr2; /* Address to jump to for next iteration */
|
||||
int tnum; /* Root page of index */
|
||||
Vdbe *v; /* Generate code into this virtual machine */
|
||||
KeyInfo *pKey; /* KeyInfo for index */
|
||||
#ifdef SQLITE_OMIT_MERGE_SORT
|
||||
int regIdxKey; /* Registers containing the index key */
|
||||
#endif
|
||||
int regRecord; /* Register holding assemblied index record */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
@ -2382,17 +2384,18 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
/* Open the sorter cursor if we are to use one. */
|
||||
iSorter = pParse->nTab++;
|
||||
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)pKey, P4_KEYINFO);
|
||||
#else
|
||||
iSorter = iTab;
|
||||
#endif
|
||||
|
||||
/* Open the table. Loop through all rows of the table, inserting index
|
||||
** records into the sorter. */
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
|
||||
addr2 = addr1 + 1;
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
|
||||
|
||||
#ifndef SQLITE_OMIT_MERGE_SORT
|
||||
sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
@ -2412,6 +2415,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
#else
|
||||
regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
|
||||
addr2 = addr1 + 1;
|
||||
if( pIndex->onError!=OE_None ){
|
||||
const int regRowid = regIdxKey + pIndex->nColumn;
|
||||
const int j2 = sqlite3VdbeCurrentAddr(v) + 2;
|
||||
@ -2509,6 +2514,7 @@ Index *sqlite3CreateIndex(
|
||||
assert( pName1 && pName2 );
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
||||
if( iDb<0 ) goto exit_create_index;
|
||||
assert( pName && pName->z );
|
||||
|
||||
#ifndef SQLITE_OMIT_TEMPDB
|
||||
/* If the index name was unqualified, check if the the table
|
||||
@ -2536,6 +2542,7 @@ Index *sqlite3CreateIndex(
|
||||
assert( db->aDb[iDb].pSchema==pTab->pSchema );
|
||||
}else{
|
||||
assert( pName==0 );
|
||||
assert( pStart==0 );
|
||||
pTab = pParse->pNewTable;
|
||||
if( !pTab ) goto exit_create_index;
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
@ -2578,6 +2585,7 @@ Index *sqlite3CreateIndex(
|
||||
if( pName ){
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if( zName==0 ) goto exit_create_index;
|
||||
assert( pName->z!=0 );
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
@ -3433,13 +3441,10 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
|
||||
** Commit a transaction
|
||||
*/
|
||||
void sqlite3CommitTransaction(Parse *pParse){
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
|
||||
assert( pParse!=0 );
|
||||
db = pParse->db;
|
||||
assert( db!=0 );
|
||||
/* if( db->aDb[0].pBt==0 ) return; */
|
||||
assert( pParse->db!=0 );
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
|
||||
return;
|
||||
}
|
||||
@ -3453,13 +3458,10 @@ void sqlite3CommitTransaction(Parse *pParse){
|
||||
** Rollback a transaction
|
||||
*/
|
||||
void sqlite3RollbackTransaction(Parse *pParse){
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
|
||||
assert( pParse!=0 );
|
||||
db = pParse->db;
|
||||
assert( db!=0 );
|
||||
/* if( db->aDb[0].pBt==0 ) return; */
|
||||
assert( pParse->db!=0 );
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
|
||||
return;
|
||||
}
|
||||
|
49
src/date.c
49
src/date.c
@ -289,12 +289,18 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the time to the current time reported by the VFS
|
||||
** Set the time to the current time reported by the VFS.
|
||||
**
|
||||
** Return the number of errors.
|
||||
*/
|
||||
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
|
||||
static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD);
|
||||
p->validJD = 1;
|
||||
if( sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD)==SQLITE_OK ){
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -324,8 +330,7 @@ static int parseDateOrTime(
|
||||
}else if( parseHhMmSs(zDate, p)==0 ){
|
||||
return 0;
|
||||
}else if( sqlite3StrICmp(zDate,"now")==0){
|
||||
setDateTimeToCurrent(context, p);
|
||||
return 0;
|
||||
return setDateTimeToCurrent(context, p);
|
||||
}else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
|
||||
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
|
||||
p->validJD = 1;
|
||||
@ -752,8 +757,9 @@ static int isDate(
|
||||
int eType;
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( argc==0 ){
|
||||
setDateTimeToCurrent(context, p);
|
||||
}else if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|
||||
return setDateTimeToCurrent(context, p);
|
||||
}
|
||||
if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|
||||
|| eType==SQLITE_INTEGER ){
|
||||
p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
|
||||
p->validJD = 1;
|
||||
@ -1065,31 +1071,28 @@ static void currentTimeFunc(
|
||||
char *zFormat = (char *)sqlite3_user_data(context);
|
||||
sqlite3 *db;
|
||||
sqlite3_int64 iT;
|
||||
struct tm *pTm;
|
||||
struct tm sNow;
|
||||
char zBuf[20];
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
db = sqlite3_context_db_handle(context);
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
|
||||
if( sqlite3OsCurrentTimeInt64(db->pVfs, &iT) ) return;
|
||||
t = iT/1000 - 10000*(sqlite3_int64)21086676;
|
||||
#ifdef HAVE_GMTIME_R
|
||||
{
|
||||
struct tm sNow;
|
||||
gmtime_r(&t, &sNow);
|
||||
strftime(zBuf, 20, zFormat, &sNow);
|
||||
}
|
||||
pTm = gmtime_r(&t, &sNow);
|
||||
#else
|
||||
{
|
||||
struct tm *pTm;
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
pTm = gmtime(&t);
|
||||
strftime(zBuf, 20, zFormat, pTm);
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
}
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
pTm = gmtime(&t);
|
||||
if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
#endif
|
||||
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
if( pTm ){
|
||||
strftime(zBuf, 20, zFormat, &sNow);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
19
src/expr.c
19
src/expr.c
@ -403,7 +403,8 @@ Expr *sqlite3ExprAlloc(
|
||||
}else{
|
||||
int c;
|
||||
pNew->u.zToken = (char*)&pNew[1];
|
||||
memcpy(pNew->u.zToken, pToken->z, pToken->n);
|
||||
assert( pToken->z!=0 || pToken->n==0 );
|
||||
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
|
||||
pNew->u.zToken[pToken->n] = 0;
|
||||
if( dequote && nExtra>=3
|
||||
&& ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
|
||||
@ -1442,11 +1443,19 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Expr *pExpr = p->pEList->a[0].pExpr; /* Expression <column> */
|
||||
int iCol = pExpr->iColumn; /* Index of column <column> */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
Table *pTab = p->pSrc->a[0].pTab; /* Table <table>. */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
int iCol; /* Index of column <column> */
|
||||
int iDb; /* Database idx for pTab */
|
||||
|
||||
assert( p ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
pTab = p->pSrc->a[0].pTab;
|
||||
pExpr = p->pEList->a[0].pExpr;
|
||||
iCol = pExpr->iColumn;
|
||||
|
||||
/* Code an OP_VerifyCookie and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
@ -3453,7 +3462,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
}
|
||||
}else if( pA->op!=TK_COLUMN && pA->u.zToken ){
|
||||
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
|
||||
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -1124,6 +1124,7 @@ static Trigger *fkActionTrigger(
|
||||
fkTriggerDelete(db, pTrigger);
|
||||
return 0;
|
||||
}
|
||||
assert( pStep!=0 );
|
||||
|
||||
switch( action ){
|
||||
case OE_Restrict:
|
||||
|
16
src/func.c
16
src/func.c
@ -332,16 +332,15 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
if( z2 ){
|
||||
z1 = contextMalloc(context, ((i64)n)+1);
|
||||
if( z1 ){
|
||||
memcpy(z1, z2, n+1);
|
||||
for(i=0; z1[i]; i++){
|
||||
z1[i] = (char)sqlite3Toupper(z1[i]);
|
||||
for(i=0; i<n; i++){
|
||||
z1[i] = (char)sqlite3Toupper(z2[i]);
|
||||
}
|
||||
sqlite3_result_text(context, z1, -1, sqlite3_free);
|
||||
sqlite3_result_text(context, z1, n, sqlite3_free);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
u8 *z1;
|
||||
char *z1;
|
||||
const char *z2;
|
||||
int i, n;
|
||||
UNUSED_PARAMETER(argc);
|
||||
@ -352,11 +351,10 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
if( z2 ){
|
||||
z1 = contextMalloc(context, ((i64)n)+1);
|
||||
if( z1 ){
|
||||
memcpy(z1, z2, n+1);
|
||||
for(i=0; z1[i]; i++){
|
||||
z1[i] = sqlite3Tolower(z1[i]);
|
||||
for(i=0; i<n; i++){
|
||||
z1[i] = sqlite3Tolower(z2[i]);
|
||||
}
|
||||
sqlite3_result_text(context, (char *)z1, -1, sqlite3_free);
|
||||
sqlite3_result_text(context, z1, n, sqlite3_free);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,7 +716,9 @@ void Parse(
|
||||
){
|
||||
YYMINORTYPE yyminorunion;
|
||||
int yyact; /* The parser action. */
|
||||
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
|
||||
int yyendofinput; /* True if we are at the end of input */
|
||||
#endif
|
||||
#ifdef YYERRORSYMBOL
|
||||
int yyerrorhit = 0; /* True if yymajor has invoked an error */
|
||||
#endif
|
||||
@ -739,7 +741,9 @@ void Parse(
|
||||
yypParser->yystack[0].major = 0;
|
||||
}
|
||||
yyminorunion.yy0 = yyminor;
|
||||
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
|
||||
yyendofinput = (yymajor==0);
|
||||
#endif
|
||||
ParseARG_STORE;
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -751,7 +755,6 @@ void Parse(
|
||||
do{
|
||||
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
|
||||
if( yyact<YYNSTATE ){
|
||||
assert( !yyendofinput ); /* Impossible to shift the $ token */
|
||||
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
|
||||
yypParser->yyerrcnt--;
|
||||
yymajor = YYNOCODE;
|
||||
|
@ -403,7 +403,7 @@ static int sqlite3LoadExtension(
|
||||
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
char *zErrmsg = 0;
|
||||
void **aHandle;
|
||||
const int nMsg = 300;
|
||||
int nMsg = 300 + sqlite3Strlen30(zFile);
|
||||
|
||||
if( pzErrMsg ) *pzErrMsg = 0;
|
||||
|
||||
@ -440,6 +440,7 @@ static int sqlite3LoadExtension(
|
||||
sqlite3OsDlSym(pVfs, handle, zProc);
|
||||
if( xInit==0 ){
|
||||
if( pzErrMsg ){
|
||||
nMsg += sqlite3Strlen30(zProc);
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
if( zErrmsg ){
|
||||
sqlite3_snprintf(nMsg, zErrmsg,
|
||||
|
13
src/main.c
13
src/main.c
@ -106,7 +106,7 @@ char *sqlite3_temp_directory = 0;
|
||||
** without blocking.
|
||||
*/
|
||||
int sqlite3_initialize(void){
|
||||
sqlite3_mutex *pMaster; /* The main static mutex */
|
||||
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
|
||||
int rc; /* Result code */
|
||||
|
||||
#ifdef SQLITE_OMIT_WSD
|
||||
@ -140,7 +140,7 @@ int sqlite3_initialize(void){
|
||||
** malloc subsystem - this implies that the allocation of a static
|
||||
** mutex must not require support from the malloc subsystem.
|
||||
*/
|
||||
pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
||||
sqlite3_mutex_enter(pMaster);
|
||||
sqlite3GlobalConfig.isMutexInit = 1;
|
||||
if( !sqlite3GlobalConfig.isMallocInit ){
|
||||
@ -1214,13 +1214,13 @@ int sqlite3_overload_function(
|
||||
int nArg
|
||||
){
|
||||
int nName = sqlite3Strlen30(zName);
|
||||
int rc;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
|
||||
sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
|
||||
0, sqlite3InvalidFunction, 0, 0, 0);
|
||||
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
|
||||
0, sqlite3InvalidFunction, 0, 0, 0);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, SQLITE_OK);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
@ -2303,6 +2303,7 @@ opendb_out:
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}
|
||||
rc = sqlite3_errcode(db);
|
||||
assert( db!=0 || rc==SQLITE_NOMEM );
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3_close(db);
|
||||
db = 0;
|
||||
|
@ -60,12 +60,15 @@
|
||||
*/
|
||||
#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
|
||||
#define sqlite3_mutex_free(X)
|
||||
#define sqlite3_mutex_enter(X)
|
||||
#define sqlite3_mutex_enter(X)
|
||||
#define sqlite3_mutex_try(X) SQLITE_OK
|
||||
#define sqlite3_mutex_leave(X)
|
||||
#define sqlite3_mutex_leave(X)
|
||||
#define sqlite3_mutex_held(X) ((void)(X),1)
|
||||
#define sqlite3_mutex_notheld(X) ((void)(X),1)
|
||||
#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
|
||||
#define sqlite3MutexInit() SQLITE_OK
|
||||
#define sqlite3MutexEnd()
|
||||
#define MUTEX_LOGIC(X)
|
||||
#else
|
||||
#define MUTEX_LOGIC(X) X
|
||||
#endif /* defined(SQLITE_MUTEX_OMIT) */
|
||||
|
4
src/os.c
4
src/os.c
@ -297,12 +297,12 @@ static void vfsUnlink(sqlite3_vfs *pVfs){
|
||||
** true.
|
||||
*/
|
||||
int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
|
||||
sqlite3_mutex *mutex = 0;
|
||||
MUTEX_LOGIC(sqlite3_mutex *mutex;)
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
int rc = sqlite3_initialize();
|
||||
if( rc ) return rc;
|
||||
#endif
|
||||
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
||||
sqlite3_mutex_enter(mutex);
|
||||
vfsUnlink(pVfs);
|
||||
if( makeDflt || vfsList==0 ){
|
||||
|
@ -528,7 +528,7 @@ static int unixMutexHeld(void) {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Helper function for printing out trace information from debugging
|
||||
** binaries. This returns the string represetation of the supplied
|
||||
@ -1363,14 +1363,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
*/
|
||||
int rc = SQLITE_OK;
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
unixInodeInfo *pInode = pFile->pInode;
|
||||
unixInodeInfo *pInode;
|
||||
struct flock lock;
|
||||
int tErrno = 0;
|
||||
|
||||
assert( pFile );
|
||||
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
|
||||
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
|
||||
azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
|
||||
azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid()));
|
||||
|
||||
/* If there is already a lock of this type or more restrictive on the
|
||||
** unixFile, do nothing. Don't use the end_lock: exit path, as
|
||||
@ -1574,7 +1574,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
unixInodeInfo *pInode;
|
||||
struct flock lock;
|
||||
int rc = SQLITE_OK;
|
||||
int h;
|
||||
|
||||
assert( pFile );
|
||||
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock,
|
||||
@ -1586,14 +1585,10 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
unixEnterMutex();
|
||||
h = pFile->h;
|
||||
pInode = pFile->pInode;
|
||||
assert( pInode->nShared!=0 );
|
||||
if( pFile->eFileLock>SHARED_LOCK ){
|
||||
assert( pInode->eFileLock==pFile->eFileLock );
|
||||
SimulateIOErrorBenign(1);
|
||||
SimulateIOError( h=(-1) )
|
||||
SimulateIOErrorBenign(0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* When reducing a lock such that other processes can start
|
||||
@ -1604,11 +1599,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
** the file has changed and hence might not know to flush their
|
||||
** cache. The use of a stale cache can lead to database corruption.
|
||||
*/
|
||||
#if 0
|
||||
assert( pFile->inNormalWrite==0
|
||||
|| pFile->dbUpdate==0
|
||||
|| pFile->transCntrChng==1 );
|
||||
#endif
|
||||
pFile->inNormalWrite = 0;
|
||||
#endif
|
||||
|
||||
@ -1710,9 +1700,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
lock.l_type = F_UNLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = lock.l_len = 0L;
|
||||
SimulateIOErrorBenign(1);
|
||||
SimulateIOError( h=(-1) )
|
||||
SimulateIOErrorBenign(0);
|
||||
if( unixFileLock(pFile, &lock)==0 ){
|
||||
pInode->eFileLock = NO_LOCK;
|
||||
}else{
|
||||
@ -3854,16 +3841,15 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
}
|
||||
|
||||
if( pInode->bProcessLock==0 ){
|
||||
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
|
||||
(sStat.st_mode & 0777));
|
||||
const char *zRO;
|
||||
int openFlags = O_RDWR | O_CREAT;
|
||||
zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
|
||||
if( zRO && sqlite3GetBoolean(zRO) ){
|
||||
openFlags = O_RDONLY;
|
||||
pShmNode->isReadonly = 1;
|
||||
}
|
||||
pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
|
||||
if( pShmNode->h<0 ){
|
||||
const char *zRO;
|
||||
zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
|
||||
if( zRO && sqlite3GetBoolean(zRO) ){
|
||||
pShmNode->h = robust_open(zShmFilename, O_RDONLY,
|
||||
(sStat.st_mode & 0777));
|
||||
pShmNode->isReadonly = 1;
|
||||
}
|
||||
if( pShmNode->h<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
|
||||
goto shm_open_err;
|
||||
@ -4549,6 +4535,9 @@ static int fillInUnixFile(
|
||||
assert( zFilename==0 || zFilename[0]=='/' );
|
||||
#endif
|
||||
|
||||
/* No locking occurs in temporary files */
|
||||
assert( zFilename!=0 || noLock );
|
||||
|
||||
OSTRACE(("OPEN %-3d %s\n", h, zFilename));
|
||||
pNew->h = h;
|
||||
pNew->zPath = zFilename;
|
||||
@ -4650,6 +4639,7 @@ static int fillInUnixFile(
|
||||
*/
|
||||
char *zLockFile;
|
||||
int nFilename;
|
||||
assert( zFilename!=0 );
|
||||
nFilename = (int)strlen(zFilename) + 6;
|
||||
zLockFile = (char *)sqlite3_malloc(nFilename);
|
||||
if( zLockFile==0 ){
|
||||
@ -4884,13 +4874,13 @@ static int findCreateFileMode(
|
||||
** "<path to db>-journalNN"
|
||||
** "<path to db>-walNN"
|
||||
**
|
||||
** where NN is a 4 digit decimal number. The NN naming schemes are
|
||||
** where NN is a decimal number. The NN naming schemes are
|
||||
** used by the test_multiplex.c module.
|
||||
*/
|
||||
nDb = sqlite3Strlen30(zPath) - 1;
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
while( nDb>0 && zPath[nDb]!='-' && zPath[nDb]!='/' ) nDb--;
|
||||
if( nDb==0 || zPath[nDb]=='/' ) return SQLITE_OK;
|
||||
while( nDb>0 && !sqlite3Isalnum(zPath[nDb]) ) nDb--;
|
||||
if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
|
||||
#else
|
||||
while( zPath[nDb]!='-' ){
|
||||
assert( nDb>0 );
|
||||
@ -5429,10 +5419,12 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
|
||||
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
|
||||
** proleptic Gregorian calendar.
|
||||
**
|
||||
** On success, return 0. Return 1 if the time and date cannot be found.
|
||||
** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
|
||||
** cannot be found.
|
||||
*/
|
||||
static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
|
||||
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
|
||||
int rc = SQLITE_OK;
|
||||
#if defined(NO_GETTOD)
|
||||
time_t t;
|
||||
time(&t);
|
||||
@ -5443,8 +5435,11 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
|
||||
*piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
gettimeofday(&sNow, 0);
|
||||
*piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
|
||||
if( gettimeofday(&sNow, 0)==0 ){
|
||||
*piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
@ -5453,7 +5448,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
|
||||
}
|
||||
#endif
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5462,11 +5457,12 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
|
||||
** return 0. Return 1 if the time and date cannot be found.
|
||||
*/
|
||||
static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
|
||||
sqlite3_int64 i;
|
||||
sqlite3_int64 i = 0;
|
||||
int rc;
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
unixCurrentTimeInt64(0, &i);
|
||||
rc = unixCurrentTimeInt64(0, &i);
|
||||
*prNow = i/86400000.0;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
13
src/os_win.c
13
src/os_win.c
@ -2981,7 +2981,7 @@ static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
getLastErrorMsg(nBuf, zBufOut);
|
||||
}
|
||||
void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
|
||||
static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
#if SQLITE_OS_WINCE
|
||||
/* The GetProcAddressA() routine is only available on wince. */
|
||||
@ -2992,7 +2992,7 @@ void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
|
||||
return (void(*)(void))GetProcAddress((HANDLE)pHandle, zSymbol);
|
||||
#endif
|
||||
}
|
||||
void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
FreeLibrary((HANDLE)pHandle);
|
||||
}
|
||||
@ -3066,7 +3066,8 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
|
||||
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
|
||||
** proleptic Gregorian calendar.
|
||||
**
|
||||
** On success, return 0. Return 1 if the time and date cannot be found.
|
||||
** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
|
||||
** cannot be found.
|
||||
*/
|
||||
static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
|
||||
/* FILETIME structure is a 64-bit value representing the number of
|
||||
@ -3086,7 +3087,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
|
||||
GetSystemTime(&time);
|
||||
/* if SystemTimeToFileTime() fails, it returns zero. */
|
||||
if (!SystemTimeToFileTime(&time,&ft)){
|
||||
return 1;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
#else
|
||||
GetSystemTimeAsFileTime( &ft );
|
||||
@ -3102,7 +3103,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
|
||||
}
|
||||
#endif
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
return 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3110,7 +3111,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
|
||||
** current time and date as a Julian Day number into *prNow and
|
||||
** return 0. Return 1 if the time and date cannot be found.
|
||||
*/
|
||||
int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
|
||||
static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
|
||||
int rc;
|
||||
sqlite3_int64 i;
|
||||
rc = winCurrentTimeInt64(pVfs, &i);
|
||||
|
@ -2703,7 +2703,6 @@ static int pager_playback(Pager *pPager, int isHot){
|
||||
rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
pPager->journalOff = szJ;
|
||||
break;
|
||||
}else if( rc==SQLITE_IOERR_SHORT_READ ){
|
||||
@ -2965,6 +2964,7 @@ static int pagerWalFrames(
|
||||
#endif
|
||||
|
||||
assert( pPager->pWal );
|
||||
assert( pList );
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Verify that the page list is in accending order */
|
||||
for(p=pList; p && p->pDirty; p=p->pDirty){
|
||||
@ -6836,6 +6836,13 @@ int sqlite3PagerCloseWal(Pager *pPager){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unless this is an in-memory or temporary database, clear the pager cache.
|
||||
*/
|
||||
void sqlite3PagerClearCache(Pager *pPager){
|
||||
if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/*
|
||||
** This function is called by the wal module when writing page content
|
||||
|
@ -156,6 +156,7 @@ int sqlite3PagerNosync(Pager*);
|
||||
void *sqlite3PagerTempSpace(Pager*);
|
||||
int sqlite3PagerIsMemdb(Pager*);
|
||||
void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
||||
void sqlite3PagerClearCache(Pager *);
|
||||
|
||||
/* Functions used to truncate the database file. */
|
||||
void sqlite3PagerTruncateImage(Pager*,Pgno);
|
||||
|
@ -467,7 +467,7 @@ void sqlite3Pragma(
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
iReg = ++pParse->nMem;
|
||||
if( zLeft[0]=='p' ){
|
||||
if( sqlite3Tolower(zLeft[0])=='p' ){
|
||||
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
|
||||
@ -1080,7 +1080,7 @@ void sqlite3Pragma(
|
||||
{ OP_ResultRow, 3, 1, 0},
|
||||
};
|
||||
|
||||
int isQuick = (zLeft[0]=='q');
|
||||
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
|
||||
|
||||
/* Initialize the VDBE program */
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
|
151
src/printf.c
151
src/printf.c
@ -7,48 +7,10 @@
|
||||
**
|
||||
**************************************************************************
|
||||
**
|
||||
** The following modules is an enhanced replacement for the "printf" subroutines
|
||||
** found in the standard C library. The following enhancements are
|
||||
** supported:
|
||||
**
|
||||
** + Additional functions. The standard set of "printf" functions
|
||||
** includes printf, fprintf, sprintf, vprintf, vfprintf, and
|
||||
** vsprintf. This module adds the following:
|
||||
**
|
||||
** * snprintf -- Works like sprintf, but has an extra argument
|
||||
** which is the size of the buffer written to.
|
||||
**
|
||||
** * mprintf -- Similar to sprintf. Writes output to memory
|
||||
** obtained from malloc.
|
||||
**
|
||||
** * xprintf -- Calls a function to dispose of output.
|
||||
**
|
||||
** * nprintf -- No output, but returns the number of characters
|
||||
** that would have been output by printf.
|
||||
**
|
||||
** * A v- version (ex: vsnprintf) of every function is also
|
||||
** supplied.
|
||||
**
|
||||
** + A few extensions to the formatting notation are supported:
|
||||
**
|
||||
** * The "=" flag (similar to "-") causes the output to be
|
||||
** be centered in the appropriately sized field.
|
||||
**
|
||||
** * The %b field outputs an integer in binary notation.
|
||||
**
|
||||
** * The %c field now accepts a precision. The character output
|
||||
** is repeated by the number of times the precision specifies.
|
||||
**
|
||||
** * The %' field works like %c, but takes as its character the
|
||||
** next character of the format string, instead of the next
|
||||
** argument. For example, printf("%.78'-") prints 78 minus
|
||||
** signs, the same as printf("%.78c",'-').
|
||||
**
|
||||
** + When compiled using GCC on a SPARC, this version of printf is
|
||||
** faster than the library printf for SUN OS 4.1.
|
||||
**
|
||||
** + All functions are fully reentrant.
|
||||
**
|
||||
** This file contains code for a set of "printf"-like routines. These
|
||||
** routines format strings much like the printf() from the standard C
|
||||
** library, though the implementation here has enhancements to support
|
||||
** SQLlite.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -187,43 +149,15 @@ static void appendSpace(StrAccum *pAccum, int N){
|
||||
|
||||
/*
|
||||
** On machines with a small stack size, you can redefine the
|
||||
** SQLITE_PRINT_BUF_SIZE to be less than 350.
|
||||
** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
|
||||
*/
|
||||
#ifndef SQLITE_PRINT_BUF_SIZE
|
||||
# if defined(SQLITE_SMALL_STACK)
|
||||
# define SQLITE_PRINT_BUF_SIZE 50
|
||||
# else
|
||||
# define SQLITE_PRINT_BUF_SIZE 350
|
||||
# endif
|
||||
# define SQLITE_PRINT_BUF_SIZE 70
|
||||
#endif
|
||||
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
|
||||
|
||||
/*
|
||||
** The root program. All variations call this core.
|
||||
**
|
||||
** INPUTS:
|
||||
** func This is a pointer to a function taking three arguments
|
||||
** 1. A pointer to anything. Same as the "arg" parameter.
|
||||
** 2. A pointer to the list of characters to be output
|
||||
** (Note, this list is NOT null terminated.)
|
||||
** 3. An integer number of characters to be output.
|
||||
** (Note: This number might be zero.)
|
||||
**
|
||||
** arg This is the pointer to anything which will be passed as the
|
||||
** first argument to "func". Use it for whatever you like.
|
||||
**
|
||||
** fmt This is the format string, as in the usual print.
|
||||
**
|
||||
** ap This is a pointer to a list of arguments. Same as in
|
||||
** vfprint.
|
||||
**
|
||||
** OUTPUTS:
|
||||
** The return value is the total number of characters sent to
|
||||
** the function "func". Returns -1 on a error.
|
||||
**
|
||||
** Note that the order in which automatic variables are declared below
|
||||
** seems to make a big difference in determining how fast this beast
|
||||
** will run.
|
||||
** Render a string given by "fmt" into the StrAccum object.
|
||||
*/
|
||||
void sqlite3VXPrintf(
|
||||
StrAccum *pAccum, /* Accumulate results here */
|
||||
@ -246,23 +180,23 @@ void sqlite3VXPrintf(
|
||||
etByte flag_long; /* True if "l" flag is present */
|
||||
etByte flag_longlong; /* True if the "ll" flag is present */
|
||||
etByte done; /* Loop termination flag */
|
||||
etByte xtype = 0; /* Conversion paradigm */
|
||||
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
|
||||
sqlite_uint64 longvalue; /* Value for integer types */
|
||||
LONGDOUBLE_TYPE realvalue; /* Value for real types */
|
||||
const et_info *infop; /* Pointer to the appropriate info structure */
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
|
||||
etByte xtype = 0; /* Conversion paradigm */
|
||||
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
|
||||
char *zOut; /* Rendering buffer */
|
||||
int nOut; /* Size of the rendering buffer */
|
||||
char *zExtra; /* Malloced memory used by some conversion */
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int exp, e2; /* exponent of real numbers */
|
||||
int nsd; /* Number of significant digits returned */
|
||||
double rounder; /* Used for rounding floating point values */
|
||||
etByte flag_dp; /* True if decimal point should be shown */
|
||||
etByte flag_rtz; /* True if trailing zeros should be removed */
|
||||
etByte flag_exp; /* True to force display of the exponent */
|
||||
int nsd; /* Number of significant digits returned */
|
||||
#endif
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
|
||||
length = 0;
|
||||
bufpt = 0;
|
||||
for(; (c=(*fmt))!=0; ++fmt){
|
||||
if( c!='%' ){
|
||||
@ -307,9 +241,6 @@ void sqlite3VXPrintf(
|
||||
c = *++fmt;
|
||||
}
|
||||
}
|
||||
if( width > etBUFSIZE-10 ){
|
||||
width = etBUFSIZE-10;
|
||||
}
|
||||
/* Get the precision */
|
||||
if( c=='.' ){
|
||||
precision = 0;
|
||||
@ -356,12 +287,6 @@ void sqlite3VXPrintf(
|
||||
}
|
||||
zExtra = 0;
|
||||
|
||||
|
||||
/* Limit the precision to prevent overflowing buf[] during conversion */
|
||||
if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){
|
||||
precision = etBUFSIZE-40;
|
||||
}
|
||||
|
||||
/*
|
||||
** At this point, variables are initialized as follows:
|
||||
**
|
||||
@ -426,16 +351,26 @@ void sqlite3VXPrintf(
|
||||
if( flag_zeropad && precision<width-(prefix!=0) ){
|
||||
precision = width-(prefix!=0);
|
||||
}
|
||||
bufpt = &buf[etBUFSIZE-1];
|
||||
if( precision<etBUFSIZE-10 ){
|
||||
nOut = etBUFSIZE;
|
||||
zOut = buf;
|
||||
}else{
|
||||
nOut = precision + 10;
|
||||
zOut = zExtra = sqlite3Malloc( nOut );
|
||||
if( zOut==0 ){
|
||||
pAccum->mallocFailed = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
bufpt = &zOut[nOut-1];
|
||||
if( xtype==etORDINAL ){
|
||||
static const char zOrd[] = "thstndrd";
|
||||
int x = (int)(longvalue % 10);
|
||||
if( x>=4 || (longvalue/10)%10==1 ){
|
||||
x = 0;
|
||||
}
|
||||
buf[etBUFSIZE-3] = zOrd[x*2];
|
||||
buf[etBUFSIZE-2] = zOrd[x*2+1];
|
||||
bufpt -= 2;
|
||||
*(--bufpt) = zOrd[x*2+1];
|
||||
*(--bufpt) = zOrd[x*2];
|
||||
}
|
||||
{
|
||||
register const char *cset; /* Use registers for speed */
|
||||
@ -447,7 +382,7 @@ void sqlite3VXPrintf(
|
||||
longvalue = longvalue/base;
|
||||
}while( longvalue>0 );
|
||||
}
|
||||
length = (int)(&buf[etBUFSIZE-1]-bufpt);
|
||||
length = (int)(&zOut[nOut-1]-bufpt);
|
||||
for(idx=precision-length; idx>0; idx--){
|
||||
*(--bufpt) = '0'; /* Zero pad */
|
||||
}
|
||||
@ -458,7 +393,7 @@ void sqlite3VXPrintf(
|
||||
pre = &aPrefix[infop->prefix];
|
||||
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
|
||||
}
|
||||
length = (int)(&buf[etBUFSIZE-1]-bufpt);
|
||||
length = (int)(&zOut[nOut-1]-bufpt);
|
||||
break;
|
||||
case etFLOAT:
|
||||
case etEXP:
|
||||
@ -468,7 +403,6 @@ void sqlite3VXPrintf(
|
||||
length = 0;
|
||||
#else
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
|
||||
if( realvalue<0.0 ){
|
||||
realvalue = -realvalue;
|
||||
prefix = '-';
|
||||
@ -516,7 +450,6 @@ void sqlite3VXPrintf(
|
||||
** If the field type is etGENERIC, then convert to either etEXP
|
||||
** or etFLOAT, as appropriate.
|
||||
*/
|
||||
flag_exp = xtype==etEXP;
|
||||
if( xtype!=etFLOAT ){
|
||||
realvalue += rounder;
|
||||
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
|
||||
@ -537,6 +470,14 @@ void sqlite3VXPrintf(
|
||||
}else{
|
||||
e2 = exp;
|
||||
}
|
||||
if( e2+precision+width > etBUFSIZE - 15 ){
|
||||
bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 );
|
||||
if( bufpt==0 ){
|
||||
pAccum->mallocFailed = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
zOut = bufpt;
|
||||
nsd = 0;
|
||||
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
|
||||
/* The sign in front of the number */
|
||||
@ -568,7 +509,7 @@ void sqlite3VXPrintf(
|
||||
/* Remove trailing zeros and the "." if no digits follow the "." */
|
||||
if( flag_rtz && flag_dp ){
|
||||
while( bufpt[-1]=='0' ) *(--bufpt) = 0;
|
||||
assert( bufpt>buf );
|
||||
assert( bufpt>zOut );
|
||||
if( bufpt[-1]=='.' ){
|
||||
if( flag_altform2 ){
|
||||
*(bufpt++) = '0';
|
||||
@ -578,7 +519,7 @@ void sqlite3VXPrintf(
|
||||
}
|
||||
}
|
||||
/* Add the "eNNN" suffix */
|
||||
if( flag_exp || xtype==etEXP ){
|
||||
if( xtype==etEXP ){
|
||||
*(bufpt++) = aDigits[infop->charset];
|
||||
if( exp<0 ){
|
||||
*(bufpt++) = '-'; exp = -exp;
|
||||
@ -597,8 +538,8 @@ void sqlite3VXPrintf(
|
||||
/* The converted number is in buf[] and zero terminated. Output it.
|
||||
** Note that the number is in the usual order, not reversed as with
|
||||
** integer conversions. */
|
||||
length = (int)(bufpt-buf);
|
||||
bufpt = buf;
|
||||
length = (int)(bufpt-zOut);
|
||||
bufpt = zOut;
|
||||
|
||||
/* Special case: Add leading zeros if the flag_zeropad flag is
|
||||
** set and we are not left justified */
|
||||
@ -736,9 +677,7 @@ void sqlite3VXPrintf(
|
||||
appendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
if( zExtra ){
|
||||
sqlite3_free(zExtra);
|
||||
}
|
||||
sqlite3_free(zExtra);
|
||||
}/* End for loop over the format string */
|
||||
} /* End of function */
|
||||
|
||||
@ -752,6 +691,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
testcase(p->mallocFailed);
|
||||
return;
|
||||
}
|
||||
assert( p->zText!=0 || p->nChar==0 );
|
||||
if( N<0 ){
|
||||
N = sqlite3Strlen30(z);
|
||||
}
|
||||
@ -783,7 +723,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
if( zOld==0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
p->mallocFailed = 1;
|
||||
@ -792,6 +732,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( p->zText );
|
||||
memcpy(&p->zText[p->nChar], z, N);
|
||||
p->nChar += N;
|
||||
}
|
||||
|
@ -98,6 +98,24 @@ static void resolveAlias(
|
||||
sqlite3DbFree(db, pDup);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return TRUE if the name zCol occurs anywhere in the USING clause.
|
||||
**
|
||||
** Return FALSE if the USING clause is NULL or if it does not contain
|
||||
** zCol.
|
||||
*/
|
||||
static int nameInUsingClause(IdList *pUsing, const char *zCol){
|
||||
if( pUsing ){
|
||||
int k;
|
||||
for(k=0; k<pUsing->nId; k++){
|
||||
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
|
||||
** that name in the set of source tables in pSrcList and make the pExpr
|
||||
@ -189,7 +207,14 @@ static int lookupName(
|
||||
}
|
||||
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
||||
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
||||
IdList *pUsing;
|
||||
/* If there has been exactly one prior match and this match
|
||||
** is for the right-hand table of a NATURAL JOIN or is in a
|
||||
** USING clause, then skip this match.
|
||||
*/
|
||||
if( cnt==1 ){
|
||||
if( pItem->jointype & JT_NATURAL ) continue;
|
||||
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
|
||||
}
|
||||
cnt++;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->pTab = pTab;
|
||||
@ -197,26 +222,6 @@ static int lookupName(
|
||||
pSchema = pTab->pSchema;
|
||||
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
||||
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
|
||||
if( i<pSrcList->nSrc-1 ){
|
||||
if( pItem[1].jointype & JT_NATURAL ){
|
||||
/* If this match occurred in the left table of a natural join,
|
||||
** then skip the right table to avoid a duplicate match */
|
||||
pItem++;
|
||||
i++;
|
||||
}else if( (pUsing = pItem[1].pUsing)!=0 ){
|
||||
/* If this match occurs on a column that is in the USING clause
|
||||
** of a join, skip the search of the right table of the join
|
||||
** to avoid a duplicate match there. */
|
||||
int k;
|
||||
for(k=0; k<pUsing->nId; k++){
|
||||
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
|
||||
pItem++;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ Select *sqlite3SelectNew(
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
||||
assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */
|
||||
if( pNew==0 ){
|
||||
assert( db->mallocFailed );
|
||||
pNew = &standin;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
@ -92,6 +93,7 @@ Select *sqlite3SelectNew(
|
||||
}else{
|
||||
assert( pNew->pSrc!=0 || pParse->nErr>0 );
|
||||
}
|
||||
assert( pNew!=&standin );
|
||||
return pNew;
|
||||
}
|
||||
|
||||
@ -1270,7 +1272,10 @@ static int selectColumnsFromExprList(
|
||||
}else{
|
||||
Expr *pColExpr = p; /* The expression that is the result column name */
|
||||
Table *pTab; /* Table associated with this expression */
|
||||
while( pColExpr->op==TK_DOT ) pColExpr = pColExpr->pRight;
|
||||
while( pColExpr->op==TK_DOT ){
|
||||
pColExpr = pColExpr->pRight;
|
||||
assert( pColExpr!=0 );
|
||||
}
|
||||
if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
|
||||
/* For columns use the column name name */
|
||||
int iCol = pColExpr->iColumn;
|
||||
|
138
src/shell.c
138
src/shell.c
@ -17,6 +17,17 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Enable large-file support for fopen() and friends on unix.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
# define _LARGE_FILE 1
|
||||
# ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -60,7 +71,7 @@
|
||||
#else
|
||||
/* Make sure isatty() has a prototype.
|
||||
*/
|
||||
extern int isatty();
|
||||
extern int isatty(int);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
@ -74,6 +85,11 @@ extern int isatty();
|
||||
/* True if the timer is enabled */
|
||||
static int enableTimer = 0;
|
||||
|
||||
/* ctype macros that work with signed characters */
|
||||
#define IsSpace(X) isspace((unsigned char)X)
|
||||
#define IsDigit(X) isdigit((unsigned char)X)
|
||||
#define ToLower(X) (char)tolower((unsigned char)X)
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
@ -265,23 +281,23 @@ static void iotracePrintf(const char *zFormat, ...){
|
||||
*/
|
||||
static int isNumber(const char *z, int *realnum){
|
||||
if( *z=='-' || *z=='+' ) z++;
|
||||
if( !isdigit(*z) ){
|
||||
if( !IsDigit(*z) ){
|
||||
return 0;
|
||||
}
|
||||
z++;
|
||||
if( realnum ) *realnum = 0;
|
||||
while( isdigit(*z) ){ z++; }
|
||||
while( IsDigit(*z) ){ z++; }
|
||||
if( *z=='.' ){
|
||||
z++;
|
||||
if( !isdigit(*z) ) return 0;
|
||||
while( isdigit(*z) ){ z++; }
|
||||
if( !IsDigit(*z) ) return 0;
|
||||
while( IsDigit(*z) ){ z++; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
if( *z=='e' || *z=='E' ){
|
||||
z++;
|
||||
if( *z=='+' || *z=='-' ) z++;
|
||||
if( !isdigit(*z) ) return 0;
|
||||
while( isdigit(*z) ){ z++; }
|
||||
if( !IsDigit(*z) ) return 0;
|
||||
while( IsDigit(*z) ){ z++; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
return *z==0;
|
||||
@ -322,7 +338,6 @@ static char *local_getline(char *zPrompt, FILE *in){
|
||||
char *zLine;
|
||||
int nLine;
|
||||
int n;
|
||||
int eol;
|
||||
|
||||
if( zPrompt && *zPrompt ){
|
||||
printf("%s",zPrompt);
|
||||
@ -332,8 +347,7 @@ static char *local_getline(char *zPrompt, FILE *in){
|
||||
zLine = malloc( nLine );
|
||||
if( zLine==0 ) return 0;
|
||||
n = 0;
|
||||
eol = 0;
|
||||
while( !eol ){
|
||||
while( 1 ){
|
||||
if( n+100>nLine ){
|
||||
nLine = nLine*2 + 100;
|
||||
zLine = realloc(zLine, nLine);
|
||||
@ -345,7 +359,6 @@ static char *local_getline(char *zPrompt, FILE *in){
|
||||
return 0;
|
||||
}
|
||||
zLine[n] = 0;
|
||||
eol = 1;
|
||||
break;
|
||||
}
|
||||
while( zLine[n] ){ n++; }
|
||||
@ -353,7 +366,7 @@ static char *local_getline(char *zPrompt, FILE *in){
|
||||
n--;
|
||||
if( n>0 && zLine[n-1]=='\r' ) n--;
|
||||
zLine[n] = 0;
|
||||
eol = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
zLine = realloc( zLine, n+1 );
|
||||
@ -402,6 +415,7 @@ struct callback_data {
|
||||
int statsOn; /* True to display memory stats before each finalize */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
FILE *out; /* Write results here */
|
||||
int nErr; /* Number of errors seen */
|
||||
int mode; /* An output mode setting */
|
||||
int writableSchema; /* True if PRAGMA writable_schema=ON */
|
||||
int showHeader; /* True to show column names in List or Column mode */
|
||||
@ -927,27 +941,33 @@ static char *appendText(char *zIn, char const *zAppend, char quote){
|
||||
** querying the SQLITE_MASTER table.
|
||||
*/
|
||||
static int run_table_dump_query(
|
||||
FILE *out, /* Send output here */
|
||||
sqlite3 *db, /* Database to query */
|
||||
const char *zSelect, /* SELECT statement to extract content */
|
||||
const char *zFirstRow /* Print before first row, if not NULL */
|
||||
struct callback_data *p, /* Query context */
|
||||
const char *zSelect, /* SELECT statement to extract content */
|
||||
const char *zFirstRow /* Print before first row, if not NULL */
|
||||
){
|
||||
sqlite3_stmt *pSelect;
|
||||
int rc;
|
||||
rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
|
||||
rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
|
||||
if( rc!=SQLITE_OK || !pSelect ){
|
||||
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
|
||||
p->nErr++;
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3_step(pSelect);
|
||||
while( rc==SQLITE_ROW ){
|
||||
if( zFirstRow ){
|
||||
fprintf(out, "%s", zFirstRow);
|
||||
fprintf(p->out, "%s", zFirstRow);
|
||||
zFirstRow = 0;
|
||||
}
|
||||
fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
|
||||
fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0));
|
||||
rc = sqlite3_step(pSelect);
|
||||
}
|
||||
return sqlite3_finalize(pSelect);
|
||||
rc = sqlite3_finalize(pSelect);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
|
||||
p->nErr++;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1074,6 +1094,7 @@ static int shell_exec(
|
||||
){
|
||||
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
int rc2;
|
||||
const char *zLeftover; /* Tail of unprocessed SQL */
|
||||
|
||||
if( pzErrMsg ){
|
||||
@ -1090,7 +1111,7 @@ static int shell_exec(
|
||||
if( !pStmt ){
|
||||
/* this happens for a comment or white-space */
|
||||
zSql = zLeftover;
|
||||
while( isspace(zSql[0]) ) zSql++;
|
||||
while( IsSpace(zSql[0]) ) zSql++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1167,10 +1188,11 @@ static int shell_exec(
|
||||
/* Finalize the statement just executed. If this fails, save a
|
||||
** copy of the error message. Otherwise, set zSql to point to the
|
||||
** next statement to execute. */
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
rc2 = sqlite3_finalize(pStmt);
|
||||
if( rc!=SQLITE_NOMEM ) rc = rc2;
|
||||
if( rc==SQLITE_OK ){
|
||||
zSql = zLeftover;
|
||||
while( isspace(zSql[0]) ) zSql++;
|
||||
while( IsSpace(zSql[0]) ) zSql++;
|
||||
}else if( pzErrMsg ){
|
||||
*pzErrMsg = save_err_msg(db);
|
||||
}
|
||||
@ -1273,10 +1295,10 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
zSelect = appendText(zSelect, "|| ')' FROM ", 0);
|
||||
zSelect = appendText(zSelect, zTable, '"');
|
||||
|
||||
rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt);
|
||||
rc = run_table_dump_query(p, zSelect, zPrepStmt);
|
||||
if( rc==SQLITE_CORRUPT ){
|
||||
zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
|
||||
rc = run_table_dump_query(p->out, p->db, zSelect, 0);
|
||||
run_table_dump_query(p, zSelect, 0);
|
||||
}
|
||||
if( zSelect ) free(zSelect);
|
||||
}
|
||||
@ -1292,19 +1314,30 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
*/
|
||||
static int run_schema_dump_query(
|
||||
struct callback_data *p,
|
||||
const char *zQuery,
|
||||
char **pzErrMsg
|
||||
const char *zQuery
|
||||
){
|
||||
int rc;
|
||||
rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
|
||||
char *zErr = 0;
|
||||
rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
|
||||
if( rc==SQLITE_CORRUPT ){
|
||||
char *zQ2;
|
||||
int len = strlen30(zQuery);
|
||||
if( pzErrMsg ) sqlite3_free(*pzErrMsg);
|
||||
fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");
|
||||
if( zErr ){
|
||||
fprintf(p->out, "/****** %s ******/\n", zErr);
|
||||
sqlite3_free(zErr);
|
||||
zErr = 0;
|
||||
}
|
||||
zQ2 = malloc( len+100 );
|
||||
if( zQ2==0 ) return rc;
|
||||
sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
|
||||
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
|
||||
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
|
||||
if( rc ){
|
||||
fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
|
||||
}else{
|
||||
rc = SQLITE_CORRUPT;
|
||||
}
|
||||
sqlite3_free(zErr);
|
||||
free(zQ2);
|
||||
}
|
||||
return rc;
|
||||
@ -1441,7 +1474,7 @@ static int booleanValue(char *zArg){
|
||||
int val = atoi(zArg);
|
||||
int j;
|
||||
for(j=0; zArg[j]; j++){
|
||||
zArg[j] = (char)tolower(zArg[j]);
|
||||
zArg[j] = ToLower(zArg[j]);
|
||||
}
|
||||
if( strcmp(zArg,"on")==0 ){
|
||||
val = 1;
|
||||
@ -1467,7 +1500,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
/* Parse the input line into tokens.
|
||||
*/
|
||||
while( zLine[i] && nArg<ArraySize(azArg) ){
|
||||
while( isspace((unsigned char)zLine[i]) ){ i++; }
|
||||
while( IsSpace(zLine[i]) ){ i++; }
|
||||
if( zLine[i]==0 ) break;
|
||||
if( zLine[i]=='\'' || zLine[i]=='"' ){
|
||||
int delim = zLine[i++];
|
||||
@ -1479,7 +1512,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
|
||||
}else{
|
||||
azArg[nArg++] = &zLine[i];
|
||||
while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
|
||||
while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
|
||||
if( zLine[i] ) zLine[i++] = 0;
|
||||
resolve_backslashes(azArg[nArg-1]);
|
||||
}
|
||||
@ -1550,7 +1583,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}else
|
||||
|
||||
if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
|
||||
char *zErrMsg = 0;
|
||||
open_db(p);
|
||||
/* When playing back a "dump", the content might appear in an order
|
||||
** which causes immediate foreign key constraints to be violated.
|
||||
@ -1558,17 +1590,18 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
|
||||
fprintf(p->out, "BEGIN TRANSACTION;\n");
|
||||
p->writableSchema = 0;
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0);
|
||||
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
|
||||
p->nErr = 0;
|
||||
if( nArg==1 ){
|
||||
run_schema_dump_query(p,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0
|
||||
"WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
|
||||
);
|
||||
run_schema_dump_query(p,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE name=='sqlite_sequence'", 0
|
||||
"WHERE name=='sqlite_sequence'"
|
||||
);
|
||||
run_table_dump_query(p->out, p->db,
|
||||
run_table_dump_query(p,
|
||||
"SELECT sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
|
||||
);
|
||||
@ -1579,8 +1612,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
run_schema_dump_query(p,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE tbl_name LIKE shellstatic() AND type=='table'"
|
||||
" AND sql NOT NULL", 0);
|
||||
run_table_dump_query(p->out, p->db,
|
||||
" AND sql NOT NULL");
|
||||
run_table_dump_query(p,
|
||||
"SELECT sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL"
|
||||
" AND type IN ('index','trigger','view')"
|
||||
@ -1593,13 +1626,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
|
||||
p->writableSchema = 0;
|
||||
}
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr,"Error: %s\n", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
}else{
|
||||
fprintf(p->out, "COMMIT;\n");
|
||||
}
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
|
||||
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
|
||||
fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
|
||||
@ -1732,7 +1761,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
zCommit = "COMMIT";
|
||||
while( (zLine = local_getline(0, in))!=0 ){
|
||||
char *z;
|
||||
i = 0;
|
||||
lineno++;
|
||||
azCol[0] = zLine;
|
||||
for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
|
||||
@ -2021,7 +2049,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
data.mode = MODE_Semi;
|
||||
if( nArg>1 ){
|
||||
int i;
|
||||
for(i=0; azArg[1][i]; i++) azArg[1][i] = (char)tolower(azArg[1][i]);
|
||||
for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
|
||||
if( strcmp(azArg[1],"sqlite_master")==0 ){
|
||||
char *new_argv[2], *new_colv[2];
|
||||
new_argv[0] = "CREATE TABLE sqlite_master (\n"
|
||||
@ -2207,7 +2235,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
if( testctrl<0 ){
|
||||
testctrl = aCtrl[i].ctrlCode;
|
||||
}else{
|
||||
fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]);
|
||||
fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
|
||||
testctrl = -1;
|
||||
break;
|
||||
}
|
||||
@ -2344,7 +2372,7 @@ static int _contains_semicolon(const char *z, int N){
|
||||
*/
|
||||
static int _all_whitespace(const char *z){
|
||||
for(; *z; z++){
|
||||
if( isspace(*(unsigned char*)z) ) continue;
|
||||
if( IsSpace(z[0]) ) continue;
|
||||
if( *z=='/' && z[1]=='*' ){
|
||||
z += 2;
|
||||
while( *z && (*z!='*' || z[1]!='/') ){ z++; }
|
||||
@ -2369,11 +2397,11 @@ static int _all_whitespace(const char *z){
|
||||
** as is the Oracle "/".
|
||||
*/
|
||||
static int _is_command_terminator(const char *zLine){
|
||||
while( isspace(*(unsigned char*)zLine) ){ zLine++; };
|
||||
while( IsSpace(zLine[0]) ){ zLine++; };
|
||||
if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
|
||||
return 1; /* Oracle */
|
||||
}
|
||||
if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
|
||||
if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
|
||||
&& _all_whitespace(&zLine[2]) ){
|
||||
return 1; /* SQL Server */
|
||||
}
|
||||
@ -2443,7 +2471,7 @@ static int process_input(struct callback_data *p, FILE *in){
|
||||
nSqlPrior = nSql;
|
||||
if( zSql==0 ){
|
||||
int i;
|
||||
for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
|
||||
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
|
||||
if( zLine[i]!=0 ){
|
||||
nSql = strlen30(zLine);
|
||||
zSql = malloc( nSql+3 );
|
||||
@ -2715,6 +2743,7 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(argv[i],"-batch")==0 ){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( strcmp(argv[i],"-heap")==0 ){
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
int j, c;
|
||||
const char *zSize;
|
||||
sqlite3_int64 szHeap;
|
||||
@ -2727,7 +2756,6 @@ int main(int argc, char **argv){
|
||||
if( c=='G' ){ szHeap *= 1000000000; break; }
|
||||
}
|
||||
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_VFSTRACE
|
||||
|
@ -1399,8 +1399,8 @@ struct sqlite3_mem_methods {
|
||||
** allocator is engaged to handle all of SQLites memory allocation needs.
|
||||
** The first pointer (the memory pointer) must be aligned to an 8-byte
|
||||
** boundary or subsequent behavior of SQLite will be undefined.
|
||||
** The minimum allocation size is capped at 2^12. Reasonable values
|
||||
** for the minimum allocation size are 2^5 through 2^8.</dd>
|
||||
** The minimum allocation size is capped at 2**12. Reasonable values
|
||||
** for the minimum allocation size are 2**5 through 2**8.</dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
@ -2799,7 +2799,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** that the supplied string is nul-terminated, then there is a small
|
||||
** performance advantage to be gained by passing an nByte parameter that
|
||||
** is equal to the number of bytes in the input string <i>including</i>
|
||||
** the nul-terminator bytes.
|
||||
** the nul-terminator bytes as this saves SQLite from having to
|
||||
** make a copy of the input string.
|
||||
**
|
||||
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
|
||||
** past the end of the first SQL statement in zSql. These routines only
|
||||
@ -3020,6 +3021,13 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** number of <u>bytes</u> in the value, not the number of characters.)^
|
||||
** ^If the fourth parameter is negative, the length of the string is
|
||||
** the number of bytes up to the first zero terminator.
|
||||
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
|
||||
** or sqlite3_bind_text16() then that parameter must be the byte offset
|
||||
** where the NUL terminator would occur assuming the string were NUL
|
||||
** terminated. If any NUL characters occur at byte offsets less than
|
||||
** the value of the fourth parameter then the resulting string value will
|
||||
** contain embedded NULs. The result of expressions involving strings
|
||||
** with embedded NULs is undefined.
|
||||
**
|
||||
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
|
||||
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
|
||||
@ -4038,7 +4046,12 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
||||
** is non-negative, then as many bytes (not characters) of the text
|
||||
** pointed to by the 2nd parameter are taken as the application-defined
|
||||
** function result.
|
||||
** function result. If the 3rd parameter is non-negative, then it
|
||||
** must be the byte offset into the string where the NUL terminator would
|
||||
** appear if the string where NUL terminated. If any NUL characters occur
|
||||
** in the string at a byte offset that is less than the value of the 3rd
|
||||
** parameter, then the resulting string will contain embedded NULs and the
|
||||
** result of expressions operating on strings with embedded NULs is undefined.
|
||||
** ^If the 4th parameter to the sqlite3_result_text* interfaces
|
||||
** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that
|
||||
** function as the destructor on the text or BLOB result when it has
|
||||
|
@ -3104,6 +3104,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
# define sqlite3VtabUnlock(X)
|
||||
# define sqlite3VtabUnlockList(X)
|
||||
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
|
||||
# define sqlite3GetVTable(X,Y) ((VTable*)0)
|
||||
#else
|
||||
void sqlite3VtabClear(sqlite3 *db, Table*);
|
||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||
@ -3113,6 +3114,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
void sqlite3VtabUnlock(VTable *);
|
||||
void sqlite3VtabUnlockList(sqlite3*);
|
||||
int sqlite3VtabSavepoint(sqlite3 *, int, int);
|
||||
VTable *sqlite3GetVTable(sqlite3*, Table*);
|
||||
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
|
||||
#endif
|
||||
void sqlite3VtabMakeWritable(Parse*,Table*);
|
||||
@ -3132,7 +3134,6 @@ int sqlite3Reprepare(Vdbe*);
|
||||
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
|
||||
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
|
||||
int sqlite3TempInMemory(const sqlite3*);
|
||||
VTable *sqlite3GetVTable(sqlite3*, Table*);
|
||||
const char *sqlite3JournalModename(int);
|
||||
int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
|
||||
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
|
||||
|
@ -963,7 +963,7 @@ static int auth_callback(
|
||||
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
|
||||
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
|
||||
Tcl_DStringFree(&str);
|
||||
zReply = Tcl_GetStringResult(pDb->interp);
|
||||
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
|
||||
if( strcmp(zReply,"SQLITE_OK")==0 ){
|
||||
rc = SQLITE_OK;
|
||||
}else if( strcmp(zReply,"SQLITE_DENY")==0 ){
|
||||
@ -1012,14 +1012,12 @@ static char *local_getline(char *zPrompt, FILE *in){
|
||||
char *zLine;
|
||||
int nLine;
|
||||
int n;
|
||||
int eol;
|
||||
|
||||
nLine = 100;
|
||||
zLine = malloc( nLine );
|
||||
if( zLine==0 ) return 0;
|
||||
n = 0;
|
||||
eol = 0;
|
||||
while( !eol ){
|
||||
while( 1 ){
|
||||
if( n+100>nLine ){
|
||||
nLine = nLine*2 + 100;
|
||||
zLine = realloc(zLine, nLine);
|
||||
@ -1031,14 +1029,13 @@ static char *local_getline(char *zPrompt, FILE *in){
|
||||
return 0;
|
||||
}
|
||||
zLine[n] = 0;
|
||||
eol = 1;
|
||||
break;
|
||||
}
|
||||
while( zLine[n] ){ n++; }
|
||||
if( n>0 && zLine[n-1]=='\n' ){
|
||||
n--;
|
||||
zLine[n] = 0;
|
||||
eol = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
zLine = realloc( zLine, n+1 );
|
||||
@ -2206,7 +2203,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
zCommit = "COMMIT";
|
||||
while( (zLine = local_getline(0, in))!=0 ){
|
||||
char *z;
|
||||
i = 0;
|
||||
lineno++;
|
||||
azCol[0] = zLine;
|
||||
for(i=0, z=zLine; *z; z++){
|
||||
@ -2635,14 +2631,16 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** Change the encryption key on the currently open database.
|
||||
*/
|
||||
case DB_REKEY: {
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
int nKey;
|
||||
void *pKey;
|
||||
#endif
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "KEY");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
|
||||
rc = sqlite3_rekey(pDb->db, pKey, nKey);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
|
||||
@ -3066,8 +3064,6 @@ static int DbObjCmdAdaptor(
|
||||
*/
|
||||
static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
SqliteDb *p;
|
||||
void *pKey = 0;
|
||||
int nKey = 0;
|
||||
const char *zArg;
|
||||
char *zErrMsg;
|
||||
int i;
|
||||
@ -3075,6 +3071,10 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
const char *zVfs = 0;
|
||||
int flags;
|
||||
Tcl_DString translatedFilename;
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
void *pKey = 0;
|
||||
int nKey = 0;
|
||||
#endif
|
||||
|
||||
/* In normal use, each TCL interpreter runs in a single thread. So
|
||||
** by default, we can turn of mutexing on SQLite database connections.
|
||||
@ -3106,7 +3106,9 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
for(i=3; i+1<objc; i+=2){
|
||||
zArg = Tcl_GetString(objv[i]);
|
||||
if( strcmp(zArg,"-key")==0 ){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
|
||||
#endif
|
||||
}else if( strcmp(zArg, "-vfs")==0 ){
|
||||
zVfs = Tcl_GetString(objv[i+1]);
|
||||
}else if( strcmp(zArg, "-readonly")==0 ){
|
||||
|
@ -356,6 +356,7 @@ void sqlite3Update(
|
||||
}
|
||||
}
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
assert( aRegIdx );
|
||||
if( openAll || aRegIdx[i]>0 ){
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb,
|
||||
@ -542,6 +543,7 @@ void sqlite3Update(
|
||||
|
||||
/* Close all tables */
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
assert( aRegIdx );
|
||||
if( openAll || aRegIdx[i]>0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0);
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
|
||||
}
|
||||
/* copy digits to exponent */
|
||||
while( z<zEnd && sqlite3Isdigit(*z) ){
|
||||
e = e*10 + (*z - '0');
|
||||
e = e<10000 ? (e*10 + (*z - '0')) : 10000;
|
||||
z+=incr;
|
||||
eValid = 1;
|
||||
}
|
||||
@ -382,6 +382,12 @@ do_atof_calc:
|
||||
result = s * scale;
|
||||
result *= 1.0e+308;
|
||||
}
|
||||
}else if( e>=342 ){
|
||||
if( esign<0 ){
|
||||
result = 0.0*s;
|
||||
}else{
|
||||
result = 1e308*1e308*s; /* Infinity */
|
||||
}
|
||||
}else{
|
||||
/* 1.0e+22 is the largest power of 10 than can be
|
||||
** represented exactly. */
|
||||
|
23
src/vdbe.c
23
src/vdbe.c
@ -2188,7 +2188,7 @@ case OP_Column: {
|
||||
zRec = (char*)pC->aRow;
|
||||
}else if( pC->isIndex ){
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
rc = sqlite3BtreeKeySize(pCrsr, &payloadSize64);
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
|
||||
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
||||
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
|
||||
** payload size, so it is impossible for payloadSize64 to be
|
||||
@ -2197,7 +2197,7 @@ case OP_Column: {
|
||||
payloadSize = (u32)payloadSize64;
|
||||
}else{
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
rc = sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
||||
VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
||||
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
||||
}
|
||||
}else if( ALWAYS(pC->pseudoTableReg>0) ){
|
||||
@ -4243,14 +4243,14 @@ case OP_RowData: {
|
||||
|
||||
if( pC->isIndex ){
|
||||
assert( !pC->isTable );
|
||||
rc = sqlite3BtreeKeySize(pCrsr, &n64);
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
|
||||
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
||||
if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
n = (u32)n64;
|
||||
}else{
|
||||
rc = sqlite3BtreeDataSize(pCrsr, &n);
|
||||
VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
|
||||
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
||||
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
@ -5519,7 +5519,7 @@ case OP_JournalMode: { /* out2-prerelease */
|
||||
** in temporary storage or if the VFS does not support shared memory
|
||||
*/
|
||||
if( eNew==PAGER_JOURNALMODE_WAL
|
||||
&& (zFilename[0]==0 /* Temp file */
|
||||
&& (sqlite3Strlen30(zFilename)==0 /* Temp file */
|
||||
|| !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */
|
||||
){
|
||||
eNew = eOld;
|
||||
@ -5940,10 +5940,15 @@ case OP_VRename: {
|
||||
assert( memIsValid(pName) );
|
||||
REGISTER_TRACE(pOp->p1, pName);
|
||||
assert( pName->flags & MEM_Str );
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
importVtabErrMsg(p, pVtab);
|
||||
p->expired = 0;
|
||||
|
||||
testcase( pName->enc==SQLITE_UTF8 );
|
||||
testcase( pName->enc==SQLITE_UTF16BE );
|
||||
testcase( pName->enc==SQLITE_UTF16LE );
|
||||
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
importVtabErrMsg(p, pVtab);
|
||||
p->expired = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -782,30 +782,29 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
** makes the code easier to read during debugging. None of this happens
|
||||
** in a production build.
|
||||
*/
|
||||
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
if( !p ) return;
|
||||
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
|
||||
assert( p->nOp>0 || p->aOp==0 );
|
||||
assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );
|
||||
if( p->nOp ){
|
||||
char **pz = &p->aOp[p->nOp-1].zComment;
|
||||
assert( p->aOp );
|
||||
sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
|
||||
p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap);
|
||||
}
|
||||
}
|
||||
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
if( p ){
|
||||
va_start(ap, zFormat);
|
||||
sqlite3DbFree(p->db, *pz);
|
||||
*pz = sqlite3VMPrintf(p->db, zFormat, ap);
|
||||
vdbeVComment(p, zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
if( !p ) return;
|
||||
sqlite3VdbeAddOp0(p, OP_Noop);
|
||||
assert( p->nOp>0 || p->aOp==0 );
|
||||
assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );
|
||||
if( p->nOp ){
|
||||
char **pz = &p->aOp[p->nOp-1].zComment;
|
||||
if( p ){
|
||||
sqlite3VdbeAddOp0(p, OP_Noop);
|
||||
va_start(ap, zFormat);
|
||||
sqlite3DbFree(p->db, *pz);
|
||||
*pz = sqlite3VMPrintf(p->db, zFormat, ap);
|
||||
vdbeVComment(p, zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
@ -3066,7 +3065,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
||||
** this code can safely assume that nCellKey is 32-bits
|
||||
*/
|
||||
assert( sqlite3BtreeCursorIsValid(pCur) );
|
||||
rc = sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
|
||||
assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
|
||||
|
||||
@ -3141,7 +3140,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
Mem m;
|
||||
|
||||
assert( sqlite3BtreeCursorIsValid(pCur) );
|
||||
rc = sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
|
||||
/* nCellKey will always be between 0 and 0xffffffff because of the say
|
||||
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
|
||||
|
@ -2343,7 +2343,7 @@ int sqlite3WalRead(
|
||||
int sz;
|
||||
i64 iOffset;
|
||||
sz = pWal->hdr.szPage;
|
||||
sz = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
|
||||
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
|
||||
testcase( sz<=32768 );
|
||||
testcase( sz>=65536 );
|
||||
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
|
||||
|
11
src/where.c
11
src/where.c
@ -705,7 +705,7 @@ static int isLikeOrGlob(
|
||||
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
|
||||
z = (char *)sqlite3_value_text(pVal);
|
||||
}
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-31526-56213 */
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
|
||||
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
|
||||
}else if( op==TK_STRING ){
|
||||
z = pRight->u.zToken;
|
||||
@ -723,7 +723,7 @@ static int isLikeOrGlob(
|
||||
*ppPrefix = pPrefix;
|
||||
if( op==TK_VARIABLE ){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-31526-56213 */
|
||||
sqlite3VdbeSetVarmask(v, pRight->iColumn);
|
||||
if( *pisComplete && pRight->u.zToken[1] ){
|
||||
/* If the rhs of the LIKE expression is a variable, and the current
|
||||
** value of the variable means there is no need to invoke the LIKE
|
||||
@ -1855,6 +1855,7 @@ static void bestOrClauseIndex(
|
||||
tempWC.pOuter = pWC;
|
||||
tempWC.op = TK_AND;
|
||||
tempWC.a = pOrTerm;
|
||||
tempWC.wctrlFlags = 0;
|
||||
tempWC.nTerm = 1;
|
||||
bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
|
||||
}else{
|
||||
@ -2476,7 +2477,6 @@ static int whereKeyStats(
|
||||
if( pVal==0 ) return SQLITE_ERROR;
|
||||
n = pIdx->aiRowEst[0];
|
||||
aSample = pIdx->aSample;
|
||||
i = 0;
|
||||
eType = sqlite3_value_type(pVal);
|
||||
|
||||
if( eType==SQLITE_INTEGER ){
|
||||
@ -2637,7 +2637,7 @@ static int valueFromExpr(
|
||||
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
){
|
||||
int iVar = pExpr->iColumn;
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-31526-56213 */
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
|
||||
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -4896,7 +4896,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
WHERETRACE(("*** Optimizer selects table %d for loop %d"
|
||||
" with cost=%g and nRow=%g\n",
|
||||
bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow));
|
||||
if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){
|
||||
/* The ALWAYS() that follows was added to hush up clang scan-build */
|
||||
if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 && ALWAYS(ppOrderBy) ){
|
||||
*ppOrderBy = 0;
|
||||
}
|
||||
if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){
|
||||
|
59
test/fts-9fd058691.test
Normal file
59
test/fts-9fd058691.test
Normal file
@ -0,0 +1,59 @@
|
||||
# 2011 October 13
|
||||
#
|
||||
# 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 the FTS SQLite module.
|
||||
#
|
||||
# This file implements tests to verify that ticket [9fd058691] has been
|
||||
# fixed.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set ::testprefix fts3-9fd058691
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE fts USING fts3( tags TEXT);
|
||||
INSERT INTO fts (tags) VALUES ('tag1');
|
||||
SELECT * FROM fts WHERE tags MATCH 'tag1';
|
||||
} {tag1}
|
||||
|
||||
do_test 1.1 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
UPDATE fts SET tags = 'tag1' WHERE rowid = 1;
|
||||
SELECT * FROM fts WHERE tags MATCH 'tag1';
|
||||
}
|
||||
} {tag1}
|
||||
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE fts USING fts3(tags TEXT);
|
||||
INSERT INTO fts (docid, tags) VALUES (1, 'tag1');
|
||||
INSERT INTO fts (docid, tags) VALUES (2, NULL);
|
||||
INSERT INTO fts (docid, tags) VALUES (3, 'three');
|
||||
} {}
|
||||
|
||||
do_test 2.1 {
|
||||
execsql {
|
||||
UPDATE fts SET tags = 'two' WHERE rowid = 2;
|
||||
SELECT * FROM fts WHERE tags MATCH 'two';
|
||||
}
|
||||
} {two}
|
||||
|
||||
finish_test
|
@ -200,6 +200,9 @@ do_test fts3ao-4.7 {
|
||||
SELECT * FROM t5;
|
||||
}
|
||||
} {{the quick brown fox} {jumped over the} {lazy dog}}
|
||||
do_execsql_test fts3ao-4.8 {
|
||||
SELECT snippet(t5, '[', ']') FROM t5 WHERE t5 MATCH 'the'
|
||||
} {{[the] quick brown fox} {jumped over [the]}}
|
||||
|
||||
# Test that it is possible to rename an FTS4 table. Renaming an FTS4 table
|
||||
# involves renaming the extra %_docsize and %_stat tables.
|
||||
|
@ -304,4 +304,57 @@ do_test fts3d-5.1 {
|
||||
}
|
||||
} {{Index already optimal} 2 0}
|
||||
|
||||
|
||||
# ALTER TABLE RENAME should work regardless of the database encoding.
|
||||
#
|
||||
do_test fts3d-6.0 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA encoding=UTF8;
|
||||
CREATE VIRTUAL TABLE fts USING fts3(a,b,c);
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {fts_content fts_segdir fts_segments}
|
||||
do_test fts3d-6.1 {
|
||||
db eval {
|
||||
ALTER TABLE fts RENAME TO xyz;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {xyz_content xyz_segdir xyz_segments}
|
||||
do_test fts3d-6.2 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA encoding=UTF16le;
|
||||
CREATE VIRTUAL TABLE fts USING fts3(a,b,c);
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {fts_content fts_segdir fts_segments}
|
||||
do_test fts3d-6.3 {
|
||||
db eval {
|
||||
ALTER TABLE fts RENAME TO xyz;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {xyz_content xyz_segdir xyz_segments}
|
||||
do_test fts3d-6.4 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA encoding=UTF16be;
|
||||
CREATE VIRTUAL TABLE fts USING fts3(a,b,c);
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {fts_content fts_segdir fts_segments}
|
||||
do_test fts3d-6.5 {
|
||||
db eval {
|
||||
ALTER TABLE fts RENAME TO xyz;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {xyz_content xyz_segdir xyz_segments}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -426,6 +426,18 @@ foreach {tn setup} {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH '"jk xduvfhk" OR "zm azavwm"'
|
||||
} {8 15 26 92 96}
|
||||
}
|
||||
|
||||
if {$tn>1} {
|
||||
# These tests will not work with $tn==1, as in this case table t1 is
|
||||
# created using FTS3. The ^ syntax is only available with FTS4 tables.
|
||||
#
|
||||
do_select_test 7.1 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH '^zm mjpavjuhw'
|
||||
} {56 62}
|
||||
do_select_test 7.2 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH '^azavwm zm'
|
||||
} {43}
|
||||
}
|
||||
}
|
||||
|
||||
set testprefix fts3defer
|
||||
@ -449,5 +461,33 @@ do_execsql_test 3.3 {
|
||||
SELECT count(*) FROM x1 WHERE x1 MATCH '"d e f"'
|
||||
} {16}
|
||||
|
||||
# At one point the following was causing a floating-point exception.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
CREATE VIRTUAL TABLE x2 USING FTS4(x);
|
||||
BEGIN;
|
||||
INSERT INTO x2 VALUES('m m m m m m m m m m m m m m m m m m m m m m m m m m');
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 SELECT * FROM x2;
|
||||
INSERT INTO x2 VALUES('a b c d e f g h i j k l m n o p q r s t u v w x y m');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 4.2 {
|
||||
SELECT * FROM x2 WHERE x2 MATCH 'a b c d e f g h i j k l m n o p q r s';
|
||||
} {{a b c d e f g h i j k l m n o p q r s t u v w x y m}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -82,4 +82,53 @@ do_faultsim_test 2.1 -prep {
|
||||
faultsim_test_result {0 {a * 1 1 a 0 1 1 b * 1 1 b 0 1 1 c * 1 1 c 0 1 1 x * 1 1 x 1 1 1 y * 1 1 y 1 1 1 z * 1 1 z 1 1 1}}
|
||||
}
|
||||
|
||||
do_faultsim_test 3.0 -faults oom* -prep {
|
||||
faultsim_delete_and_reopen
|
||||
db eval { CREATE TABLE 'xx yy'(a, b); }
|
||||
} -body {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE tt USING fts4(content="xx yy");
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
do_faultsim_test 3.1 -faults oom* -prep {
|
||||
faultsim_delete_and_reopen
|
||||
db func zip zip
|
||||
db func unzip unzip
|
||||
} -body {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE tt USING fts4(compress=zip, uncompress=unzip);
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
do_test 4.0 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE ft USING fts4(a, b);
|
||||
INSERT INTO ft VALUES('U U T C O', 'F N D E S');
|
||||
INSERT INTO ft VALUES('P H X G B', 'I D M R U');
|
||||
INSERT INTO ft VALUES('P P X D M', 'Y V N T C');
|
||||
INSERT INTO ft VALUES('Z L Q O W', 'D F U N Q');
|
||||
INSERT INTO ft VALUES('A J D U P', 'C H M Q E');
|
||||
INSERT INTO ft VALUES('P S A O H', 'S Z C W D');
|
||||
INSERT INTO ft VALUES('T B N L W', 'C A K T I');
|
||||
INSERT INTO ft VALUES('K E Z L O', 'L L Y C E');
|
||||
INSERT INTO ft VALUES('C R E S V', 'Q V F W P');
|
||||
INSERT INTO ft VALUES('S K H G W', 'R W Q F G');
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
do_faultsim_test 4.1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db eval {SELECT * FROM sqlite_master}
|
||||
} -body {
|
||||
execsql { INSERT INTO ft(ft) VALUES('rebuild') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
163
test/fts3first.test
Normal file
163
test/fts3first.test
Normal file
@ -0,0 +1,163 @@
|
||||
# 2011 October 18
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix fts3first
|
||||
|
||||
proc lreverse {L} {
|
||||
set res [list]
|
||||
for {set ii [expr [llength $L]-1]} {$ii>=0} {incr ii -1} {
|
||||
lappend res [lindex $L $ii]
|
||||
}
|
||||
set res
|
||||
}
|
||||
|
||||
proc mit {blob} {
|
||||
set scan(littleEndian) i*
|
||||
set scan(bigEndian) I*
|
||||
binary scan $blob $scan($::tcl_platform(byteOrder)) r
|
||||
return $r
|
||||
}
|
||||
db func mit mit
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING FTS4(a, b, c);
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(0, 'K H D S T', 'V M N Y K', 'S Z N Q S');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(1, 'K N J L W', 'S Z W J Q', 'D U W S E');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(2, 'B P M O I', 'R P H W S', 'R J L L E');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(3, 'U R Q M L', 'M J K A V', 'Q W J T J');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(4, 'N J C Y N', 'R U D X V', 'B O U A Q');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(5, 'Q L X L U', 'I F N X S', 'U Q A N Y');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(6, 'M R G U T', 'U V I Q P', 'X Y D L S');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(7, 'D Y P O I', 'X J P K R', 'V O T H V');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(8, 'R Y D L R', 'U U E S J', 'N W L M R');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(9, 'Z P F N P', 'W A X D U', 'V A E Q A');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(10, 'Q I A Q M', 'N D K H C', 'A H T Q Z');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(11, 'T E R Q B', 'C I B C B', 'F Z U W R');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(12, 'E S V U W', 'T P F W H', 'A M D J Q');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(13, 'X S B X Y', 'U D N D P', 'X Z Y G F');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(14, 'K H A B L', 'S R C C Z', 'D W E H J');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(15, 'C E U C C', 'W F M N M', 'T Z U X T');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(16, 'Q G C G H', 'H N N B H', 'B Q I H Y');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(17, 'Q T S K B', 'W B D Y N', 'V J P E C');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(18, 'A J M O Q', 'L G Y Y A', 'G N M R N');
|
||||
INSERT INTO x1(docid,a,b,c) VALUES(19, 'T R Y P Y', 'N V Y B X', 'L Z T N T');
|
||||
|
||||
CREATE VIRTUAL TABLE x2 USING FTS4(a, b, c, order=DESC);
|
||||
INSERT INTO x2(docid, a, b, c) SELECT docid, a, b, c FROM x1;
|
||||
}
|
||||
|
||||
|
||||
# Test queries.
|
||||
#
|
||||
foreach x {1 2} {
|
||||
foreach {tn match res} {
|
||||
1 "^K" {0 1 14}
|
||||
2 "^S" {0 1 14}
|
||||
3 "^W" {9 15 17}
|
||||
4 "^J" {}
|
||||
5 "^E" {12}
|
||||
6 "V ^-E" {0 3 4 6 7 9 17 19}
|
||||
7 "V -^E" {0 3 4 6 7 9 17 19}
|
||||
8 "^-E V" {0 3 4 6 7 9 17 19}
|
||||
9 "-^E V" {0 3 4 6 7 9 17 19}
|
||||
10 "V" {0 3 4 6 7 9 12 17 19}
|
||||
|
||||
11 {"^K H"} {0 14}
|
||||
12 {"K H"} {0 10 14}
|
||||
13 {"K ^H"} {}
|
||||
} {
|
||||
set rev [lreverse $res]
|
||||
do_execsql_test 1.$x.$tn.1 {SELECT docid FROM x1 WHERE x1 MATCH $match} $res
|
||||
do_execsql_test 1.$x.$tn.2 {SELECT docid FROM x2 WHERE x2 MATCH $match} $rev
|
||||
}
|
||||
|
||||
do_execsql_test 1.$x.[expr $tn+1] {
|
||||
INSERT INTO x1(x1) VALUES('optimize');
|
||||
INSERT INTO x2(x2) VALUES('optimize');
|
||||
} {}
|
||||
}
|
||||
|
||||
# Test the snippet() function.
|
||||
#
|
||||
foreach {tn match res} {
|
||||
1 {^K} {{[K] H D S T} {[K] N J L W} {[K] H A B L}}
|
||||
2 {^X} {{[X] Y D L S} {[X] J P K R} {[X] S B X Y}}
|
||||
3 {^X Y} {{[X] [Y] D L S} {D [Y] P O I...[X] J P K R} {[X] S B X [Y]}}
|
||||
} {
|
||||
set rev [lreverse $res]
|
||||
|
||||
do_execsql_test 1.3.$tn.1 {
|
||||
SELECT snippet(x1, '[', ']', '...') FROM x1 WHERE x1 MATCH $match
|
||||
} $res
|
||||
|
||||
do_execsql_test 1.3.$tn.2 {
|
||||
SELECT snippet(x2, '[', ']', '...') FROM x2 WHERE x2 MATCH $match
|
||||
} $rev
|
||||
}
|
||||
|
||||
# Test matchinfo().
|
||||
#
|
||||
foreach {tn match res} {
|
||||
1 {^K} {
|
||||
{1 3 3 0 0 0 0 0 0}
|
||||
{1 3 3 0 0 0 0 0 0}
|
||||
{1 3 3 0 0 0 0 0 0}
|
||||
}
|
||||
2 {^X} {
|
||||
{0 1 1 0 1 1 1 2 2}
|
||||
{0 1 1 1 1 1 0 2 2}
|
||||
{1 1 1 0 1 1 1 2 2}
|
||||
}
|
||||
3 {^X Y} {
|
||||
{0 1 1 0 1 1 1 2 2 0 6 5 0 5 4 1 4 4}
|
||||
{0 1 1 1 1 1 0 2 2 1 6 5 0 5 4 0 4 4}
|
||||
{1 1 1 0 1 1 1 2 2 1 6 5 0 5 4 1 4 4}
|
||||
}
|
||||
} {
|
||||
set rev [lreverse $res]
|
||||
|
||||
do_execsql_test 1.3.$tn.1 {
|
||||
SELECT mit(matchinfo(x1, 'x')) FROM x1 WHERE x1 MATCH $match
|
||||
} $res
|
||||
do_execsql_test 1.3.$tn.2 {
|
||||
SELECT mit(matchinfo(x2, 'x')) FROM x2 WHERE x2 MATCH $match
|
||||
} $rev
|
||||
}
|
||||
|
||||
# Test that ^ is ignored for FTS3 tables.
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
CREATE VIRTUAL TABLE x3 USING fts3;
|
||||
INSERT INTO x3 VALUES('A B C');
|
||||
INSERT INTO x3 VALUES('B A C');
|
||||
|
||||
CREATE VIRTUAL TABLE x4 USING fts4;
|
||||
INSERT INTO x4 VALUES('A B C');
|
||||
INSERT INTO x4 VALUES('B A C');
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.1 {
|
||||
SELECT * FROM x3 WHERE x3 MATCH '^A';
|
||||
} {{A B C} {B A C}}
|
||||
do_execsql_test 2.2.2 {
|
||||
SELECT * FROM x4 WHERE x4 MATCH '^A';
|
||||
} {{A B C}}
|
||||
|
||||
finish_test
|
@ -294,6 +294,7 @@ do_write_test fts3_malloc-5.1 ft_content {
|
||||
do_test fts3_malloc-5.2 {
|
||||
execsql { CREATE VIRTUAL TABLE ft8 USING fts3(x, tokenize porter) }
|
||||
} {}
|
||||
|
||||
do_write_test fts3_malloc-5.3 ft_content {
|
||||
INSERT INTO ft8 VALUES('short alongertoken reallyquitealotlongerimeanit andthistokenisjustsolongthatonemightbeforgivenforimaginingthatitwasmerelyacontrivedexampleandnotarealtoken')
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ source $testdir/tester.tcl
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
set testprefix fts3matchinfo
|
||||
set sqlite_fts3_enable_parentheses 0
|
||||
|
||||
proc mit {blob} {
|
||||
set scan(littleEndian) i*
|
||||
@ -57,6 +58,9 @@ do_catchsql_test 2.0 {
|
||||
do_catchsql_test 2.1 {
|
||||
CREATE VIRTUAL TABLE x2 USING fts4(mtchinfo=fts3);
|
||||
} {1 {unrecognized parameter: mtchinfo=fts3}}
|
||||
do_catchsql_test 2.2 {
|
||||
CREATE VIRTUAL TABLE x2 USING fts4(matchinfo=fts5);
|
||||
} {1 {unrecognized matchinfo: fts5}}
|
||||
|
||||
# Check that with fts3, the "=" character is permitted in column definitions.
|
||||
#
|
||||
@ -224,6 +228,18 @@ do_matchinfo_test 4.1.3 t4 {t4 MATCH 'a b'} { s {{2 0} {0 2}} }
|
||||
do_matchinfo_test 4.1.4 t4 {t4 MATCH '"a b" c'} { s {{2 0} {0 2}} }
|
||||
do_matchinfo_test 4.1.5 t4 {t4 MATCH 'a "b c"'} { s {{2 0} {0 2}} }
|
||||
do_matchinfo_test 4.1.6 t4 {t4 MATCH 'd d'} { s {{1 0} {0 1}} }
|
||||
do_matchinfo_test 4.1.7 t4 {t4 MATCH 'f OR abcd'} {
|
||||
x {
|
||||
{0 1 1 1 1 1 0 0 0 0 0 0}
|
||||
{1 1 1 0 1 1 0 0 0 0 0 0}
|
||||
}
|
||||
}
|
||||
do_matchinfo_test 4.1.8 t4 {t4 MATCH 'f -abcd'} {
|
||||
x {
|
||||
{0 1 1 1 1 1}
|
||||
{1 1 1 0 1 1}
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 4.2.0 {
|
||||
CREATE VIRTUAL TABLE t5 USING fts4;
|
||||
|
@ -200,4 +200,14 @@ do_execsql_test 4.6 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH 'one*'
|
||||
} {{one two three}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Syntax tests.
|
||||
#
|
||||
do_catchsql_test 5.1 {
|
||||
CREATE VIRTUAL TABLE t4 USING fts4(prefix="abc");
|
||||
} {1 {error parsing prefix parameter: abc}}
|
||||
do_catchsql_test 5.2 {
|
||||
CREATE VIRTUAL TABLE t4 USING fts4(prefix="");
|
||||
} {0 {}}
|
||||
|
||||
finish_test
|
||||
|
@ -138,6 +138,8 @@ foreach {tn param res} {
|
||||
3 "order=dec" {1 {unrecognized order: dec}}
|
||||
4 "order=xxx, order=asc" {1 {unrecognized order: xxx}}
|
||||
5 "order=desc, order=asc" {0 {}}
|
||||
6 "order=xxxx, order=asc" {1 {unrecognized order: xxxx}}
|
||||
7 "order=desk" {1 {unrecognized order: desk}}
|
||||
} {
|
||||
execsql { DROP TABLE IF EXISTS t1 }
|
||||
do_catchsql_test 2.1.$tn "
|
||||
@ -157,6 +159,9 @@ do_execsql_test 2.2 {
|
||||
do_execsql_test 2.3 {
|
||||
SELECT docid FROM t2 WHERE t2 MATCH 'aa';
|
||||
} {3 1}
|
||||
do_execsql_test 2.4 {
|
||||
SELECT docid FROM t2 WHERE t2 MATCH 'aa' ORDER BY content;
|
||||
} {1 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that ticket [56be976859] has been fixed.
|
||||
|
478
test/fts4content.test
Normal file
478
test/fts4content.test
Normal file
@ -0,0 +1,478 @@
|
||||
# 2011 October 03
|
||||
#
|
||||
# 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 content=xxx FTS4 option.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix fts4content
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test organization:
|
||||
#
|
||||
# 1.* - Warm-body tests.
|
||||
#
|
||||
# 2.* - Querying a content=xxx FTS table.
|
||||
#
|
||||
# 3.* - Writing to a content=xxx FTS table.
|
||||
#
|
||||
# 4.* - The "INSERT INTO fts(fts) VALUES('rebuild')" command.
|
||||
#
|
||||
# 5.* - Check that CREATE TABLE, DROP TABLE and ALTER TABLE correctly
|
||||
# ignore any %_content table when used with the content=xxx option.
|
||||
#
|
||||
# 6.* - Test the effects of messing with the schema of table xxx after
|
||||
# creating a content=xxx FTS index.
|
||||
#
|
||||
|
||||
do_execsql_test 1.1.1 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES('w x', 'x y', 'y z');
|
||||
CREATE VIRTUAL TABLE ft1 USING fts4(content=t1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1.2 {
|
||||
PRAGMA table_info(ft1);
|
||||
} {
|
||||
0 a {} 0 {} 0
|
||||
1 b {} 0 {} 0
|
||||
2 c {} 0 {} 0
|
||||
}
|
||||
|
||||
do_execsql_test 1.1.3 { SELECT *, rowid FROM ft1 } {{w x} {x y} {y z} 1}
|
||||
do_execsql_test 1.1.4 { SELECT a, c FROM ft1 WHERE rowid=1 } {{w x} {y z}}
|
||||
|
||||
do_execsql_test 1.1.5 { INSERT INTO ft1(ft1) VALUES('rebuild') } {}
|
||||
do_execsql_test 1.1.6 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'x' } {1}
|
||||
do_execsql_test 1.1.7 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'a' } {}
|
||||
|
||||
do_execsql_test 1.2.1 {
|
||||
DROP TABLE ft1;
|
||||
CREATE VIRTUAL TABLE ft1 USING fts4(content=t1, b);
|
||||
PRAGMA table_info(ft1);
|
||||
} {
|
||||
0 b {} 0 {} 0
|
||||
}
|
||||
do_execsql_test 1.2.2 {
|
||||
SELECT *, rowid FROM ft1
|
||||
} {{x y} 1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following block of tests - 2.* - test that a content=xxx FTS table
|
||||
# can be queried. Also tested are cases where rows identified in the FTS
|
||||
# are missing from the content table, and cases where the index is
|
||||
# inconsistent with the content table.
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t2(x);
|
||||
INSERT INTO t2 VALUES('O S W W F U C R Q I C N P Z Y Y E Y Y E'); -- 1
|
||||
INSERT INTO t2 VALUES('Y X U V L B E H Y J C Y A I A P V F V K'); -- 2
|
||||
INSERT INTO t2 VALUES('P W I N J H I I N I F B K D U Q B Z S F'); -- 3
|
||||
INSERT INTO t2 VALUES('N R O R H J R H G M D I U U B O M P A U'); -- 4
|
||||
INSERT INTO t2 VALUES('Y O V O G T P N G T N F I V B U M J M G'); -- 5
|
||||
INSERT INTO t2 VALUES('J O B N K N E C H Z R K J O U G M K L S'); -- 6
|
||||
INSERT INTO t2 VALUES('S Z S R I Q U A P W R X H K C Z U L S P'); -- 7
|
||||
INSERT INTO t2 VALUES('J C H N R C K R V N M O F Z M Z A I H W'); -- 8
|
||||
INSERT INTO t2 VALUES('O Y G I S J U U W O D Z F J K N R P R L'); -- 9
|
||||
INSERT INTO t2 VALUES('B G L K U R U P V X Z I H V R W C Q A S'); -- 10
|
||||
INSERT INTO t2 VALUES('T F T J F F Y V F W N X K Q A Y L X W G'); -- 11
|
||||
INSERT INTO t2 VALUES('C J U H B Q X L C M M Y E G V F W V Z C'); -- 12
|
||||
INSERT INTO t2 VALUES('B W L T F S G X D P H N G M R I O A X I'); -- 13
|
||||
INSERT INTO t2 VALUES('N G Y O K Q K Z N M H U J E D H U W R K'); -- 14
|
||||
INSERT INTO t2 VALUES('U D T R U Y F J D S J X E H Q G V A S Z'); -- 15
|
||||
INSERT INTO t2 VALUES('M I W P J S H R J D Q I C G P C T P H R'); -- 16
|
||||
INSERT INTO t2 VALUES('J M N I S L X Q C A B F C B Y D H V R J'); -- 17
|
||||
INSERT INTO t2 VALUES('F V Z W J Q L P X Y E W B U Q N H X K T'); -- 18
|
||||
INSERT INTO t2 VALUES('R F S R Y O F Q E I E G H C B H R X Y N'); -- 19
|
||||
INSERT INTO t2 VALUES('U Q Q Q T E P D M F X P J G H X C Q D L'); -- 20
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
CREATE VIRTUAL TABLE ft2 USING fts4(content=t2);
|
||||
INSERT INTO ft2(ft2) VALUES('rebuild');
|
||||
|
||||
-- Modify the backing table a bit: Row 17 is missing and the contents
|
||||
-- of row 20 do not match the FTS index contents.
|
||||
DELETE FROM t2 WHERE rowid = 17;
|
||||
UPDATE t2 SET x = 'a b c d e f g h i j' WHERE rowid = 20;
|
||||
}
|
||||
|
||||
foreach {tn match rowidlist} {
|
||||
1 {S} {1 3 6 7 9 10 13 15 16 17 19}
|
||||
2 {"S R"} {7 19}
|
||||
3 {"N K N"} {6}
|
||||
4 {"Q Q"} {20}
|
||||
5 {"B Y D"} {17}
|
||||
} {
|
||||
do_execsql_test 2.2.1.$tn {
|
||||
SELECT rowid FROM ft2 WHERE ft2 MATCH $match
|
||||
} $rowidlist
|
||||
|
||||
do_execsql_test 2.2.2.$tn {
|
||||
SELECT docid FROM ft2 WHERE ft2 MATCH $match
|
||||
} $rowidlist
|
||||
}
|
||||
|
||||
foreach {tn match result} {
|
||||
1 {"N K N"} {{J O B N K N E C H Z R K J O U G M K L S}}
|
||||
2 {"Q Q"} {{a b c d e f g h i j}}
|
||||
3 {"B Y D"} {{}}
|
||||
} {
|
||||
do_execsql_test 2.3.$tn {
|
||||
SELECT * FROM ft2 WHERE ft2 MATCH $match
|
||||
} $result
|
||||
}
|
||||
|
||||
foreach {tn match result} {
|
||||
1 {"N K N"} {{..O B [N] [K] [N] E..}}
|
||||
2 {"B Y D"} {{}}
|
||||
3 {"Q Q"} {{a [b] [c] [d] e f..}}
|
||||
} {
|
||||
do_execsql_test 2.4.$tn {
|
||||
SELECT snippet(ft2, '[', ']', '..', -1, 6) FROM ft2 WHERE ft2 MATCH $match
|
||||
} $result
|
||||
}
|
||||
|
||||
foreach {tn match result} {
|
||||
1 {"N K N"} {{0 0 6 1 0 1 8 1 0 2 10 1}}
|
||||
2 {"B Y D"} {{}}
|
||||
3 {"Q Q"} {{0 0 2 1 0 0 4 1 0 1 4 1 0 1 6 1}}
|
||||
4 {"Q D L"} {{}}
|
||||
} {
|
||||
do_execsql_test 2.5.$tn {
|
||||
SELECT offsets(ft2) FROM ft2 WHERE ft2 MATCH $match
|
||||
} $result
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following block of tests - 3.* - test that the FTS index can be
|
||||
# modified by writing to the table. But that this has no effect on the
|
||||
# content table.
|
||||
#
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE t3(x, y);
|
||||
CREATE VIRTUAL TABLE ft3 USING fts4(content=t3);
|
||||
}
|
||||
|
||||
do_catchsql_test 3.1.1 {
|
||||
INSERT INTO ft3 VALUES('a b c', 'd e f');
|
||||
} {1 {constraint failed}}
|
||||
do_execsql_test 3.1.2 {
|
||||
INSERT INTO ft3(docid, x, y) VALUES(21, 'a b c', 'd e f');
|
||||
SELECT rowid FROM ft3 WHERE ft3 MATCH '"a b c"';
|
||||
} {21}
|
||||
do_execsql_test 3.1.3 { SELECT * FROM t3 } {}
|
||||
|
||||
# This DELETE does not work, since there is no row in [t3] to base the
|
||||
# DELETE on. So the SELECT on [ft3] still returns rowid 21.
|
||||
do_execsql_test 3.1.4 {
|
||||
DELETE FROM ft3;
|
||||
SELECT rowid FROM ft3 WHERE ft3 MATCH '"a b c"';
|
||||
} {21}
|
||||
|
||||
# If the row is added to [t3] before the DELETE on [ft3], it works.
|
||||
do_execsql_test 3.1.5 {
|
||||
INSERT INTO t3(rowid, x, y) VALUES(21, 'a b c', 'd e f');
|
||||
DELETE FROM ft3;
|
||||
SELECT rowid FROM ft3 WHERE ft3 MATCH '"a b c"';
|
||||
} {}
|
||||
do_execsql_test 3.1.6 { SELECT rowid FROM t3 } {21}
|
||||
|
||||
do_execsql_test 3.2.1 {
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(0, 'R T M S M', 'A F O K H');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(1, 'C Z J O X', 'U S Q D K');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(2, 'N G H P O', 'N O P O C');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(3, 'V H S D R', 'K N G E C');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(4, 'J T R V U', 'U X S L C');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(5, 'N A Y N G', 'X D G P Y');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(6, 'I Q I S P', 'D R O Q B');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(7, 'T K T Z J', 'B W D G O');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(8, 'Y K F X T', 'D F G V G');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(9, 'E L E T L', 'P W N F Z');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(10, 'O G J G X', 'G J F E P');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(11, 'O L N N Z', 'K E Z F D');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(12, 'R Z M R J', 'X G I M Z');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(13, 'L X N N X', 'R R N S T');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(14, 'F L B J H', 'K W F L C');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(15, 'P E B M V', 'E A A B U');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(16, 'V E C F P', 'L U T V K');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(17, 'T N O Z N', 'T P Q X N');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(18, 'V W U W R', 'H O A A V');
|
||||
INSERT INTO ft3(rowid, x, y) VALUES(19, 'A H N L F', 'I G H B O');
|
||||
}
|
||||
|
||||
foreach {tn match rowidlist} {
|
||||
1 "N A" {5 19}
|
||||
2 "x:O" {1 2 10 11 17}
|
||||
3 "y:O" {0 2 6 7 18 19}
|
||||
} {
|
||||
set res [list]
|
||||
foreach rowid $rowidlist { lappend res $rowid {} {} }
|
||||
|
||||
do_execsql_test 3.2.2.$tn {
|
||||
SELECT rowid, * FROM ft3 WHERE ft3 MATCH $match
|
||||
} $res
|
||||
do_execsql_test 3.2.3.$tn {
|
||||
SELECT docid, * FROM ft3 WHERE ft3 MATCH $match
|
||||
} $res
|
||||
}
|
||||
|
||||
do_execsql_test 3.3.1 {
|
||||
INSERT INTO t3(rowid, x, y) VALUES(0, 'R T M S M', 'A F O K H');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(1, 'C Z J O X', 'U S Q D K');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(2, 'N G H P O', 'N O P O C');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(3, 'V H S D R', 'K N G E C');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(4, 'J T R V U', 'U X S L C');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(5, 'N A Y N G', 'X D G P Y');
|
||||
UPDATE ft3 SET x = y, y = x;
|
||||
DELETE FROM t3;
|
||||
}
|
||||
|
||||
foreach {tn match rowidlist} {
|
||||
1 "N A" {5 19}
|
||||
2 "x:O" {0 2 10 11 17}
|
||||
3 "y:O" {1 2 6 7 18 19}
|
||||
} {
|
||||
set res [list]
|
||||
foreach rowid $rowidlist { lappend res $rowid {} {} }
|
||||
|
||||
do_execsql_test 3.3.2.$tn {
|
||||
SELECT rowid, * FROM ft3 WHERE ft3 MATCH $match
|
||||
} $res
|
||||
do_execsql_test 3.3.3.$tn {
|
||||
SELECT docid, * FROM ft3 WHERE ft3 MATCH $match
|
||||
} $res
|
||||
}
|
||||
|
||||
do_execsql_test 3.3.1 {
|
||||
INSERT INTO t3(rowid, x, y) VALUES(15, 'P E B M V', 'E A A B U');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(16, 'V E C F P', 'L U T V K');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(17, 'T N O Z N', 'T P Q X N');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(18, 'V W U W R', 'H O A A V');
|
||||
INSERT INTO t3(rowid, x, y) VALUES(19, 'A H N L F', 'I G H B O');
|
||||
DELETE FROM ft3;
|
||||
}
|
||||
|
||||
foreach {tn match rowidlist} {
|
||||
1 "N A" {5}
|
||||
2 "x:O" {0 2 10 11}
|
||||
3 "y:O" {1 2 6 7}
|
||||
} {
|
||||
set res [list]
|
||||
foreach rowid $rowidlist { lappend res $rowid {} {} }
|
||||
|
||||
do_execsql_test 3.3.2.$tn {
|
||||
SELECT rowid, * FROM ft3 WHERE ft3 MATCH $match
|
||||
} $res
|
||||
do_execsql_test 3.3.3.$tn {
|
||||
SELECT docid, * FROM ft3 WHERE ft3 MATCH $match
|
||||
} $res
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 4.* test the 'rebuild' command. On content=xxx and regular
|
||||
# FTS tables.
|
||||
#
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t4(x);
|
||||
CREATE VIRTUAL TABLE ft4 USING fts4(content=t4);
|
||||
CREATE VIRTUAL TABLE ft4x USING fts4(x);
|
||||
}
|
||||
|
||||
do_execsql_test 4.1.1 {
|
||||
INSERT INTO ft4x(ft4x) VALUES('rebuild');
|
||||
INSERT INTO ft4(ft4) VALUES('rebuild');
|
||||
} {}
|
||||
do_execsql_test 4.1.2 {
|
||||
SELECT id, quote(value) FROM ft4_stat
|
||||
} {0 X'000000'}
|
||||
do_execsql_test 4.1.3 {
|
||||
SELECT id, quote(value) FROM ft4x_stat
|
||||
} {0 X'000000'}
|
||||
|
||||
do_execsql_test 4.2.1 {
|
||||
INSERT INTO ft4x VALUES('M G M F T');
|
||||
INSERT INTO ft4x VALUES('Z Q C A U');
|
||||
INSERT INTO ft4x VALUES('N L L V');
|
||||
INSERT INTO ft4x VALUES('T F D X D');
|
||||
INSERT INTO ft4x VALUES('Z H I S D');
|
||||
|
||||
SELECT id, quote(value) FROM ft4x_stat
|
||||
} {0 X'05182B'}
|
||||
|
||||
do_execsql_test 4.2.2 {
|
||||
INSERT INTO ft4(rowid, x) SELECT rowid, * FROM ft4x;
|
||||
SELECT id, quote(value) FROM ft4_stat
|
||||
} {0 X'05182B'}
|
||||
|
||||
do_execsql_test 4.2.3 {
|
||||
SELECT docid, quote(size) FROM ft4_docsize
|
||||
} {1 X'05' 2 X'05' 3 X'04' 4 X'05' 5 X'05'}
|
||||
|
||||
do_execsql_test 4.2.4 {
|
||||
INSERT INTO ft4x(ft4x) VALUES('rebuild');
|
||||
SELECT id, quote(value) FROM ft4x_stat;
|
||||
SELECT docid, quote(size) FROM ft4x_docsize
|
||||
} {0 X'05182B' 1 X'05' 2 X'05' 3 X'04' 4 X'05' 5 X'05'}
|
||||
|
||||
do_execsql_test 4.2.5 {
|
||||
INSERT INTO ft4(ft4) VALUES('rebuild');
|
||||
SELECT id, quote(value) FROM ft4_stat;
|
||||
SELECT docid, quote(size) FROM ft4_docsize
|
||||
} {0 X'000000'}
|
||||
|
||||
do_execsql_test 4.2.6 {
|
||||
INSERT INTO t4(rowid, x) SELECT rowid, x FROM ft4x;
|
||||
INSERT INTO ft4(ft4) VALUES('rebuild');
|
||||
SELECT id, quote(value) FROM ft4_stat;
|
||||
SELECT docid, quote(size) FROM ft4_docsize
|
||||
} {0 X'05182B' 1 X'05' 2 X'05' 3 X'04' 4 X'05' 5 X'05'}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 5.* test that the following commands do not create/move or
|
||||
# delete a %_content table when used with a content=xxx FTS table.
|
||||
#
|
||||
do_execsql_test 5.1.1 {
|
||||
CREATE TABLE t5(a, b, c, d);
|
||||
CREATE VIRTUAL TABLE ft5 USING fts4(content=t5);
|
||||
SELECT name FROM sqlite_master WHERE name LIKE '%t5%';
|
||||
} {
|
||||
t5 ft5 ft5_segments ft5_segdir
|
||||
sqlite_autoindex_ft5_segdir_1 ft5_docsize ft5_stat
|
||||
}
|
||||
do_execsql_test 5.1.2 {
|
||||
ALTER TABLE ft5 RENAME TO ft6;
|
||||
SELECT name FROM sqlite_master WHERE name LIKE '%t5%';
|
||||
} {
|
||||
t5
|
||||
}
|
||||
do_execsql_test 5.1.3 {
|
||||
SELECT name FROM sqlite_master WHERE name LIKE '%t6%';
|
||||
} {
|
||||
ft6 ft6_segments ft6_segdir
|
||||
sqlite_autoindex_ft6_segdir_1 ft6_docsize ft6_stat
|
||||
}
|
||||
do_execsql_test 5.1.4 {
|
||||
INSERT INTO t5 VALUES('a', 'b', 'c', 'd');
|
||||
INSERT INTO ft6(ft6) VALUES('rebuild');
|
||||
SELECT rowid FROM ft6 WHERE ft6 MATCH 'b';
|
||||
} {1}
|
||||
do_execsql_test 5.1.5 {
|
||||
DROP TABLE ft6;
|
||||
SELECT * FROM t5;
|
||||
} {a b c d}
|
||||
do_execsql_test 5.1.6 {
|
||||
SELECT name FROM sqlite_master WHERE name LIKE '%t6%';
|
||||
} {
|
||||
}
|
||||
do_execsql_test 5.1.7 {
|
||||
CREATE VIRTUAL TABLE ft5 USING fts4(content=t5);
|
||||
CREATE TABLE t5_content(a, b);
|
||||
DROP TABLE ft5;
|
||||
SELECT name FROM sqlite_master WHERE name LIKE '%t5%';
|
||||
} {
|
||||
t5 t5_content
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 6.* test
|
||||
#
|
||||
do_catchsql_test 6.1.1 {
|
||||
CREATE VIRTUAL TABLE ft7 USING fts4(content=t7);
|
||||
} {1 {vtable constructor failed: ft7}}
|
||||
|
||||
do_execsql_test 6.2.1 {
|
||||
CREATE TABLE t7(one, two);
|
||||
CREATE VIRTUAL TABLE ft7 USING fts4(content=t7);
|
||||
INSERT INTO t7 VALUES('A B', 'B A');
|
||||
INSERT INTO t7 VALUES('C D', 'A A');
|
||||
SELECT * FROM ft7;
|
||||
} {
|
||||
{A B} {B A} {C D} {A A}
|
||||
}
|
||||
|
||||
do_catchsql_test 6.2.2 {
|
||||
DROP TABLE t7;
|
||||
SELECT * FROM ft7;
|
||||
} {1 {SQL logic error or missing database}}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 6.2.3 {
|
||||
SELECT name FROM sqlite_master WHERE name LIKE '%t7%'
|
||||
} {
|
||||
ft7 ft7_segments ft7_segdir sqlite_autoindex_ft7_segdir_1
|
||||
ft7_docsize ft7_stat
|
||||
}
|
||||
do_catchsql_test 6.2.4 {
|
||||
SELECT * FROM ft7;
|
||||
} {1 {vtable constructor failed: ft7}}
|
||||
do_execsql_test 6.2.5 {
|
||||
CREATE TABLE t7(x, y);
|
||||
INSERT INTO t7 VALUES('A B', 'B A');
|
||||
INSERT INTO t7 VALUES('C D', 'A A');
|
||||
SELECT * FROM ft7;
|
||||
} {
|
||||
{A B} {B A} {C D} {A A}
|
||||
}
|
||||
|
||||
do_execsql_test 6.2.6 {
|
||||
INSERT INTO ft7(ft7) VALUES('rebuild');
|
||||
SELECT rowid FROM ft7 WHERE ft7 MATCH '"A A"';
|
||||
} {2}
|
||||
|
||||
do_execsql_test 6.2.7 {
|
||||
DROP TABLE t7;
|
||||
CREATE TABLE t7(x);
|
||||
}
|
||||
do_catchsql_test 6.2.8 {
|
||||
SELECT * FROM ft7 WHERE ft7 MATCH '"A A"';
|
||||
} {1 {SQL logic error or missing database}}
|
||||
do_catchsql_test 6.2.9 {
|
||||
SELECT * FROM ft7 WHERE ft7 MATCH '"A A"';
|
||||
} {1 {SQL logic error or missing database}}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_catchsql_test 6.2.10 {
|
||||
SELECT rowid FROM ft7 WHERE ft7 MATCH '"A A"';
|
||||
} {0 2}
|
||||
do_catchsql_test 6.2.11 {
|
||||
SELECT rowid, * FROM ft7 WHERE ft7 MATCH '"A A"';
|
||||
} {0 {2 {}}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 7.*
|
||||
#
|
||||
do_execsql_test 7.1.1 {
|
||||
CREATE VIRTUAL TABLE ft8 USING fts4(content=nosuchtable, x);
|
||||
INSERT INTO ft8(docid, x) VALUES(13, 'U O N X G');
|
||||
INSERT INTO ft8(docid, x) VALUES(14, 'C J J U B');
|
||||
INSERT INTO ft8(docid, x) VALUES(15, 'N J Y G X');
|
||||
INSERT INTO ft8(docid, x) VALUES(16, 'R Y D O R');
|
||||
INSERT INTO ft8(docid, x) VALUES(17, 'I Y T Q O');
|
||||
}
|
||||
|
||||
do_execsql_test 7.1.2 {
|
||||
SELECT docid FROM ft8 WHERE ft8 MATCH 'N';
|
||||
} {13 15}
|
||||
|
||||
finish_test
|
@ -320,6 +320,52 @@ do_realnum_test nan-4.20 {
|
||||
db eval {SELECT x, typeof(x) FROM t1}
|
||||
} {inf real}
|
||||
|
||||
do_realnum_test nan-4.30 {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES('2.5e+9999');
|
||||
SELECT x, typeof(x) FROM t1;
|
||||
}
|
||||
} {inf real}
|
||||
do_realnum_test nan-4.31 {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES('2.5e+10000');
|
||||
SELECT x, typeof(x) FROM t1;
|
||||
}
|
||||
} {inf real}
|
||||
|
||||
do_realnum_test nan-4.32 {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES('2.5e-9999');
|
||||
SELECT x, typeof(x) FROM t1;
|
||||
}
|
||||
} {0.0 real}
|
||||
do_realnum_test nan-4.33 {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES('2.5e-10000');
|
||||
SELECT x, typeof(x) FROM t1;
|
||||
}
|
||||
} {0.0 real}
|
||||
do_realnum_test nan-4.34 {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES('2.5e2147483650');
|
||||
SELECT x, typeof(x) FROM t1;
|
||||
}
|
||||
} {inf real}
|
||||
do_realnum_test nan-4.35 {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES('2.5e-2147483650');
|
||||
SELECT x, typeof(x) FROM t1;
|
||||
}
|
||||
} {0.0 real}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -183,10 +183,12 @@ test_suite "fts3" -prefix "" -description {
|
||||
fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test
|
||||
fts3near.test fts3query.test fts3shared.test fts3snippet.test
|
||||
fts3sort.test
|
||||
|
||||
fts3fault.test fts3malloc.test fts3matchinfo.test
|
||||
|
||||
fts3aux1.test fts3comp1.test fts3auto.test
|
||||
fts4aa.test fts4content.test
|
||||
fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test
|
||||
fts3corrupt2.test
|
||||
fts3first.test
|
||||
}
|
||||
|
||||
|
||||
|
@ -329,6 +329,9 @@ ifcapable attach {
|
||||
do_test pragma-3.8.1 {
|
||||
execsql {PRAGMA quick_check}
|
||||
} {ok}
|
||||
do_test pragma-3.8.2 {
|
||||
execsql {PRAGMA QUICK_CHECK}
|
||||
} {ok}
|
||||
do_test pragma-3.9 {
|
||||
execsql {
|
||||
ATTACH 'testerr.db' AS t2;
|
||||
@ -1219,6 +1222,9 @@ ifcapable pager_pragmas {
|
||||
PRAGMA page_count;
|
||||
}
|
||||
} {2}
|
||||
do_test pragma-14.2uc {
|
||||
execsql {pragma PAGE_COUNT}
|
||||
} {2}
|
||||
|
||||
do_test pragma-14.3 {
|
||||
execsql {
|
||||
@ -1227,6 +1233,9 @@ ifcapable pager_pragmas {
|
||||
PRAGMA page_count;
|
||||
}
|
||||
} {3}
|
||||
do_test pragma-14.3uc {
|
||||
execsql {pragma PAGE_COUNT}
|
||||
} {3}
|
||||
|
||||
do_test pragma-14.4 {
|
||||
set page_size [db one {pragma page_size}]
|
||||
@ -1256,6 +1265,9 @@ ifcapable pager_pragmas {
|
||||
PRAGMA aux.page_count;
|
||||
}
|
||||
} {5}
|
||||
do_test pragma-14.6uc {
|
||||
execsql {pragma AUX.PAGE_COUNT}
|
||||
} {5}
|
||||
}
|
||||
|
||||
# Test that the value set using the cache_size pragma is not reset when the
|
||||
|
@ -3547,7 +3547,7 @@ do_test printf-4.16 {
|
||||
do_test printf-5.1 {
|
||||
set x [sqlite3_mprintf_str {%d %d %100000s} 0 0 {Hello}]
|
||||
string length $x
|
||||
} {344}
|
||||
} {100004}
|
||||
do_test printf-5.2 {
|
||||
sqlite3_mprintf_str {%d %d (%-10.10s) %} -9 -10 {HelloHelloHello}
|
||||
} {-9 -10 (HelloHello) %}
|
||||
|
39
test/tkt-fa7bf5ec.test
Normal file
39
test/tkt-fa7bf5ec.test
Normal file
@ -0,0 +1,39 @@
|
||||
# 2011 October 13
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. Specifically,
|
||||
# it tests that ticket [fa7bf5ec94801e7e2030e41eefe5d9dd96eaacfd] has
|
||||
# been resolved.
|
||||
#
|
||||
# The problem described by this ticket was that the sqlite3ExprCompare()
|
||||
# function was saying that expressions (x='a') and (x='A') were identical
|
||||
# because it was using sqlite3StrICmp() instead of strcmp() to compare string
|
||||
# literals. That was causing the query optimizer for aggregate queries to
|
||||
# believe that both count() operations were identical, and thus only
|
||||
# computing the first count() and making a copy of the result for the
|
||||
# second count().
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test tkt-fa7bf5ec-1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES ('a');
|
||||
INSERT INTO t1 VALUES ('A');
|
||||
INSERT INTO t1 VALUES ('A');
|
||||
SELECT count(CASE WHEN x='a' THEN 1 END),
|
||||
count(CASE WHEN x='A' THEN 1 END)
|
||||
FROM t1;
|
||||
}
|
||||
} {1 2}
|
||||
|
||||
finish_test
|
@ -100,16 +100,18 @@ set x 0
|
||||
# Note: Before the bug was fixed, if [db2] was opened with the "-fullmutex 1"
|
||||
# option, then this test case would cause an assert() to fail.
|
||||
#
|
||||
set ::busyconnection db1
|
||||
db1 eval {SELECT * FROM t2 ORDER BY a LIMIT 20} {
|
||||
do_test tkt3793-2.[incr x] { set ::busyconnection } db1
|
||||
set ::busyconnection db2
|
||||
|
||||
db2 eval { SELECT count(*) FROM t2 }
|
||||
do_test tkt3793-2.[incr x] { set ::busyconnection } db2
|
||||
ifcapable threadsafe {
|
||||
set ::busyconnection db1
|
||||
db1 eval {SELECT * FROM t2 ORDER BY a LIMIT 20} {
|
||||
do_test tkt3793-2.[incr x] { set ::busyconnection } db1
|
||||
set ::busyconnection db2
|
||||
|
||||
db2 eval { SELECT count(*) FROM t2 }
|
||||
do_test tkt3793-2.[incr x] { set ::busyconnection } db2
|
||||
set ::busyconnection db1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do_test tkt3793-3 {
|
||||
db1 close
|
||||
db2 close
|
||||
|
@ -143,7 +143,7 @@ do_multiclient_test tn {
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
# Also test that if the -shm file can be opened for read/write access,
|
||||
# it is, even if readonly_shm=1 is present in the URI.
|
||||
# it is not if readonly_shm=1 is present in the URI.
|
||||
do_test 1.3.2.1 {
|
||||
code1 { db close }
|
||||
code2 { db2 close }
|
||||
@ -151,8 +151,8 @@ do_multiclient_test tn {
|
||||
} {0}
|
||||
do_test 1.3.2.2 {
|
||||
code1 { sqlite3 db file:test.db?readonly_shm=1 }
|
||||
sql1 { SELECT * FROM t1 }
|
||||
} {a b c d e f g h i j k l}
|
||||
csql1 { SELECT * FROM sqlite_master }
|
||||
} {1 {unable to open database file}}
|
||||
do_test 1.3.2.3 {
|
||||
code1 { db close }
|
||||
close [open test.db-shm w]
|
||||
|
@ -342,4 +342,87 @@ do_execsql_test where3-5.3 {
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
# Name resolution with NATURAL JOIN and USING
|
||||
#
|
||||
do_test where3-6.setup {
|
||||
db eval {
|
||||
CREATE TABLE t6w(a, w);
|
||||
INSERT INTO t6w VALUES(1, 'w-one');
|
||||
INSERT INTO t6w VALUES(2, 'w-two');
|
||||
INSERT INTO t6w VALUES(9, 'w-nine');
|
||||
CREATE TABLE t6x(a, x);
|
||||
INSERT INTO t6x VALUES(1, 'x-one');
|
||||
INSERT INTO t6x VALUES(3, 'x-three');
|
||||
INSERT INTO t6x VALUES(9, 'x-nine');
|
||||
CREATE TABLE t6y(a, y);
|
||||
INSERT INTO t6y VALUES(1, 'y-one');
|
||||
INSERT INTO t6y VALUES(4, 'y-four');
|
||||
INSERT INTO t6y VALUES(9, 'y-nine');
|
||||
CREATE TABLE t6z(a, z);
|
||||
INSERT INTO t6z VALUES(1, 'z-one');
|
||||
INSERT INTO t6z VALUES(5, 'z-five');
|
||||
INSERT INTO t6z VALUES(9, 'z-nine');
|
||||
}
|
||||
} {}
|
||||
set cnt 0
|
||||
foreach predicate {
|
||||
{}
|
||||
{ORDER BY a}
|
||||
{ORDER BY t6w.a}
|
||||
{WHERE a>0}
|
||||
{WHERE t6y.a>0}
|
||||
{WHERE a>0 ORDER BY a}
|
||||
} {
|
||||
incr cnt
|
||||
do_test where3-6.$cnt.1 {
|
||||
set sql "SELECT * FROM t6w NATURAL JOIN t6x NATURAL JOIN t6y"
|
||||
append sql " NATURAL JOIN t6z "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.2 {
|
||||
set sql "SELECT * FROM t6w JOIN t6x USING(a) JOIN t6y USING(a)"
|
||||
append sql " JOIN t6z USING(a) "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.3 {
|
||||
set sql "SELECT * FROM t6w NATURAL JOIN t6x JOIN t6y USING(a)"
|
||||
append sql " JOIN t6z USING(a) "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.4 {
|
||||
set sql "SELECT * FROM t6w JOIN t6x USING(a) NATURAL JOIN t6y"
|
||||
append sql " JOIN t6z USING(a) "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.5 {
|
||||
set sql "SELECT * FROM t6w JOIN t6x USING(a) JOIN t6y USING(a)"
|
||||
append sql " NATURAL JOIN t6z "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.6 {
|
||||
set sql "SELECT * FROM t6w JOIN t6x USING(a) NATURAL JOIN t6y"
|
||||
append sql " NATURAL JOIN t6z "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.7 {
|
||||
set sql "SELECT * FROM t6w NATURAL JOIN t6x JOIN t6y USING(a)"
|
||||
append sql " NATURAL JOIN t6z "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
do_test where3-6.$cnt.8 {
|
||||
set sql "SELECT * FROM t6w NATURAL JOIN t6x NATURAL JOIN t6y"
|
||||
append sql " JOIN t6z USING(a) "
|
||||
append sql $::predicate
|
||||
db eval $sql
|
||||
} {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -48,19 +48,18 @@ they do not respect the OPTS variable.
|
||||
#
|
||||
#
|
||||
proc run_quick_test {dir omit_symbol_list} {
|
||||
set target "testfixture"
|
||||
# Compile the value of the OPTS Makefile variable.
|
||||
set opts "-DSQLITE_MEMDEBUG -DSQLITE_DEBUG -DSQLITE_NO_SYNC"
|
||||
set opts ""
|
||||
if {$::tcl_platform(platform)=="windows"} {
|
||||
append opts " -DSQLITE_OS_WIN=1"
|
||||
append opts "OPTS += -DSQLITE_OS_WIN=1\n"
|
||||
set target "testfixture.exe"
|
||||
} elseif {$::tcl_platform(platform)=="os2"} {
|
||||
append opts " -DSQLITE_OS_OS2=1"
|
||||
append opts "OPTS += -DSQLITE_OS_OS2=1\n"
|
||||
} else {
|
||||
append opts " -DSQLITE_OS_UNIX=1"
|
||||
append opts "OPTS += -DSQLITE_OS_UNIX=1\n"
|
||||
}
|
||||
foreach sym $omit_symbol_list {
|
||||
append opts " -D${sym}=1"
|
||||
append opts "OPTS += -D${sym}=1\n"
|
||||
}
|
||||
|
||||
# Create the directory and do the build. If an error occurs return
|
||||
@ -68,12 +67,20 @@ proc run_quick_test {dir omit_symbol_list} {
|
||||
file mkdir $dir
|
||||
puts -nonewline "Building $dir..."
|
||||
flush stdout
|
||||
catch {
|
||||
file copy -force ./config.h $dir
|
||||
file copy -force ./libtool $dir
|
||||
}
|
||||
catch {
|
||||
file copy -force ./config.h $dir
|
||||
file copy -force ./libtool $dir
|
||||
}
|
||||
set fd [open $::MAKEFILE]
|
||||
set mkfile [read $fd]
|
||||
close $fd
|
||||
regsub {\ninclude} $mkfile "\n$opts\ninclude" mkfile
|
||||
set fd [open $dir/makefile w]
|
||||
puts $fd $mkfile
|
||||
close $fd
|
||||
|
||||
set rc [catch {
|
||||
exec $::MAKEBIN -C $dir -f $::MAKEFILE clean $target OPTS=$opts >& $dir/build.log
|
||||
exec $::MAKEBIN -C $dir -f makefile clean $::TARGET >& $dir/build.log
|
||||
}]
|
||||
if {$rc} {
|
||||
puts "No good. See $dir/build.log."
|
||||
@ -102,7 +109,7 @@ catch {
|
||||
puts -nonewline "Testing $dir..."
|
||||
flush stdout
|
||||
set rc [catch {
|
||||
exec $::MAKEBIN -C $dir -f $::MAKEFILE test OPTS=$opts >& $dir/test.log
|
||||
exec $::MAKEBIN -C $dir -f makefile test >& $dir/test.log
|
||||
}]
|
||||
if {$rc} {
|
||||
puts "No good. See $dir/test.log."
|
||||
@ -126,6 +133,7 @@ proc process_options {argv} {
|
||||
set ::MAKEFILE ./Makefile.linux-gcc ;# Default value
|
||||
}
|
||||
set ::SKIP_RUN 0 ;# Default to attempt test
|
||||
set ::TARGET testfixture ;# Default thing to build
|
||||
|
||||
for {set i 0} {$i < [llength $argv]} {incr i} {
|
||||
switch -- [lindex $argv $i] {
|
||||
@ -139,6 +147,11 @@ proc process_options {argv} {
|
||||
set ::MAKEFILE ./Makefile.msc
|
||||
}
|
||||
|
||||
-target {
|
||||
incr i
|
||||
set ::TARGET [lindex $argv $i]
|
||||
}
|
||||
|
||||
-skip_run {
|
||||
set ::SKIP_RUN 1
|
||||
}
|
||||
@ -182,7 +195,6 @@ proc main {argv} {
|
||||
SQLITE_OMIT_DATETIME_FUNCS \
|
||||
SQLITE_OMIT_DECLTYPE \
|
||||
SQLITE_OMIT_DEPRECATED \
|
||||
xxxSQLITE_OMIT_DISKIO \
|
||||
SQLITE_OMIT_EXPLAIN \
|
||||
SQLITE_OMIT_FLAG_PRAGMAS \
|
||||
SQLITE_OMIT_FLOATING_POINT \
|
||||
@ -224,15 +236,11 @@ proc main {argv} {
|
||||
SQLITE_DISABLE_DIRSYNC \
|
||||
SQLITE_DISABLE_LFS \
|
||||
SQLITE_ENABLE_ATOMIC_WRITE \
|
||||
xxxSQLITE_ENABLE_CEROD \
|
||||
SQLITE_ENABLE_COLUMN_METADATA \
|
||||
SQLITE_ENABLE_EXPENSIVE_ASSERT \
|
||||
xxxSQLITE_ENABLE_FTS1 \
|
||||
xxxSQLITE_ENABLE_FTS2 \
|
||||
SQLITE_ENABLE_FTS3 \
|
||||
SQLITE_ENABLE_FTS3_PARENTHESIS \
|
||||
SQLITE_ENABLE_FTS4 \
|
||||
xxxSQLITE_ENABLE_ICU \
|
||||
SQLITE_ENABLE_IOTRACE \
|
||||
SQLITE_ENABLE_LOAD_EXTENSION \
|
||||
SQLITE_ENABLE_LOCKING_STYLE \
|
||||
@ -241,7 +249,7 @@ proc main {argv} {
|
||||
SQLITE_ENABLE_MEMSYS5 \
|
||||
SQLITE_ENABLE_OVERSIZE_CELL_CHECK \
|
||||
SQLITE_ENABLE_RTREE \
|
||||
SQLITE_ENABLE_STAT2 \
|
||||
SQLITE_ENABLE_STAT3 \
|
||||
SQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
SQLITE_ENABLE_UPDATE_DELETE_LIMIT \
|
||||
]
|
||||
|
33
tool/symbols-mingw.sh
Normal file
33
tool/symbols-mingw.sh
Normal file
@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run this script in a directory that contains a valid SQLite makefile in
|
||||
# order to verify that unintentionally exported symbols.
|
||||
#
|
||||
make sqlite3.c
|
||||
|
||||
echo '****** Exported symbols from a build including RTREE && FTS4 ******'
|
||||
gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
|
||||
sqlite3.c
|
||||
nm sqlite3.o | grep " [TD] "
|
||||
|
||||
echo '****** Surplus symbols from a build including RTREE & FTS4 ******'
|
||||
nm sqlite3.o | grep " [TD] " | grep -v " .*sqlite3_"
|
||||
|
||||
echo '****** Dependencies of the core. No extensions. No OS interface *******'
|
||||
gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
|
||||
-DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \
|
||||
sqlite3.c
|
||||
nm sqlite3.o | grep " U "
|
||||
|
||||
echo '****** Dependencies including RTREE & FTS4 *******'
|
||||
gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
|
||||
sqlite3.c
|
||||
nm sqlite3.o | grep " U "
|
@ -7,7 +7,7 @@ make sqlite3.c
|
||||
|
||||
echo '****** Exported symbols from a build including RTREE, FTS4 & ICU ******'
|
||||
gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
|
||||
-DSQLITE_ENABLE_ICU \
|
||||
@ -18,7 +18,7 @@ echo '****** Surplus symbols from a build including RTREE, FTS4 & ICU ******'
|
||||
nm sqlite3.o | grep ' [TD] ' | grep -v ' .*sqlite3_'
|
||||
|
||||
echo '****** Dependencies of the core. No extensions. No OS interface *******'
|
||||
gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \
|
||||
gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
|
||||
-DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \
|
||||
@ -27,7 +27,7 @@ nm sqlite3.o | grep ' U ' | sort -k 3
|
||||
|
||||
echo '****** Dependencies including RTREE & FTS4 *******'
|
||||
gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT2 \
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \
|
||||
sqlite3.c
|
||||
|
13
tool/warnings-clang.sh
Normal file
13
tool/warnings-clang.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#/bin/sh
|
||||
#
|
||||
# Run this script in a directory with a working makefile to check for
|
||||
# compiler warnings in SQLite.
|
||||
#
|
||||
rm -f sqlite3.c
|
||||
make sqlite3.c
|
||||
echo '************* FTS4 and RTREE ****************'
|
||||
scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:'
|
||||
echo '********** ENABLE_STAT3. THREADSAFE=0 *******'
|
||||
scan-build gcc -c -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:'
|
Loading…
Reference in New Issue
Block a user