1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Merged in trunk.

FossilOrigin-Name: d662796c658997be13fdc3b77ad97101b9513da53fd0b824d7a4050cac3f7eba
This commit is contained in:
stephan
2022-07-20 10:09:19 +00:00
69 changed files with 2797 additions and 1133 deletions

View File

@ -4308,8 +4308,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
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 );
char *aFree = (pPhrase->doclist.bFreeList ? pPhrase->doclist.pList : 0);
for(iToken=0; iToken<pPhrase->nToken; iToken++){
Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
@ -4323,6 +4322,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
if( pList==0 ){
sqlite3_free(aPoslist);
sqlite3_free(aFree);
pPhrase->doclist.pList = 0;
pPhrase->doclist.nList = 0;
return SQLITE_OK;
@ -4343,6 +4343,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nPoslist = (int)(aOut - aPoslist);
if( nPoslist==0 ){
sqlite3_free(aPoslist);
sqlite3_free(aFree);
pPhrase->doclist.pList = 0;
pPhrase->doclist.nList = 0;
return SQLITE_OK;
@ -4382,6 +4383,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
}
pPhrase->doclist.pList = aOut;
assert( p1 && p2 );
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
pPhrase->doclist.bFreeList = 1;
pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList);
@ -4394,6 +4396,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
}
}
if( pPhrase->doclist.pList!=aFree ) sqlite3_free(aFree);
return SQLITE_OK;
}
#endif /* SQLITE_DISABLE_FTS4_DEFERRED */
@ -5568,11 +5571,10 @@ static int fts3EvalTestExpr(
default: {
#ifndef SQLITE_DISABLE_FTS4_DEFERRED
if( pCsr->pDeferred
&& (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred)
){
if( pCsr->pDeferred && (pExpr->bDeferred || (
pExpr->iDocid==pCsr->iPrevId && pExpr->pPhrase->doclist.pList
))){
Fts3Phrase *pPhrase = pExpr->pPhrase;
assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 );
if( pExpr->bDeferred ){
fts3EvalInvalidatePoslist(pPhrase);
}

View File

@ -11,6 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is testing the FTS5 module.
#
# TESTRUNNER: slow
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ah

View File

@ -16,12 +16,16 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5fault4
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
set ::TMPDBERROR [list 1 \
{unable to open a temporary database file for storing temporary tables}
]
#-------------------------------------------------------------------------
# An OOM while dropping an fts5 table.
#
@ -391,7 +395,7 @@ do_faultsim_test 14.1 -faults oom-t* -prep {
} -body {
db eval { ALTER TABLE "tbl one" RENAME TO "tbl two" }
} -test {
faultsim_test_result {0 {}}
faultsim_test_result {0 {}} $::TMPDBERROR
}
finish_test

View File

@ -280,6 +280,7 @@ static char *csv_read_one_field(CsvReader *p){
}
p->cTerm = (char)c;
}
assert( p->z==0 || p->n<p->nAlloc );
if( p->z ) p->z[p->n] = 0;
p->bNotFirst = 1;
return p->z;
@ -750,7 +751,7 @@ static int csvtabNext(sqlite3_vtab_cursor *cur){
i++;
}
}while( pCur->rdr.cTerm==',' );
if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){
if( z==0 && i==0 ){
pCur->iRowid = -1;
}else{
pCur->iRowid++;
@ -811,6 +812,12 @@ static int csvtabFilter(
CsvCursor *pCur = (CsvCursor*)pVtabCursor;
CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab;
pCur->iRowid = 0;
/* Ensure the field buffer is always allocated. Otherwise, if the
** first field is zero bytes in size, this may be mistaken for an OOM
** error in csvtabNext(). */
if( csv_append(&pCur->rdr, 0) ) return SQLITE_NOMEM;
if( pCur->rdr.in==0 ){
assert( pCur->rdr.zIn==pTab->zData );
assert( pTab->iStart>=0 );

View File

@ -72,6 +72,7 @@ SQLITE_EXTENSION_INIT1
/* The end-of-input character */
#define RE_EOF 0 /* End of input */
#define RE_START 0xfffffff /* Start of input - larger than an UTF-8 */
/* The NFA is implemented as sequence of opcodes taken from the following
** set. Each opcode has a single integer argument.
@ -93,6 +94,33 @@ SQLITE_EXTENSION_INIT1
#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
#define RE_OP_NOTSPACE 16 /* Not a digit */
#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
#define RE_OP_ATSTART 18 /* Currently at the start of the string */
#if defined(SQLITE_DEBUG)
/* Opcode names used for symbolic debugging */
static const char *ReOpName[] = {
"EOF",
"MATCH",
"ANY",
"ANYSTAR",
"FORK",
"GOTO",
"ACCEPT",
"CC_INC",
"CC_EXC",
"CC_VALUE",
"CC_RANGE",
"WORD",
"NOTWORD",
"DIGIT",
"NOTDIGIT",
"SPACE",
"NOTSPACE",
"BOUNDARY",
"ATSTART",
};
#endif /* SQLITE_DEBUG */
/* Each opcode is a "state" in the NFA */
typedef unsigned short ReStateNumber;
@ -127,7 +155,7 @@ struct ReCompiled {
int *aArg; /* Arguments to each operator */
unsigned (*xNextChar)(ReInput*); /* Next character function */
unsigned char zInit[12]; /* Initial text to match */
int nInit; /* Number of characters in zInit */
int nInit; /* Number of bytes in zInit */
unsigned nState; /* Number of entries in aOp[] and aArg[] */
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
};
@ -200,7 +228,7 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
ReStateNumber *pToFree;
unsigned int i = 0;
unsigned int iSwap = 0;
int c = RE_EOF+1;
int c = RE_START;
int cPrev = 0;
int rc = 0;
ReInput in;
@ -219,6 +247,7 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
in.i++;
}
if( in.i+pRe->nInit>in.mx ) return 0;
c = RE_START-1;
}
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
@ -247,6 +276,10 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
break;
}
case RE_OP_ATSTART: {
if( cPrev==RE_START ) re_add_state(pThis, x+1);
break;
}
case RE_OP_ANY: {
if( c!=0 ) re_add_state(pNext, x+1);
break;
@ -328,7 +361,9 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
}
}
for(i=0; i<pNext->nState; i++){
if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
int x = pNext->aState[i];
while( pRe->aOp[x]==RE_OP_GOTO ) x += pRe->aArg[x];
if( pRe->aOp[x]==RE_OP_ACCEPT ){ rc = 1; break; }
}
re_match_end:
sqlite3_free(pToFree);
@ -483,7 +518,6 @@ static const char *re_subcompile_string(ReCompiled *p){
iStart = p->nState;
switch( c ){
case '|':
case '$':
case ')': {
p->sIn.i--;
return 0;
@ -520,6 +554,14 @@ static const char *re_subcompile_string(ReCompiled *p){
re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
break;
}
case '$': {
re_append(p, RE_OP_MATCH, RE_EOF);
break;
}
case '^': {
re_append(p, RE_OP_ATSTART, 0);
break;
}
case '{': {
int m = 0, n = 0;
int sz, j;
@ -538,6 +580,7 @@ static const char *re_subcompile_string(ReCompiled *p){
if( m==0 ){
if( n==0 ) return "both m and n are zero in '{m,n}'";
re_insert(p, iPrev, RE_OP_FORK, sz+1);
iPrev++;
n--;
}else{
for(j=1; j<m; j++) re_copy(p, iPrev, sz);
@ -656,11 +699,7 @@ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
re_free(pRe);
return zErr;
}
if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
re_append(pRe, RE_OP_MATCH, RE_EOF);
re_append(pRe, RE_OP_ACCEPT, 0);
*ppRe = pRe;
}else if( pRe->sIn.i>=pRe->sIn.mx ){
if( pRe->sIn.i>=pRe->sIn.mx ){
re_append(pRe, RE_OP_ACCEPT, 0);
*ppRe = pRe;
}else{
@ -685,7 +724,7 @@ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6));
pRe->zInit[j++] = 0x80 | (x&0x3f);
}else if( x<=0xffff ){
pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12));
pRe->zInit[j++] = (unsigned char)(0xe0 | (x>>12));
pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
pRe->zInit[j++] = 0x80 | (x&0x3f);
}else{
@ -744,6 +783,67 @@ static void re_sql_func(
}
}
#if defined(SQLITE_DEBUG)
/*
** This function is used for testing and debugging only. It is only available
** if the SQLITE_DEBUG compile-time option is used.
**
** Compile a regular expression and then convert the compiled expression into
** text and return that text.
*/
static void re_bytecode_func(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zPattern;
const char *zErr;
ReCompiled *pRe;
sqlite3_str *pStr;
int i;
int n;
char *z;
zPattern = (const char*)sqlite3_value_text(argv[0]);
if( zPattern==0 ) return;
zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0);
if( zErr ){
re_free(pRe);
sqlite3_result_error(context, zErr, -1);
return;
}
if( pRe==0 ){
sqlite3_result_error_nomem(context);
return;
}
pStr = sqlite3_str_new(0);
if( pStr==0 ) goto re_bytecode_func_err;
if( pRe->nInit>0 ){
sqlite3_str_appendf(pStr, "INIT ");
for(i=0; i<pRe->nInit; i++){
sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]);
}
sqlite3_str_appendf(pStr, "\n");
}
for(i=0; i<pRe->nState; i++){
sqlite3_str_appendf(pStr, "%-8s %4d\n",
ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]);
}
n = sqlite3_str_length(pStr);
z = sqlite3_str_finish(pStr);
if( n==0 ){
sqlite3_free(z);
}else{
sqlite3_result_text(context, z, n-1, sqlite3_free);
}
re_bytecode_func_err:
re_free(pRe);
}
#endif /* SQLITE_DEBUG */
/*
** Invoke this routine to register the regexp() function with the
** SQLite database connection.
@ -768,6 +868,13 @@ int sqlite3_regexp_init(
rc = sqlite3_create_function(db, "regexpi", 2,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
(void*)db, re_sql_func, 0, 0);
#if defined(SQLITE_DEBUG)
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "regexp_bytecode", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
0, re_bytecode_func, 0, 0);
}
#endif /* SQLITE_DEBUG */
}
return rc;
}

View File

@ -30,6 +30,16 @@ SQLITE_EXTENSION_INIT1
#ifndef SQLITE_OMIT_VIRTUALTABLE
#define STMT_NUM_INTEGER_COLUMN 10
typedef struct StmtRow StmtRow;
struct StmtRow {
sqlite3_int64 iRowid; /* Rowid value */
char *zSql; /* column "sql" */
int aCol[STMT_NUM_INTEGER_COLUMN+1]; /* all other column values */
StmtRow *pNext; /* Next row to return */
};
/* stmt_vtab is a subclass of sqlite3_vtab which will
** serve as the underlying representation of a stmt virtual table
*/
@ -47,8 +57,7 @@ typedef struct stmt_cursor stmt_cursor;
struct stmt_cursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
sqlite3 *db; /* Database connection for this cursor */
sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */
sqlite3_int64 iRowid; /* The rowid */
StmtRow *pRow; /* Current row */
};
/*
@ -92,7 +101,7 @@ static int stmtConnect(
"CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
"reprep,run,mem)");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
pNew = sqlite3_malloc64( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
@ -114,7 +123,7 @@ static int stmtDisconnect(sqlite3_vtab *pVtab){
*/
static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
stmt_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
pCur = sqlite3_malloc64( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((stmt_vtab*)p)->db;
@ -122,10 +131,21 @@ static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
return SQLITE_OK;
}
static void stmtCsrReset(stmt_cursor *pCur){
StmtRow *pRow = 0;
StmtRow *pNext = 0;
for(pRow=pCur->pRow; pRow; pRow=pNext){
pNext = pRow->pNext;
sqlite3_free(pRow);
}
pCur->pRow = 0;
}
/*
** Destructor for a stmt_cursor.
*/
static int stmtClose(sqlite3_vtab_cursor *cur){
stmtCsrReset((stmt_cursor*)cur);
sqlite3_free(cur);
return SQLITE_OK;
}
@ -136,8 +156,9 @@ static int stmtClose(sqlite3_vtab_cursor *cur){
*/
static int stmtNext(sqlite3_vtab_cursor *cur){
stmt_cursor *pCur = (stmt_cursor*)cur;
pCur->iRowid++;
pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
StmtRow *pNext = pCur->pRow->pNext;
sqlite3_free(pCur->pRow);
pCur->pRow = pNext;
return SQLITE_OK;
}
@ -151,39 +172,11 @@ static int stmtColumn(
int i /* Which column to return */
){
stmt_cursor *pCur = (stmt_cursor*)cur;
switch( i ){
case STMT_COLUMN_SQL: {
sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
break;
}
case STMT_COLUMN_NCOL: {
sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
break;
}
case STMT_COLUMN_RO: {
sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
break;
}
case STMT_COLUMN_BUSY: {
sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
break;
}
default: {
assert( i==STMT_COLUMN_MEM );
i = SQLITE_STMTSTATUS_MEMUSED +
STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
/* Fall thru */
}
case STMT_COLUMN_NSCAN:
case STMT_COLUMN_NSORT:
case STMT_COLUMN_NAIDX:
case STMT_COLUMN_NSTEP:
case STMT_COLUMN_REPREP:
case STMT_COLUMN_RUN: {
sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
break;
}
StmtRow *pRow = pCur->pRow;
if( i==STMT_COLUMN_SQL ){
sqlite3_result_text(ctx, pRow->zSql, -1, SQLITE_TRANSIENT);
}else{
sqlite3_result_int(ctx, pRow->aCol[i]);
}
return SQLITE_OK;
}
@ -194,7 +187,7 @@ static int stmtColumn(
*/
static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
stmt_cursor *pCur = (stmt_cursor*)cur;
*pRowid = pCur->iRowid;
*pRowid = pCur->pRow->iRowid;
return SQLITE_OK;
}
@ -204,7 +197,7 @@ static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
*/
static int stmtEof(sqlite3_vtab_cursor *cur){
stmt_cursor *pCur = (stmt_cursor*)cur;
return pCur->pStmt==0;
return pCur->pRow==0;
}
/*
@ -219,9 +212,53 @@ static int stmtFilter(
int argc, sqlite3_value **argv
){
stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
pCur->pStmt = 0;
pCur->iRowid = 0;
return stmtNext(pVtabCursor);
sqlite3_stmt *p = 0;
sqlite3_int64 iRowid = 1;
StmtRow **ppRow = 0;
stmtCsrReset(pCur);
ppRow = &pCur->pRow;
for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){
const char *zSql = sqlite3_sql(p);
sqlite3_int64 nSql = zSql ? strlen(zSql)+1 : 0;
StmtRow *pNew = (StmtRow*)sqlite3_malloc64(sizeof(StmtRow) + nSql);
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(StmtRow));
if( zSql ){
pNew->zSql = (char*)&pNew[1];
memcpy(pNew->zSql, zSql, nSql);
}
pNew->aCol[STMT_COLUMN_NCOL] = sqlite3_column_count(p);
pNew->aCol[STMT_COLUMN_RO] = sqlite3_stmt_readonly(p);
pNew->aCol[STMT_COLUMN_BUSY] = sqlite3_stmt_busy(p);
pNew->aCol[STMT_COLUMN_NSCAN] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_FULLSCAN_STEP, 0
);
pNew->aCol[STMT_COLUMN_NSORT] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_SORT, 0
);
pNew->aCol[STMT_COLUMN_NAIDX] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_AUTOINDEX, 0
);
pNew->aCol[STMT_COLUMN_NSTEP] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_VM_STEP, 0
);
pNew->aCol[STMT_COLUMN_REPREP] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_REPREPARE, 0
);
pNew->aCol[STMT_COLUMN_RUN] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_RUN, 0
);
pNew->aCol[STMT_COLUMN_MEM] = sqlite3_stmt_status(
p, SQLITE_STMTSTATUS_MEMUSED, 0
);
pNew->iRowid = iRowid++;
*ppRow = pNew;
ppRow = &pNew->pNext;
}
return SQLITE_OK;
}
/*

View File

@ -23,6 +23,10 @@ ifcapable !rtree {
return
}
set ::TMPDBERROR [list 1 \
{unable to open a temporary database file for storing temporary tables}
]
# Test summary:
#
# rtree3-1: Test OOM in simple CREATE TABLE, INSERT, DELETE and SELECT
@ -196,9 +200,9 @@ do_test rtree3-7.prep {
do_faultsim_test rtree3-7 -faults oom-* -prep {
faultsim_restore_and_reopen
} -body {
execsql { ALTER TABLE rt RENAME TO rt2 }
execsql { ALTER TABLE rt RENAME TO rt2 }
} -test {
faultsim_test_result {0 {}}
faultsim_test_result {0 {}} $::TMPDBERROR
}
do_faultsim_test rtree3-8 -faults oom-* -prep {