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:
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
}
|
||||
|
125
ext/misc/stmt.c
125
ext/misc/stmt.c
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user