Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 86e2e4cf54 | |||
| f76f7c2e2b |
@@ -927,7 +927,7 @@ LIBRESOBJS =
|
||||
# when the shell is not being dynamically linked.
|
||||
#
|
||||
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
||||
+97
-415
@@ -10,8 +10,8 @@
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains the implementation of the "unionvtab" and "swarmvtab"
|
||||
** virtual tables. These modules provide read-only access to multiple tables,
|
||||
** This file contains the implementation of the "unionvtab" virtual
|
||||
** table. This module provides read-only access to multiple tables,
|
||||
** possibly in multiple database files, via a single database object.
|
||||
** The source tables must have the following characteristics:
|
||||
**
|
||||
@@ -25,48 +25,26 @@
|
||||
**
|
||||
** * Each table must contain a distinct range of rowid values.
|
||||
**
|
||||
** The difference between the two virtual table modules is that for
|
||||
** "unionvtab", all source tables must be located in the main database or
|
||||
** in databases ATTACHed to the main database by the user. For "swarmvtab",
|
||||
** the tables may be located in any database file on disk. The "swarmvtab"
|
||||
** implementation takes care of opening and closing database files
|
||||
** automatically.
|
||||
** A "unionvtab" virtual table is created as follows:
|
||||
**
|
||||
** UNIONVTAB
|
||||
** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql statement>);
|
||||
**
|
||||
** A "unionvtab" virtual table is created as follows:
|
||||
** The implementation evalutes <sql statement> whenever a unionvtab virtual
|
||||
** table is created or opened. It should return one row for each source
|
||||
** database table. The four columns required of each row are:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql-statement>);
|
||||
** 1. The name of the database containing the table ("main" or "temp" or
|
||||
** the name of an attached database). Or NULL to indicate that all
|
||||
** databases should be searched for the table in the usual fashion.
|
||||
**
|
||||
** The implementation evalutes <sql statement> whenever a unionvtab virtual
|
||||
** table is created or opened. It should return one row for each source
|
||||
** database table. The four columns required of each row are:
|
||||
** 2. The name of the database table.
|
||||
**
|
||||
** 1. The name of the database containing the table ("main" or "temp" or
|
||||
** the name of an attached database). Or NULL to indicate that all
|
||||
** databases should be searched for the table in the usual fashion.
|
||||
** 3. The smallest rowid in the range of rowids that may be stored in the
|
||||
** database table (an integer).
|
||||
**
|
||||
** 2. The name of the database table.
|
||||
** 4. The largest rowid in the range of rowids that may be stored in the
|
||||
** database table (an integer).
|
||||
**
|
||||
** 3. The smallest rowid in the range of rowids that may be stored in the
|
||||
** database table (an integer).
|
||||
**
|
||||
** 4. The largest rowid in the range of rowids that may be stored in the
|
||||
** database table (an integer).
|
||||
**
|
||||
** SWARMVTAB
|
||||
**
|
||||
** A "swarmvtab" virtual table is created similarly to a unionvtab table:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE <name>
|
||||
** USING swarmvtab(<sql-statement>, <callback>);
|
||||
**
|
||||
** The difference is that for a swarmvtab table, the first column returned
|
||||
** by the <sql statement> must return a path or URI that can be used to open
|
||||
** the database file containing the source table. The <callback> option
|
||||
** is optional. If included, it is the name of an application-defined
|
||||
** SQL function that is invoked with the URI of the file, if the file
|
||||
** does not already exist on disk.
|
||||
*/
|
||||
|
||||
#include "sqlite3ext.h"
|
||||
@@ -87,30 +65,6 @@ SQLITE_EXTENSION_INIT1
|
||||
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following is also copied from sqliteInt.h. To facilitate coverage
|
||||
** testing.
|
||||
*/
|
||||
#ifndef ALWAYS
|
||||
# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
|
||||
# define ALWAYS(X) (1)
|
||||
# define NEVER(X) (0)
|
||||
# elif !defined(NDEBUG)
|
||||
# define ALWAYS(X) ((X)?1:(assert(0),0))
|
||||
# define NEVER(X) ((X)?(assert(0),1):0)
|
||||
# else
|
||||
# define ALWAYS(X) (X)
|
||||
# define NEVER(X) (X)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The swarmvtab module attempts to keep the number of open database files
|
||||
** at or below this limit. This may not be possible if there are too many
|
||||
** simultaneous queries.
|
||||
*/
|
||||
#define SWARMVTAB_MAX_OPEN 9
|
||||
|
||||
typedef struct UnionCsr UnionCsr;
|
||||
typedef struct UnionTab UnionTab;
|
||||
typedef struct UnionSrc UnionSrc;
|
||||
@@ -125,12 +79,6 @@ struct UnionSrc {
|
||||
char *zTab; /* Source table name */
|
||||
sqlite3_int64 iMin; /* Minimum rowid */
|
||||
sqlite3_int64 iMax; /* Maximum rowid */
|
||||
|
||||
/* Fields used by swarmvtab only */
|
||||
char *zFile; /* Database file containing table zTab */
|
||||
int nUser; /* Current number of users */
|
||||
sqlite3 *db; /* Database handle */
|
||||
UnionSrc *pNextClosable; /* Next in list of closable sources */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -139,17 +87,9 @@ struct UnionSrc {
|
||||
struct UnionTab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database handle */
|
||||
int bSwarm; /* 1 for "swarmvtab", 0 for "unionvtab" */
|
||||
int iPK; /* INTEGER PRIMARY KEY column, or -1 */
|
||||
int nSrc; /* Number of elements in the aSrc[] array */
|
||||
UnionSrc *aSrc; /* Array of source tables, sorted by rowid */
|
||||
|
||||
/* Used by swarmvtab only */
|
||||
char *zSourceStr; /* Expected unionSourceToStr() value */
|
||||
char *zNotFoundCallback; /* UDF to invoke if file not found on open */
|
||||
UnionSrc *pClosable; /* First in list of closable sources */
|
||||
int nOpen; /* Current number of open sources */
|
||||
int nMaxOpen; /* Maximum number of open sources */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -158,20 +98,8 @@ struct UnionTab {
|
||||
struct UnionCsr {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_stmt *pStmt; /* SQL statement to run */
|
||||
|
||||
/* Used by swarmvtab only */
|
||||
sqlite3_int64 iMaxRowid; /* Last rowid to visit */
|
||||
int iTab; /* Index of table read by pStmt */
|
||||
};
|
||||
|
||||
/*
|
||||
** Given UnionTab table pTab and UnionSrc object pSrc, return the database
|
||||
** handle that should be used to access the table identified by pSrc. This
|
||||
** is the main db handle for "unionvtab" tables, or the source-specific
|
||||
** handle for "swarmvtab".
|
||||
*/
|
||||
#define unionGetDb(pTab, pSrc) ((pTab)->bSwarm ? (pSrc)->db : (pTab)->db)
|
||||
|
||||
/*
|
||||
** If *pRc is other than SQLITE_OK when this function is called, it
|
||||
** always returns NULL. Otherwise, it attempts to allocate and return
|
||||
@@ -232,7 +160,7 @@ static void unionDequote(char *z){
|
||||
int iIn = 1;
|
||||
int iOut = 0;
|
||||
if( q=='[' ) q = ']';
|
||||
while( ALWAYS(z[iIn]) ){
|
||||
while( z[iIn] ){
|
||||
if( z[iIn]==q ){
|
||||
if( z[iIn+1]!=q ){
|
||||
/* Character iIn was the close quote. */
|
||||
@@ -274,7 +202,6 @@ static sqlite3_stmt *unionPrepare(
|
||||
char **pzErr /* OUT: Error message */
|
||||
){
|
||||
sqlite3_stmt *pRet = 0;
|
||||
assert( pzErr );
|
||||
if( *pRc==SQLITE_OK ){
|
||||
int rc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -323,7 +250,6 @@ static sqlite3_stmt *unionPreparePrintf(
|
||||
** In this case, *pzErr may be set to point to an error message
|
||||
** buffer allocated by sqlite3_malloc().
|
||||
*/
|
||||
#if 0
|
||||
static void unionReset(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
|
||||
int rc = sqlite3_reset(pStmt);
|
||||
if( *pRc==SQLITE_OK ){
|
||||
@@ -333,39 +259,15 @@ static void unionReset(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Call sqlite3_finalize() on SQL statement pStmt. If *pRc is set to
|
||||
** SQLITE_OK when this function is called, then it is set to the
|
||||
** value returned by sqlite3_finalize() before this function exits.
|
||||
*/
|
||||
static void unionFinalize(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
|
||||
sqlite3 *db = sqlite3_db_handle(pStmt);
|
||||
static void unionFinalize(int *pRc, sqlite3_stmt *pStmt){
|
||||
int rc = sqlite3_finalize(pStmt);
|
||||
if( *pRc==SQLITE_OK ){
|
||||
*pRc = rc;
|
||||
if( rc ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is a no-op for unionvtab. For swarmvtab, it attempts to
|
||||
** close open database files until at most nMax are open. An SQLite error
|
||||
** code is returned if an error occurs, or SQLITE_OK otherwise.
|
||||
*/
|
||||
static void unionCloseSources(UnionTab *pTab, int nMax){
|
||||
while( pTab->pClosable && pTab->nOpen>nMax ){
|
||||
UnionSrc **pp;
|
||||
for(pp=&pTab->pClosable; (*pp)->pNextClosable; pp=&(*pp)->pNextClosable);
|
||||
assert( (*pp)->db );
|
||||
sqlite3_close((*pp)->db);
|
||||
(*pp)->db = 0;
|
||||
*pp = 0;
|
||||
pTab->nOpen--;
|
||||
}
|
||||
if( *pRc==SQLITE_OK ) *pRc = rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -376,52 +278,15 @@ static int unionDisconnect(sqlite3_vtab *pVtab){
|
||||
UnionTab *pTab = (UnionTab*)pVtab;
|
||||
int i;
|
||||
for(i=0; i<pTab->nSrc; i++){
|
||||
UnionSrc *pSrc = &pTab->aSrc[i];
|
||||
sqlite3_free(pSrc->zDb);
|
||||
sqlite3_free(pSrc->zTab);
|
||||
sqlite3_free(pSrc->zFile);
|
||||
sqlite3_close(pSrc->db);
|
||||
sqlite3_free(pTab->aSrc[i].zDb);
|
||||
sqlite3_free(pTab->aSrc[i].zTab);
|
||||
}
|
||||
sqlite3_free(pTab->zSourceStr);
|
||||
sqlite3_free(pTab->zNotFoundCallback);
|
||||
sqlite3_free(pTab->aSrc);
|
||||
sqlite3_free(pTab);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check that the table identified by pSrc is a rowid table. If not,
|
||||
** return SQLITE_ERROR and set (*pzErr) to point to an English language
|
||||
** error message. If the table is a rowid table and no error occurs,
|
||||
** return SQLITE_OK and leave (*pzErr) unmodified.
|
||||
*/
|
||||
static int unionIsIntkeyTable(
|
||||
sqlite3 *db, /* Database handle */
|
||||
UnionSrc *pSrc, /* Source table to test */
|
||||
char **pzErr /* OUT: Error message */
|
||||
){
|
||||
int bPk = 0;
|
||||
const char *zType = 0;
|
||||
int rc;
|
||||
|
||||
sqlite3_table_column_metadata(
|
||||
db, pSrc->zDb, pSrc->zTab, "_rowid_", &zType, 0, 0, &bPk, 0
|
||||
);
|
||||
rc = sqlite3_errcode(db);
|
||||
if( rc==SQLITE_ERROR
|
||||
|| (rc==SQLITE_OK && (!bPk || sqlite3_stricmp("integer", zType)))
|
||||
){
|
||||
rc = SQLITE_ERROR;
|
||||
*pzErr = sqlite3_mprintf("no such rowid table: %s%s%s",
|
||||
(pSrc->zDb ? pSrc->zDb : ""),
|
||||
(pSrc->zDb ? "." : ""),
|
||||
pSrc->zTab
|
||||
);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
||||
** called. In this case it returns NULL.
|
||||
@@ -441,27 +306,41 @@ static int unionIsIntkeyTable(
|
||||
*/
|
||||
static char *unionSourceToStr(
|
||||
int *pRc, /* IN/OUT: Error code */
|
||||
UnionTab *pTab, /* Virtual table object */
|
||||
sqlite3 *db, /* Database handle */
|
||||
UnionSrc *pSrc, /* Source table to test */
|
||||
sqlite3_stmt *pStmt,
|
||||
char **pzErr /* OUT: Error message */
|
||||
){
|
||||
char *zRet = 0;
|
||||
if( *pRc==SQLITE_OK ){
|
||||
sqlite3 *db = unionGetDb(pTab, pSrc);
|
||||
int rc = unionIsIntkeyTable(db, pSrc, pzErr);
|
||||
sqlite3_stmt *pStmt = unionPrepare(&rc, db,
|
||||
"SELECT group_concat(quote(name) || '.' || quote(type)) "
|
||||
"FROM pragma_table_info(?, ?)", pzErr
|
||||
int bPk = 0;
|
||||
const char *zType = 0;
|
||||
int rc;
|
||||
|
||||
sqlite3_table_column_metadata(
|
||||
db, pSrc->zDb, pSrc->zTab, "_rowid_", &zType, 0, 0, &bPk, 0
|
||||
);
|
||||
rc = sqlite3_errcode(db);
|
||||
if( rc==SQLITE_ERROR
|
||||
|| (rc==SQLITE_OK && (!bPk || sqlite3_stricmp("integer", zType)))
|
||||
){
|
||||
rc = SQLITE_ERROR;
|
||||
*pzErr = sqlite3_mprintf("no such rowid table: %s%s%s",
|
||||
(pSrc->zDb ? pSrc->zDb : ""),
|
||||
(pSrc->zDb ? "." : ""),
|
||||
pSrc->zTab
|
||||
);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_text(pStmt, 1, pSrc->zTab, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(pStmt, 2, pSrc->zDb, -1, SQLITE_STATIC);
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
const char *z = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
zRet = unionStrdup(&rc, z);
|
||||
zRet = unionStrdup(&rc, (const char*)sqlite3_column_text(pStmt, 0));
|
||||
}
|
||||
unionFinalize(&rc, pStmt, pzErr);
|
||||
unionReset(&rc, pStmt, pzErr);
|
||||
}
|
||||
|
||||
*pRc = rc;
|
||||
}
|
||||
|
||||
@@ -477,152 +356,34 @@ static char *unionSourceToStr(
|
||||
** other error occurs, SQLITE_OK is returned.
|
||||
*/
|
||||
static int unionSourceCheck(UnionTab *pTab, char **pzErr){
|
||||
const char *zSql =
|
||||
"SELECT group_concat(quote(name) || '.' || quote(type)) "
|
||||
"FROM pragma_table_info(?, ?)";
|
||||
int rc = SQLITE_OK;
|
||||
char *z0 = 0;
|
||||
int i;
|
||||
|
||||
assert( *pzErr==0 );
|
||||
z0 = unionSourceToStr(&rc, pTab, &pTab->aSrc[0], pzErr);
|
||||
for(i=1; i<pTab->nSrc; i++){
|
||||
char *z = unionSourceToStr(&rc, pTab, &pTab->aSrc[i], pzErr);
|
||||
if( rc==SQLITE_OK && sqlite3_stricmp(z, z0) ){
|
||||
*pzErr = sqlite3_mprintf("source table schema mismatch");
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3_free(z);
|
||||
}
|
||||
sqlite3_free(z0);
|
||||
if( pTab->nSrc==0 ){
|
||||
*pzErr = sqlite3_mprintf("no source tables configured");
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *z0 = 0;
|
||||
int i;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to open the swarmvtab database. If initially unable, invoke the
|
||||
** not-found callback UDF and then try again.
|
||||
*/
|
||||
static int unionOpenDatabaseInner(UnionTab *pTab, UnionSrc *pSrc, char **pzErr){
|
||||
int rc = SQLITE_OK;
|
||||
static const int openFlags =
|
||||
SQLITE_OPEN_READONLY | SQLITE_OPEN_URI;
|
||||
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
|
||||
if( rc==SQLITE_OK ) return rc;
|
||||
if( pTab->zNotFoundCallback ){
|
||||
char *zSql = sqlite3_mprintf("SELECT \"%w\"(%Q);",
|
||||
pTab->zNotFoundCallback, pSrc->zFile);
|
||||
sqlite3_close(pSrc->db);
|
||||
pSrc->db = 0;
|
||||
if( zSql==0 ){
|
||||
*pzErr = sqlite3_mprintf("out of memory");
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3_exec(pTab->db, zSql, 0, 0, pzErr);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pSrc->db));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function may only be called for swarmvtab tables. The results of
|
||||
** calling it on a unionvtab table are undefined.
|
||||
**
|
||||
** For a swarmvtab table, this function ensures that source database iSrc
|
||||
** is open. If the database is opened successfully and the schema is as
|
||||
** expected, or if it is already open when this function is called, SQLITE_OK
|
||||
** is returned.
|
||||
**
|
||||
** Alternatively If an error occurs while opening the databases, or if the
|
||||
** database schema is unsuitable, an SQLite error code is returned and (*pzErr)
|
||||
** may be set to point to an English language error message. In this case it is
|
||||
** the responsibility of the caller to eventually free the error message buffer
|
||||
** using sqlite3_free().
|
||||
*/
|
||||
static int unionOpenDatabase(UnionTab *pTab, int iSrc, char **pzErr){
|
||||
int rc = SQLITE_OK;
|
||||
UnionSrc *pSrc = &pTab->aSrc[iSrc];
|
||||
|
||||
assert( pTab->bSwarm && iSrc<pTab->nSrc );
|
||||
if( pSrc->db==0 ){
|
||||
unionCloseSources(pTab, pTab->nMaxOpen-1);
|
||||
rc = unionOpenDatabaseInner(pTab, pSrc, pzErr);
|
||||
pStmt = unionPrepare(&rc, pTab->db, zSql, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
char *z = unionSourceToStr(&rc, pTab, pSrc, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pTab->zSourceStr==0 ){
|
||||
pTab->zSourceStr = z;
|
||||
}else{
|
||||
if( sqlite3_stricmp(z, pTab->zSourceStr) ){
|
||||
*pzErr = sqlite3_mprintf("source table schema mismatch");
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3_free(z);
|
||||
}
|
||||
z0 = unionSourceToStr(&rc, pTab->db, &pTab->aSrc[0], pStmt, pzErr);
|
||||
}
|
||||
for(i=1; i<pTab->nSrc; i++){
|
||||
char *z = unionSourceToStr(&rc, pTab->db, &pTab->aSrc[i], pStmt, pzErr);
|
||||
if( rc==SQLITE_OK && sqlite3_stricmp(z, z0) ){
|
||||
*pzErr = sqlite3_mprintf("source table schema mismatch");
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3_free(z);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pSrc->pNextClosable = pTab->pClosable;
|
||||
pTab->pClosable = pSrc;
|
||||
pTab->nOpen++;
|
||||
}else{
|
||||
sqlite3_close(pSrc->db);
|
||||
pSrc->db = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is a no-op for unionvtab tables. For swarmvtab, increment
|
||||
** the reference count for source table iTab. If the reference count was
|
||||
** zero before it was incremented, also remove the source from the closable
|
||||
** list.
|
||||
*/
|
||||
static void unionIncrRefcount(UnionTab *pTab, int iTab){
|
||||
if( pTab->bSwarm ){
|
||||
UnionSrc *pSrc = &pTab->aSrc[iTab];
|
||||
assert( pSrc->nUser>=0 && pSrc->db );
|
||||
if( pSrc->nUser==0 ){
|
||||
UnionSrc **pp;
|
||||
for(pp=&pTab->pClosable; *pp!=pSrc; pp=&(*pp)->pNextClosable);
|
||||
*pp = pSrc->pNextClosable;
|
||||
pSrc->pNextClosable = 0;
|
||||
}
|
||||
pSrc->nUser++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Finalize the SQL statement pCsr->pStmt and return the result.
|
||||
**
|
||||
** If this is a swarmvtab table (not unionvtab) and pCsr->pStmt was not
|
||||
** NULL when this function was called, also decrement the reference
|
||||
** count on the associated source table. If this means the source tables
|
||||
** refcount is now zero, add it to the closable list.
|
||||
*/
|
||||
static int unionFinalizeCsrStmt(UnionCsr *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->pStmt ){
|
||||
UnionTab *pTab = (UnionTab*)pCsr->base.pVtab;
|
||||
UnionSrc *pSrc = &pTab->aSrc[pCsr->iTab];
|
||||
rc = sqlite3_finalize(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
if( pTab->bSwarm ){
|
||||
pSrc->nUser--;
|
||||
assert( pSrc->nUser>=0 );
|
||||
if( pSrc->nUser==0 ){
|
||||
pSrc->pNextClosable = pTab->pClosable;
|
||||
pTab->pClosable = pSrc;
|
||||
}
|
||||
unionCloseSources(pTab, pTab->nMaxOpen);
|
||||
}
|
||||
unionFinalize(&rc, pStmt);
|
||||
sqlite3_free(z0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -632,11 +393,10 @@ static int unionFinalizeCsrStmt(UnionCsr *pCsr){
|
||||
**
|
||||
** The argv[] array contains the following:
|
||||
**
|
||||
** argv[0] -> module name ("unionvtab" or "swarmvtab")
|
||||
** argv[0] -> module name ("unionvtab")
|
||||
** argv[1] -> database name
|
||||
** argv[2] -> table name
|
||||
** argv[3] -> SQL statement
|
||||
** argv[4] -> not-found callback UDF name
|
||||
*/
|
||||
static int unionConnect(
|
||||
sqlite3 *db,
|
||||
@@ -647,15 +407,14 @@ static int unionConnect(
|
||||
){
|
||||
UnionTab *pTab = 0;
|
||||
int rc = SQLITE_OK;
|
||||
int bSwarm = (pAux==0 ? 0 : 1);
|
||||
const char *zVtab = (bSwarm ? "swarmvtab" : "unionvtab");
|
||||
|
||||
(void)pAux; /* Suppress harmless 'unused parameter' warning */
|
||||
if( sqlite3_stricmp("temp", argv[1]) ){
|
||||
/* unionvtab tables may only be created in the temp schema */
|
||||
*pzErr = sqlite3_mprintf("%s tables must be created in TEMP schema", zVtab);
|
||||
*pzErr = sqlite3_mprintf("unionvtab tables must be created in TEMP schema");
|
||||
rc = SQLITE_ERROR;
|
||||
}else if( argc!=4 && argc!=5 ){
|
||||
*pzErr = sqlite3_mprintf("wrong number of arguments for %s", zVtab);
|
||||
}else if( argc!=4 ){
|
||||
*pzErr = sqlite3_mprintf("wrong number of arguments for unionvtab");
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
int nAlloc = 0; /* Allocated size of pTab->aSrc[] */
|
||||
@@ -705,60 +464,30 @@ static int unionConnect(
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pSrc = &pTab->aSrc[pTab->nSrc++];
|
||||
pSrc->zTab = unionStrdup(&rc, zTab);
|
||||
pSrc->iMin = iMin;
|
||||
pSrc->iMax = iMax;
|
||||
if( bSwarm ){
|
||||
pSrc->zFile = unionStrdup(&rc, zDb);
|
||||
}else{
|
||||
pSrc->zDb = unionStrdup(&rc, zDb);
|
||||
}
|
||||
}
|
||||
pSrc = &pTab->aSrc[pTab->nSrc++];
|
||||
pSrc->zDb = unionStrdup(&rc, zDb);
|
||||
pSrc->zTab = unionStrdup(&rc, zTab);
|
||||
pSrc->iMin = iMin;
|
||||
pSrc->iMax = iMax;
|
||||
}
|
||||
unionFinalize(&rc, pStmt, pzErr);
|
||||
unionFinalize(&rc, pStmt);
|
||||
pStmt = 0;
|
||||
|
||||
/* Capture the not-found callback UDF name */
|
||||
if( rc==SQLITE_OK && argc>=5 ){
|
||||
pTab->zNotFoundCallback = unionStrdup(&rc, argv[4]);
|
||||
unionDequote(pTab->zNotFoundCallback);
|
||||
}
|
||||
|
||||
/* It is an error if the SELECT statement returned zero rows. If only
|
||||
** because there is no way to determine the schema of the virtual
|
||||
** table in this case. */
|
||||
if( rc==SQLITE_OK && pTab->nSrc==0 ){
|
||||
*pzErr = sqlite3_mprintf("no source tables configured");
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* For unionvtab, verify that all source tables exist and have
|
||||
** compatible schemas. For swarmvtab, attach the first database and
|
||||
** check that the first table is a rowid table only. */
|
||||
/* Verify that all source tables exist and have compatible schemas. */
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab->db = db;
|
||||
pTab->bSwarm = bSwarm;
|
||||
pTab->nMaxOpen = SWARMVTAB_MAX_OPEN;
|
||||
if( bSwarm ){
|
||||
rc = unionOpenDatabase(pTab, 0, pzErr);
|
||||
}else{
|
||||
rc = unionSourceCheck(pTab, pzErr);
|
||||
}
|
||||
rc = unionSourceCheck(pTab, pzErr);
|
||||
}
|
||||
|
||||
/* Compose a CREATE TABLE statement and pass it to declare_vtab() */
|
||||
if( rc==SQLITE_OK ){
|
||||
UnionSrc *pSrc = &pTab->aSrc[0];
|
||||
sqlite3 *tdb = unionGetDb(pTab, pSrc);
|
||||
pStmt = unionPreparePrintf(&rc, pzErr, tdb, "SELECT "
|
||||
pStmt = unionPreparePrintf(&rc, pzErr, db, "SELECT "
|
||||
"'CREATE TABLE xyz('"
|
||||
" || group_concat(quote(name) || ' ' || type, ', ')"
|
||||
" || ')',"
|
||||
"max((cid+1) * (type='INTEGER' COLLATE nocase AND pk=1))-1 "
|
||||
"FROM pragma_table_info(%Q, ?)",
|
||||
pSrc->zTab, pSrc->zDb
|
||||
pTab->aSrc[0].zTab, pTab->aSrc[0].zDb
|
||||
);
|
||||
}
|
||||
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
@@ -767,7 +496,7 @@ static int unionConnect(
|
||||
pTab->iPK = sqlite3_column_int(pStmt, 1);
|
||||
}
|
||||
|
||||
unionFinalize(&rc, pStmt, pzErr);
|
||||
unionFinalize(&rc, pStmt);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -779,6 +508,7 @@ static int unionConnect(
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** xOpen
|
||||
*/
|
||||
@@ -796,56 +526,25 @@ static int unionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
*/
|
||||
static int unionClose(sqlite3_vtab_cursor *cur){
|
||||
UnionCsr *pCsr = (UnionCsr*)cur;
|
||||
unionFinalizeCsrStmt(pCsr);
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
sqlite3_free(pCsr);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function does the work of the xNext() method. Except that, if it
|
||||
** returns SQLITE_ROW, it should be called again within the same xNext()
|
||||
** method call. See unionNext() for details.
|
||||
*/
|
||||
static int doUnionNext(UnionCsr *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
assert( pCsr->pStmt );
|
||||
if( sqlite3_step(pCsr->pStmt)!=SQLITE_ROW ){
|
||||
UnionTab *pTab = (UnionTab*)pCsr->base.pVtab;
|
||||
rc = unionFinalizeCsrStmt(pCsr);
|
||||
if( rc==SQLITE_OK && pTab->bSwarm ){
|
||||
pCsr->iTab++;
|
||||
if( pCsr->iTab<pTab->nSrc ){
|
||||
UnionSrc *pSrc = &pTab->aSrc[pCsr->iTab];
|
||||
if( pCsr->iMaxRowid>=pSrc->iMin ){
|
||||
/* It is necessary to scan the next table. */
|
||||
rc = unionOpenDatabase(pTab, pCsr->iTab, &pTab->base.zErrMsg);
|
||||
pCsr->pStmt = unionPreparePrintf(&rc, &pTab->base.zErrMsg, pSrc->db,
|
||||
"SELECT rowid, * FROM %Q %s %lld",
|
||||
pSrc->zTab,
|
||||
(pSrc->iMax>pCsr->iMaxRowid ? "WHERE _rowid_ <=" : "-- "),
|
||||
pCsr->iMaxRowid
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pCsr->pStmt );
|
||||
unionIncrRefcount(pTab, pCsr->iTab);
|
||||
rc = SQLITE_ROW;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** xNext
|
||||
*/
|
||||
static int unionNext(sqlite3_vtab_cursor *cur){
|
||||
UnionCsr *pCsr = (UnionCsr*)cur;
|
||||
int rc;
|
||||
do {
|
||||
rc = doUnionNext((UnionCsr*)cur);
|
||||
}while( rc==SQLITE_ROW );
|
||||
assert( pCsr->pStmt );
|
||||
if( sqlite3_step(pCsr->pStmt)!=SQLITE_ROW ){
|
||||
rc = sqlite3_finalize(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -938,7 +637,8 @@ static int unionFilter(
|
||||
}
|
||||
}
|
||||
|
||||
unionFinalizeCsrStmt(pCsr);
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
if( bZero ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -974,25 +674,12 @@ static int unionFilter(
|
||||
zSql = sqlite3_mprintf("%z %s rowid<=%lld", zSql, zWhere, iMax);
|
||||
}
|
||||
}
|
||||
|
||||
if( pTab->bSwarm ){
|
||||
pCsr->iTab = i;
|
||||
pCsr->iMaxRowid = iMax;
|
||||
rc = unionOpenDatabase(pTab, i, &pTab->base.zErrMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( zSql==0 ){
|
||||
return rc;
|
||||
}else{
|
||||
sqlite3 *db = unionGetDb(pTab, &pTab->aSrc[pCsr->iTab]);
|
||||
pCsr->pStmt = unionPrepare(&rc, db, zSql, &pTab->base.zErrMsg);
|
||||
if( pCsr->pStmt ){
|
||||
unionIncrRefcount(pTab, pCsr->iTab);
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
if( zSql==0 ) return rc;
|
||||
pCsr->pStmt = unionPrepare(&rc, pTab->db, zSql, &pTab->base.zErrMsg);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
return unionNext(pVtabCursor);
|
||||
}
|
||||
@@ -1104,13 +791,8 @@ static int createUnionVtab(sqlite3 *db){
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_create_module(db, "unionvtab", &unionModule, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_module(db, "swarmvtab", &unionModule, (void*)db);
|
||||
}
|
||||
return rc;
|
||||
return sqlite3_create_module(db, "unionvtab", &unionModule, 0);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ ifcapable fts3 {
|
||||
INSERT INTO data_xt VALUES('a', 'b', 1, 0);
|
||||
}
|
||||
} msg] $msg
|
||||
} {1 {SQLITE_ERROR - SQL logic error}}
|
||||
} {1 {SQLITE_ERROR - SQL logic error or missing database}}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -125,7 +125,7 @@ foreach {tn2 setup sql expect} {
|
||||
{1 SQLITE_IOERR_WRITE}
|
||||
{1 SQLITE_IOERR_READ}
|
||||
{1 SQLITE_IOERR_FSYNC}
|
||||
{1 {SQLITE_ERROR - SQL logic error}}
|
||||
{1 {SQLITE_ERROR - SQL logic error or missing database}}
|
||||
{1 {SQLITE_ERROR - unable to open database: rbu.db}}
|
||||
{1 {SQLITE_IOERR - unable to open database: rbu.db}}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ foreach {fault errlist} {
|
||||
{1 SQLITE_IOERR_READ}
|
||||
{1 {SQLITE_IOERR - unable to open database: test.db2}}
|
||||
{1 {SQLITE_ERROR - unable to open database: test.db2}}
|
||||
{1 {SQLITE_ERROR - SQL logic error}}
|
||||
{1 {SQLITE_ERROR - SQL logic error or missing database}}
|
||||
}
|
||||
|
||||
cantopen* {
|
||||
|
||||
+2
-2
@@ -119,14 +119,14 @@ do_test 3.2 {
|
||||
CREATE TABLE data_ft(x, rbu_rowid, rbu_control);
|
||||
INSERT INTO data_ft VALUES(NULL, 2, 1);
|
||||
} } msg] $msg]
|
||||
} {1 {SQLITE_ERROR - SQL logic error]}}
|
||||
} {1 {SQLITE_ERROR - SQL logic error or missing database]}}
|
||||
|
||||
do_test 3.3 {
|
||||
list [catch { apply_rbu_update test.db {
|
||||
CREATE TABLE data_ft(x, rbu_rowid, rbu_control);
|
||||
INSERT INTO data_ft VALUES('7 8 9', 1, 'x');
|
||||
} } msg] $msg]
|
||||
} {1 {SQLITE_ERROR - SQL logic error]}}
|
||||
} {1 {SQLITE_ERROR - SQL logic error or missing database]}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4610,9 +4610,7 @@ static int rbuVfsAccess(
|
||||
if( *pResOut ){
|
||||
rc = SQLITE_CANTOPEN;
|
||||
}else{
|
||||
sqlite3_int64 sz = 0;
|
||||
rc = rbuVfsFileSize(&pDb->base, &sz);
|
||||
*pResOut = (sz>0);
|
||||
*pResOut = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -308,7 +308,7 @@ typedef struct sqlite3rbu sqlite3rbu;
|
||||
** not work out of the box with zipvfs. Refer to the comment describing
|
||||
** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
|
||||
*/
|
||||
SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
||||
sqlite3rbu *sqlite3rbu_open(
|
||||
const char *zTarget,
|
||||
const char *zRbu,
|
||||
const char *zState
|
||||
@@ -347,7 +347,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
||||
** a description of the complications associated with using RBU with
|
||||
** zipvfs databases.
|
||||
*/
|
||||
SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
|
||||
sqlite3rbu *sqlite3rbu_vacuum(
|
||||
const char *zTarget,
|
||||
const char *zState
|
||||
);
|
||||
@@ -383,7 +383,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
|
||||
** Database handles returned by this function remain valid until the next
|
||||
** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
|
||||
*/
|
||||
SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
|
||||
sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
|
||||
|
||||
/*
|
||||
** Do some work towards applying the RBU update to the target db.
|
||||
@@ -397,7 +397,7 @@ SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
|
||||
** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
|
||||
** that immediately return the same value.
|
||||
*/
|
||||
SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
|
||||
int sqlite3rbu_step(sqlite3rbu *pRbu);
|
||||
|
||||
/*
|
||||
** Force RBU to save its state to disk.
|
||||
@@ -409,7 +409,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
*/
|
||||
SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
|
||||
int sqlite3rbu_savestate(sqlite3rbu *pRbu);
|
||||
|
||||
/*
|
||||
** Close an RBU handle.
|
||||
@@ -429,14 +429,14 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
|
||||
** update has been partially applied, or SQLITE_DONE if it has been
|
||||
** completely applied.
|
||||
*/
|
||||
SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
|
||||
int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
|
||||
|
||||
/*
|
||||
** Return the total number of key-value operations (inserts, deletes or
|
||||
** updates) that have been performed on the target database since the
|
||||
** current RBU update was started.
|
||||
*/
|
||||
SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
||||
sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
||||
|
||||
/*
|
||||
** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
|
||||
@@ -478,7 +478,7 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
||||
** table exists but is not correctly populated, the value of the *pnOne
|
||||
** output variable during stage 1 is undefined.
|
||||
*/
|
||||
SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
|
||||
void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
|
||||
|
||||
/*
|
||||
** Obtain an indication as to the current stage of an RBU update or vacuum.
|
||||
@@ -516,7 +516,7 @@ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
|
||||
#define SQLITE_RBU_STATE_DONE 4
|
||||
#define SQLITE_RBU_STATE_ERROR 5
|
||||
|
||||
SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
|
||||
int sqlite3rbu_state(sqlite3rbu *pRbu);
|
||||
|
||||
/*
|
||||
** Create an RBU VFS named zName that accesses the underlying file-system
|
||||
@@ -560,7 +560,7 @@ SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
|
||||
** file-system via "rbu" all the time, even if it only uses RBU functionality
|
||||
** occasionally.
|
||||
*/
|
||||
SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
|
||||
int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
|
||||
|
||||
/*
|
||||
** Deregister and destroy an RBU vfs created by an earlier call to
|
||||
@@ -570,7 +570,7 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
|
||||
** before all database handles that use it have been closed, the results
|
||||
** are undefined.
|
||||
*/
|
||||
SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
|
||||
void sqlite3rbu_destroy_vfs(const char *zName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C On\sWindows,\savoid\scasting\sa\svalue\slarger\sthan\s2^31\sto\sa\s(SIZE_T)\son\ssystems\swhere\sit\sis\sa\s32-bit\stype.
|
||||
D 2017-08-07T19:06:54.041
|
||||
C Use\sthe\ssubquery\scolumn\sname,\snot\sthe\soriginal\sSQL\sstatement\stext,\sas\sthe\nadded\sAS\sclause\sin\sthe\squery\sflattener.
|
||||
D 2017-07-29T14:56:53.996
|
||||
F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
|
||||
@@ -11,7 +11,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
|
||||
F autoconf/Makefile.msc b77aec100e4fb4739748a2461b5aa82c179fcde35bc0e08ce52ae7322d218701
|
||||
F autoconf/Makefile.msc 1014be616b420a5f48611d21b62ca2f50ec97ee795087ecb8a4d6bf6375ba11d
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578
|
||||
@@ -281,14 +281,14 @@ F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c a4723b6aff748a417b5091b68a46443265c40f0d
|
||||
F ext/misc/stmt.c 6f16443abb3551e3f5813bb13ba19a30e7032830015b0f92fe0c0453045c0a11
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/unionvtab.c 1e0ebc5078e1a916db191bcd88f87e94ea7ba4aa563ee30ff706261cb4b39461
|
||||
F ext/misc/unionvtab.c 56fd163d2b6d2f4df0078be482fc9a874658ce51cce33f180c08834193449c78
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
|
||||
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
|
||||
F ext/rbu/rbu10.test 1846519a438697f45e9dcb246908af81b551c29e1078d0304fae83f1fed7e9ee
|
||||
F ext/rbu/rbu10.test 046b0980041d30700464a800bbf6733ed2df515d
|
||||
F ext/rbu/rbu11.test 9bc68c2d3dbeb1720153626e3bd0466dcc017702
|
||||
F ext/rbu/rbu12.test bde22ed0004dd5d1888c72a84ae407e574aeae16
|
||||
F ext/rbu/rbu13.test 462ff799c4afedc3ef8a47ff818c0ffbf14ae4f2
|
||||
@@ -307,18 +307,18 @@ F ext/rbu/rbucrash.test 61470d977a06a0abc2ec35b05d82a1d7d87d10f4ffabad14c1c231ed
|
||||
F ext/rbu/rbucrash2.test b2ecbdd7bb72c88bd217c65bd00dafa07f7f2d4d
|
||||
F ext/rbu/rbudiff.test 3e605cf624d00d04d0fb1316a3acec4fbe3b3ac5
|
||||
F ext/rbu/rbudor.test 99b05cc0df613e962c2c8085cfb05686a09cf315
|
||||
F ext/rbu/rbufault.test 2654aef20f8ee7de37c9c1997a44f2773dc7bf24887adea39fb19314ef32cb90
|
||||
F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
|
||||
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
|
||||
F ext/rbu/rbufault3.test 0913c1aeaee266d9c36c33179341a5a504aad7d423d1979cfec43c8346a29899
|
||||
F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
|
||||
F ext/rbu/rbufault4.test 34e70701cbec51571ffbd9fbf9d4e0f2ec495ca7
|
||||
F ext/rbu/rbufts.test a2bbd202c9321fba15fb4a62a90add7d70e07bd8404e1e598135adbfff8a0508
|
||||
F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
|
||||
F ext/rbu/rbuprogress.test 1849d4e0e50616edf5ce75ce7db86622e656b5cf
|
||||
F ext/rbu/rburesume.test 8acb77f4a422ff55acfcfc9cc15a5cb210b1de83
|
||||
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
|
||||
F ext/rbu/rbuvacuum.test ff357e9b556ca7ad4673da0ff7f244def919ff858e0f9f350d3e30fdd83a62a8
|
||||
F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
|
||||
F ext/rbu/sqlite3rbu.c 920941a6ff7dbbea0970717c43662878fda5c37e43752de329f0fdd76680ab75
|
||||
F ext/rbu/sqlite3rbu.h 82c102e5ae41025e3b245d3d5944315f82811da85e2cd363a75caa97cbd0cd3e
|
||||
F ext/rbu/sqlite3rbu.c d1438580a451eebda3bfd42ef69b677512f00125285e0e4e789b6131a45f6dd8
|
||||
F ext/rbu/sqlite3rbu.h fc25e1fcd99b5c6d32b1b5b1c73122632e873ac89bd0be9bf646db362b7ce02c
|
||||
F ext/rbu/test_rbu.c ec18cfc69a104309df23c359e3c80306c9a6bdd1d2c53c8b70ae158e9832dcd6
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 4f1804b80ae06ddf7ff69192aacdceee283646dc6a328acb951f116147445212
|
||||
@@ -390,18 +390,18 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c cf7a8af45cb0ace672f47a1b29ab24092a9e8cd8d945a9974e3b5d925f548594
|
||||
F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
|
||||
F src/attach.c 07b706e336fd3cedbd855e1f8266d10e82fecae07daf86717b5760cd7784c584
|
||||
F src/attach.c 3bd555e28382603e80d430dfebb2270f86e1e375b4c4be3e1ab1aec3a0c44943
|
||||
F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 1a17ba1a765d80c3ca39ce33ff55f92e1f51eb84bbbdab5377f11d36b1515fa1
|
||||
F src/btree.c f55ea8f456d103328d61076be40fa39acbfea05eaa4eccfed275532a63c867c4
|
||||
F src/btree.h 3edc5329bc59534d2d15b4f069a9f54b779a7e51289e98fa481ae3c0e526a5ca
|
||||
F src/btreeInt.h 97700795edf8a43245720414798b7b29d8e465aef46bf301ffacd431910c0da1
|
||||
F src/build.c 33b0f6055bd990ed052b96e71368acefcd98daa21ccf21f91aa90e8b769c2219
|
||||
F src/build.c 66f3ae9eacddd19caa09c64fdce825e652f007d1b3d632bc231954fb7942b867
|
||||
F src/callback.c 930648a084a3adc741c6471adfbdc50ba47ba3542421cb80a26f259f467de65e
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||
F src/ctime.c 928954802b1397d9fb1378c7eb702c94b4735bbab1d5793e21b6a77734f56a1b
|
||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||
F src/delete.c 939bd15e6b54b82b951e1c0ffc2ff2b4ab579196780a1f6d394e47bd6f799b6c
|
||||
@@ -414,7 +414,7 @@ F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c d2d1bf12d2b5382450620d7cede84c7ffe57e6a89fa9a908f1aba68df2731cd9
|
||||
F src/insert.c b88a58ff7eb99365b3ff163a5771c7e5db09f43997a8c5303588056ab33bc4eb
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
||||
F src/main.c 42f6a2660c7a1d643cc7e863d2dcd630c6aa1e8343f5478b0592120ab84c97ba
|
||||
@@ -424,7 +424,7 @@ F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memjournal.c 6f3d36a0a8f72f48f6c3c722f04301ac64f2515435fa42924293e46fc7994661
|
||||
F src/memjournal.c 95752936c11dc6995672d1dd783cd633eea0cc95
|
||||
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
|
||||
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
@@ -436,39 +436,39 @@ F src/os.c add02933b1dce7a39a005b00a2f5364b763e9a24
|
||||
F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c a361273749229755f92c8f0e3e4855054ad39bbc5c65773e8db5d0b79afa632c
|
||||
F src/os_win.c 964165b66cde03abc72fe948198b01be608436894732eadb94c8720d2467f223
|
||||
F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
|
||||
F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 1e63b0299cf123cf38c48413ec03190f56c1e7d0ccc6573c467d8ac240b898e9
|
||||
F src/pager.c 14f6982c470c05b8e85575c69e9c1712010602e20400f8670d8699e21283e0e4
|
||||
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
|
||||
F src/parse.y 52ef3cecd0934e9da4a45b585883a03243ad615d338ad94f44501a05891dcdfa
|
||||
F src/parse.y e384cb73f99e1b074085c974b37f4d830e885359e4b60837e30f7d67c16ba65b
|
||||
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
|
||||
F src/pcache.h 521bb9610d38ef17a3cc9b5ddafd4546c2ea67fa3d0e464823d73c2a28d50e11
|
||||
F src/pcache1.c 0b793738b5dddaf0a645784835c6b5557b1ecfaee339af9c26810c6ecdb273aa
|
||||
F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc
|
||||
F src/pragma.c cd6aeda3587be6c5c08f9b2d45eae6068666a03c9d077c8c43cdb85fb0aa70f2
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c 3cbb99757d7295997674972f9dd2331c5c544368854ca08954c9beb1e9b6145a
|
||||
F src/prepare.c 1eaeccc1f9dd5b2806408e530c0f05a1972272b66d827d0a7fdc2b192b357ead
|
||||
F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 3fd19c98c5223d411b883502d1ac928ddb762a1ea8f031d910210316545fc67c
|
||||
F src/select.c ef0be59b8394507c139678a8b6f1c9e8ea028b12200b5e38bc0992560341a035
|
||||
F src/shell.c bd6a37cbe8bf64ef6a6a74fdc50f067d3148149b4ce2b4d03154663e66ded55f
|
||||
F src/shell.c.in b5725acacba95ccefa57b6d068f710e29ba8239c3aa704628a1902a1f729c175
|
||||
F src/sqlite.h.in 72f1775c7a134f9e358eedafe1ebc703c28b0d705d976464ddbf6a9219448952
|
||||
F src/sqlite.h.in 0e2603c23f0747c5660669f946e231730af000c76d1653b153dcf2c26fce0a6b
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 0f9f72b86a3792314f5db7a1dfbc2c82376bcd8d0919ceb80637bca126ec3c68
|
||||
F src/sqliteInt.h 07e4d3c8021aea80e3bbafab4dd52833cfcfa4f000210af0d15c7fdaed2f09fc
|
||||
F src/sqliteInt.h a1b8df420e8fa80fda9414ab7784d6e62271e1f7d65034ffd3e906ee6f014def
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 487951d81f9704800fd9f0ffdaa2f935a83ccb6be3575c2c4ef83e4789b4c828
|
||||
F src/test1.c 8513b17ca4a7a9ba28748535d178b6e472ec7394ae0eea53907f2d3bcdbab2df
|
||||
F src/tclsqlite.c 2c29b0b76e91edfd1b43bf135c32c8674710089197327682b6b7e6af88062c3d
|
||||
F src/test1.c cfb78b728b37ae3a2b14fe1b3a6c766e0da41370eda112594e698c94011b622e
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
|
||||
F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
|
||||
F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
|
||||
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
|
||||
F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
|
||||
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
|
||||
@@ -481,7 +481,7 @@ F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c abf6fc1fe9d041b699578c42e3db81f8831c4f5b804f1927958102ee8f2b773e
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
|
||||
F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
|
||||
F src/test_fs.c 35a2f7dd8a915900873386331386d9ba1ae1b5026d74fd20c2807bc76221f291
|
||||
F src/test_func.c a4fdab3363b436c1b12660e9362ce3f3782b7b5e
|
||||
F src/test_hexio.c 1d4469ca61ab202a1fcec6543f584d2407205e8d
|
||||
@@ -520,16 +520,16 @@ F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
|
||||
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
|
||||
F src/vdbe.c 821b3edde2d17ec60da0617db1018a88f38634c359d22f3c8f7be10336c82636
|
||||
F src/vdbe.c ac9cc205741b295d5b77917cfd2a45632de3cd5563e143e74dce1ede42e4b68c
|
||||
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
|
||||
F src/vdbeInt.h ff2b7db0968d20e6184aee256d2e535d565f5a172e3588a78adb166a41fc4911
|
||||
F src/vdbeapi.c 05d6b14ab73952db0d73f6452d6960216997bd966a710266b2fe051f25326abc
|
||||
F src/vdbeaux.c 1bef372f59f9e1dba5ead70cc5c24bf978bab0b9fdc2f69692afaa3a2d4dd8f3
|
||||
F src/vdbeblob.c db3cf91060f6f4b2f1358a4200e844697990752177784c7c95da00b7ac9f1c7b
|
||||
F src/vdbemem.c b7fac20534c79b7554dab2e8a180c585a8bc1b9c85149d1b2d9746cf314d06ed
|
||||
F src/vdbesort.c fea2bea25f5e9ccd91e0760d7359f0365f9fba1aaeac7216c71cad78765f58e3
|
||||
F src/vdbeapi.c 0823531191f9d5588a245ed5b39306798681814e9e8099d54a3213a13a28fbe7
|
||||
F src/vdbeaux.c 3fe68bad02b33b09e08bdc0ad90d6b92b3d571f7864c3d047abca1bde050751c
|
||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||
F src/vdbemem.c 9ca2854976f35db40341977e688a08204c96427505f5b90215dc7970f6ea42c4
|
||||
F src/vdbesort.c f512c68d0bf7e0105316a5594c4329358c8ee9cae3b25138df041d97516c0372
|
||||
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
|
||||
F src/vtab.c a305582d3a6c7090982ac1610b8e5724fa954d8b28899fa6c633cb4de9c2f8ee
|
||||
F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
|
||||
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
@@ -572,9 +572,8 @@ F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
|
||||
F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
|
||||
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
|
||||
F test/attach.test f4b8918ba2f3e88e6883b8452340545f10a1388af808343c37fc5c577be8281c
|
||||
F test/attach2.test 567047a7607aae8ebb3794642ebb168abe66b4af366fcd0cf7f616a1495cd43f
|
||||
F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
@@ -608,7 +607,6 @@ F test/bestindex4.test 4cb5ff7dbaebadb87d366f51969271778423b455
|
||||
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
|
||||
F test/bigmmap.test ed6058a7794be26865c94d5bb62e12cdc4f7f01562b3b04f13eb3cdc52783921
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
F test/bigsort.test 8299fa9298f4f1e02fc7d2712e8b77d6cd60e5a2
|
||||
F test/bind.test 1e136709b306f7ed3192d349c2930d89df6ab621654ad6f1a72381d3fe76f483
|
||||
@@ -654,7 +652,7 @@ F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
|
||||
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95
|
||||
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
||||
F test/colname.test b111edd2a84f558567320904bb94c779d7eec47254265b5f0a3d1f3e52cc28e0
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
||||
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
|
||||
F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9
|
||||
@@ -756,7 +754,7 @@ F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/expr.test 66a2c9ac34f74f036faa4092f5402c7d3162fc93
|
||||
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
|
||||
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
|
||||
F test/fallocate.test 87b5e43c872b7e69cd80b7b8813eb102b571a75d45dda24e38b65537bcc85733
|
||||
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
|
||||
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
|
||||
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
|
||||
F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4
|
||||
@@ -1031,7 +1029,7 @@ F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
|
||||
F test/misc1.test 51ec3f56a2a7965de226964cff856695e743186826561536647f1e8b7d1d0eb3
|
||||
F test/misc1.test 6430dabfb4b4fa480633590118964201f94d3ccc
|
||||
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
|
||||
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
|
||||
F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3
|
||||
@@ -1073,7 +1071,7 @@ F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
|
||||
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
|
||||
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
|
||||
F test/ossfuzz.c 7f5cc87a0280a5854c1bfa7d5c4d07d34731f08ec34dc9c916aa35ed292b1468
|
||||
F test/ossfuzz.c f5abed3177f719df3c3109901fcdd26b9fb7f581c8da50fc26f3a81ddfb2c2ae
|
||||
F test/ossshell.c 296ab63067841bd1b1e97b46a0b2af48ee7f69d50d1a723008bee12dd7122622
|
||||
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
|
||||
F test/pager1.test 8149b2a8986fee667ab6a8171ab310be19e77ae215bebad0e90c857b0df1935c
|
||||
@@ -1089,7 +1087,7 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 3b94f8fd431d39fac4952eb5dc38e1bb2b4518e1ac967d66f5abc815c104aeb6
|
||||
F test/permutations.test 5e2e5439642898e0947ced066ad09b82bd817ddfb83dc71291b4c957efc84b62
|
||||
F test/pragma.test f274259d6393b6681eb433beb8dd39a26ec06a4431052a4880b43b84912a3f58
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
@@ -1115,7 +1113,7 @@ F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl 7bb585433ce7fb2a2c255ae4b5e24f1bc27fe177ec1120f886cc4852f48f5ee9 x
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test f580934279800d480a19176c6b44909df31ce7ad45267ea475a541daa522f3d3
|
||||
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
|
||||
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
|
||||
@@ -1133,7 +1131,7 @@ F test/rowvalue9.test d8dd2c6ecac432dadaa79e41dc2434f007be1b6b
|
||||
F test/rowvaluefault.test 7cd9ccc6c2fbdd881672984087aad0491bb75504
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/savepoint.test 1f8a6b1aea9a0d05837adc463d4bf47bd9d0f1c842f1c2a9caccd639baf34bf9
|
||||
F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
@@ -1146,7 +1144,6 @@ F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9
|
||||
F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
|
||||
F test/schema6.test 5b21bbdd405bc93b3e6af5e6ece64d230e35f65cc4035e5c2b89fc8a090d7270
|
||||
F test/securedel.test 5f997cb6bd38727b81e0985f53ec386c99db6441b2b9e6357240649d29017239
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686
|
||||
@@ -1232,13 +1229,10 @@ F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
|
||||
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
|
||||
F test/swarmvtab.test 05c4ca7b6ab0cc6f4c335a510347f99d741fa71366004699cf7dfa3cff4e2d17
|
||||
F test/swarmvtab2.test 038ef9bcad6fd2fb9e395196080cf23e223ddb1219015049a61540c161bc577d
|
||||
F test/swarmvtabfault.test 73563eefe3073c6fb3bb14475fb4ef5d4f2e3a67a02947ee0ca08980ea3dd7fe
|
||||
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
|
||||
F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
|
||||
F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
|
||||
F test/syscall.test 7a60601770172a8014a4d222d5f3d95a5d2b5c47fbb0374e2698e89c99e37256
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test c47171c36b3d411df2bd49719dcaa5d034f8d277477fd41d253940723b969a51
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
@@ -1252,7 +1246,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl eb7ec55fe074a909423c1de701f7c545417b8aa96787b8c3e7a79203f2cebec8
|
||||
F test/tester.tcl 581f0185434daf7026ccede4c07e8d1479186ec5
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1440,7 +1434,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unionvtab.test 595fb601de00188ca5e7c6dbe266c17a0faf234cf434ce85eccec1a929ef9baf
|
||||
F test/unionvtabfault.test 26b6854d5aef9005cd630513025690bff1b7378ae9c97b81e2a3cbe84eee0f58
|
||||
F test/unionvtabfault.test 18f4f878e550ae3c5efa195b1420c78607c0f9810f7a71a49ab6379dfe501f32
|
||||
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
|
||||
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
|
||||
@@ -1519,7 +1513,7 @@ F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test f520bcec2c3d12dc4615623b06b2aec7c2d67e94
|
||||
F test/where8.test 98eedca0d375fb400b8377269c4b4686582dfb45
|
||||
F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2
|
||||
F test/whereA.test 6c6a420ca7d313242f9b1bd471dc80e4d0f8323700ba9c78df0bb843d4daa3b4
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
|
||||
F test/whereD.test 711d4df58d6d4fb9b3f5ce040b818564198be002
|
||||
@@ -1541,20 +1535,19 @@ F test/with1.test 732e3ef398dcecb609839cd5ef0cb63beb2a9eff31420f3b745fc55b9e85b6
|
||||
F test/with2.test 2b40da883658eb74ad8ad06afabe11a408e7fb87
|
||||
F test/with3.test e71604a0e53cba82bc04c703987cb1d6751ec0b6
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test 06b7215130882d6a072233820dd364c874c4fd69221e8fc756ec471009192874
|
||||
F test/without_rowid1.test 1a7b9bd51b899928d327052df9741d2fe8dbe701
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test 2724c787a51a5dce09d078453a758117b4b728f1
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
|
||||
F test/without_rowid6.test 1f99644e6508447fb050f73697350c7ceca3392e
|
||||
F test/wordcount.c 06efb84b7c48a4973c2c24ea06c93d00bce24389
|
||||
F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc
|
||||
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
|
||||
F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
|
||||
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat 8995df40c4209808b31f24de0b58f90930239a234f7591e3675d45bfbb990c5d
|
||||
F tool/GetTclKit.bat 3822c7651b18cda4cc50ebd5215c4d0efca1a480895f6a226b5a3ad81f5621e6
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
F tool/addopcodes.tcl 7181c041d495e3f26acc36d15c86923ed722285f9015f017f41a3efdb9a0dab4
|
||||
F tool/addopcodes.tcl edbd53806bf20e25af2373ad0c091be4385081c1aa1813b916bf093f94ed8380
|
||||
F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/cg_anno.tcl f95b0006c52cf7f0496b506343415b6ee3cdcdd3 x
|
||||
@@ -1568,7 +1561,7 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c e6056373044d55296d21f81467dba7632bbb81dc49af072b3f0e76338771497e
|
||||
F tool/lemon.c 5a04dff28578a67415cea5bf981b893c50cebfdd4388fb21254d1892525edfd8
|
||||
F tool/lempar.c 10579a61dc2290182725e7abdefe311dd8b521a8f7f0aabbfc571e9012a09eaf
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
@@ -1579,13 +1572,13 @@ F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9
|
||||
F tool/mkkeywordhash.c 2e852ac0dfdc5af18886dc1ce7e9676d11714ae3df0a282dc7d90b3a0fe2033c
|
||||
F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
|
||||
F tool/mkopcodeh.tcl bb04ab6e5e2000c91e0c69a597e7e36e002320d123e2e1944cb2819181b72ee9
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
|
||||
F tool/mkshellc.tcl 69c38ecd7b74b2b0799a35ce20e1e3998e504d8c99c100ca4b98ae9d8f6279bc
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
F tool/mksqlite3c.tcl a4b36eaa002ed00a0ab2c93d999a14f1acae98ff09a85382e5abc05a91edb82b
|
||||
F tool/mksqlite3c.tcl f6214285bec900d28441366ca31af327aade18bbc424b0480497966ec05bc43c
|
||||
F tool/mksqlite3h.tcl 51bd5e7e840a920388a5966c9f2ccc618f434c57bd68c1bab4085b2553e1e237
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||
@@ -1644,7 +1637,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 4249fcf7b0c0233f9b3ba5139702738d5221c5309240e6e91dc139eff59471fe
|
||||
R ada1495a3f5fb5efd255ea78a3bbd776
|
||||
U mistachkin
|
||||
Z fa32878e56ea1fef6300b9cb2bae7ccb
|
||||
P 439cc5c52cbe6e67bbf0b6de0610f7d95ca9eb994f032547dc3535fd2c9dfc78
|
||||
R 958b536ad819a7cfdc8789f87ebdcbab
|
||||
U drh
|
||||
Z 4ab6903a815161b50ba952b68c66e144
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
f08d63b413601b22726e8b96ff8eb779857321b9df30db0333f71e50ffb5077d
|
||||
5df7f0e6a1fbc770a68830ce88e78ecccbf023557ea446ce312ab53d5b32a6a9
|
||||
@@ -93,6 +93,10 @@ static void attachFunc(
|
||||
);
|
||||
goto attach_error;
|
||||
}
|
||||
if( !db->autoCommit ){
|
||||
zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
|
||||
goto attach_error;
|
||||
}
|
||||
for(i=0; i<db->nDb; i++){
|
||||
char *z = db->aDb[i].zDbSName;
|
||||
assert( z && zName );
|
||||
@@ -284,6 +288,11 @@ static void detachFunc(
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
if( !db->autoCommit ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr,
|
||||
"cannot DETACH database within transaction");
|
||||
goto detach_error;
|
||||
}
|
||||
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
|
||||
goto detach_error;
|
||||
|
||||
+17
-16
@@ -731,7 +731,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
testcase( p->iPage>=0 );
|
||||
testcase( p->iPage>0 );
|
||||
btreeReleaseAllCursorPages(p);
|
||||
}
|
||||
}
|
||||
@@ -3981,6 +3981,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
|
||||
if( pBtree ){
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
||||
int i;
|
||||
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
|
||||
if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
|
||||
rc = saveCursorPosition(p);
|
||||
@@ -3994,7 +3995,10 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
|
||||
p->eState = CURSOR_FAULT;
|
||||
p->skipNext = errCode;
|
||||
}
|
||||
btreeReleaseAllCursorPages(p);
|
||||
for(i=0; i<=p->iPage; i++){
|
||||
releasePage(p->apPage[i]);
|
||||
p->apPage[i] = 0;
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
@@ -4311,7 +4315,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
}while( ALWAYS(pPrev) );
|
||||
}
|
||||
for(i=0; i<=pCur->iPage; i++){
|
||||
releasePageNotNull(pCur->apPage[i]);
|
||||
releasePage(pCur->apPage[i]);
|
||||
}
|
||||
unlockBtreeIfUnused(pBt);
|
||||
sqlite3_free(pCur->aOverflow);
|
||||
@@ -4934,7 +4938,13 @@ static int moveToRoot(BtCursor *pCur){
|
||||
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
|
||||
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
|
||||
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
|
||||
assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
|
||||
if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
return pCur->skipNext;
|
||||
}
|
||||
sqlite3BtreeClearCursor(pCur);
|
||||
}
|
||||
|
||||
if( pCur->iPage>=0 ){
|
||||
if( pCur->iPage ){
|
||||
@@ -4949,13 +4959,6 @@ static int moveToRoot(BtCursor *pCur){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
assert( pCur->iPage==(-1) );
|
||||
if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
return pCur->skipNext;
|
||||
}
|
||||
sqlite3BtreeClearCursor(pCur);
|
||||
}
|
||||
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
|
||||
0, pCur->curPagerFlags);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -6117,7 +6120,7 @@ static int clearCell(
|
||||
unsigned char *pCell, /* First byte of the Cell */
|
||||
CellInfo *pInfo /* Size information about the cell */
|
||||
){
|
||||
BtShared *pBt;
|
||||
BtShared *pBt = pPage->pBt;
|
||||
Pgno ovflPgno;
|
||||
int rc;
|
||||
int nOvfl;
|
||||
@@ -6133,7 +6136,6 @@ static int clearCell(
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
}
|
||||
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
|
||||
pBt = pPage->pBt;
|
||||
assert( pBt->usableSize > 4 );
|
||||
ovflPageSize = pBt->usableSize - 4;
|
||||
nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
|
||||
@@ -8252,7 +8254,7 @@ int sqlite3BtreeInsert(
|
||||
pCur->apPage[pCur->iPage]->nOverflow = 0;
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
|
||||
btreeReleaseAllCursorPages(pCur);
|
||||
rc = moveToRoot(pCur);
|
||||
if( pCur->pKeyInfo ){
|
||||
assert( pCur->pKey==0 );
|
||||
pCur->pKey = sqlite3Malloc( pX->nKey );
|
||||
@@ -8266,7 +8268,7 @@ int sqlite3BtreeInsert(
|
||||
pCur->nKey = pX->nKey;
|
||||
}
|
||||
}
|
||||
assert( pCur->iPage<0 || pCur->apPage[pCur->iPage]->nOverflow==0 );
|
||||
assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
|
||||
|
||||
end_insert:
|
||||
return rc;
|
||||
@@ -8436,7 +8438,6 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
}else{
|
||||
rc = moveToRoot(pCur);
|
||||
if( bPreserve ){
|
||||
btreeReleaseAllCursorPages(pCur);
|
||||
pCur->eState = CURSOR_REQUIRESEEK;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -1681,7 +1681,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
|
||||
** schema to the rootpage from the main table.
|
||||
** (5) Add all table columns to the PRIMARY KEY Index object
|
||||
** so that the PRIMARY KEY is a covering index. The surplus
|
||||
** columns are part of KeyInfo.nAllField and are not used for
|
||||
** columns are part of KeyInfo.nXField and are not used for
|
||||
** sorting or lookup or uniqueness checks.
|
||||
** (6) Replace the rowid tail on all automatically generated UNIQUE
|
||||
** indices with the PRIMARY KEY columns.
|
||||
@@ -1739,6 +1739,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
}else{
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
|
||||
/* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
|
||||
** table entry. This is only required if currently generating VDBE
|
||||
** code for a CREATE TABLE (not when parsing one as part of reading
|
||||
** a database schema). */
|
||||
if( v ){
|
||||
assert( db->init.busy==0 );
|
||||
sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove all redundant columns from the PRIMARY KEY. For example, change
|
||||
** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
|
||||
@@ -1758,15 +1767,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
|
||||
nPk = pPk->nKeyCol;
|
||||
|
||||
/* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
|
||||
** table entry. This is only required if currently generating VDBE
|
||||
** code for a CREATE TABLE (not when parsing one as part of reading
|
||||
** a database schema). */
|
||||
if( v && pPk->tnum>0 ){
|
||||
assert( db->init.busy==0 );
|
||||
sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
|
||||
}
|
||||
|
||||
/* The root page of the PRIMARY KEY is the table root page */
|
||||
pPk->tnum = pTab->tnum;
|
||||
|
||||
@@ -2836,7 +2836,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
|
||||
@@ -184,9 +184,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_ENABLE_ATOMIC_WRITE
|
||||
"ENABLE_ATOMIC_WRITE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
"ENABLE_BATCH_ATOMIC_WRITE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_CEROD
|
||||
"ENABLE_CEROD",
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -2180,7 +2180,7 @@ static int xferOptimization(
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
if( db->mDbFlags & DBFLAG_Vacuum ){
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
|
||||
OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
|
||||
}else{
|
||||
@@ -2217,7 +2217,7 @@ static int xferOptimization(
|
||||
** collation sequence BINARY, then it can also be assumed that the
|
||||
** index will be populated by inserting keys in strictly sorted
|
||||
** order. In this case, instead of seeking within the b-tree as part
|
||||
** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
|
||||
** of every OP_IdxInsert opcode, an OP_Last is added before the
|
||||
** OP_IdxInsert to seek to the point within the b-tree where each key
|
||||
** should be inserted. This is faster.
|
||||
**
|
||||
@@ -2232,7 +2232,7 @@ static int xferOptimization(
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT;
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
||||
}
|
||||
}
|
||||
if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
|
||||
|
||||
+8
-24
@@ -96,8 +96,7 @@ static int memjrnlRead(
|
||||
int iChunkOffset;
|
||||
FileChunk *pChunk;
|
||||
|
||||
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
||||
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
if( (iAmt+iOfst)>p->endpoint.iOffset ){
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
@@ -216,8 +215,7 @@ static int memjrnlWrite(
|
||||
** atomic-write optimization. In this case the first 28 bytes of the
|
||||
** journal file may be written as part of committing the transaction. */
|
||||
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
|
||||
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
||||
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
if( iOfst==0 && p->pFirst ){
|
||||
assert( p->nChunkSize>iAmt );
|
||||
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
|
||||
@@ -386,31 +384,17 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
|
||||
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
||||
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
/*
|
||||
** If the argument p points to a MemJournal structure that is not an
|
||||
** in-memory-only journal file (i.e. is one that was opened with a +ve
|
||||
** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
|
||||
** file has not yet been created, create it now.
|
||||
** nSpill parameter), and the underlying file has not yet been created,
|
||||
** create it now.
|
||||
*/
|
||||
int sqlite3JournalCreate(sqlite3_file *pJfd){
|
||||
int sqlite3JournalCreate(sqlite3_file *p){
|
||||
int rc = SQLITE_OK;
|
||||
MemJournal *p = (MemJournal*)pJfd;
|
||||
if( p->pMethod==&MemJournalMethods && (
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
p->nSpill>0
|
||||
#else
|
||||
/* While this appears to not be possible without ATOMIC_WRITE, the
|
||||
** paths are complex, so it seems prudent to leave the test in as
|
||||
** a NEVER(), in case our analysis is subtly flawed. */
|
||||
NEVER(p->nSpill>0)
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
|| (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
|
||||
#endif
|
||||
)){
|
||||
rc = memjrnlCreateFile(p);
|
||||
if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
|
||||
rc = memjrnlCreateFile((MemJournal*)p);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+34
-92
@@ -90,7 +90,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
@@ -221,8 +220,10 @@ struct unixFile {
|
||||
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
|
||||
void *pMapRegion; /* Memory mapped region */
|
||||
#endif
|
||||
#ifdef __QNXNTO__
|
||||
int sectorSize; /* Device sector size */
|
||||
int deviceCharacteristics; /* Precomputed device characteristics */
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
int openFlags; /* The flags specified at open() */
|
||||
#endif
|
||||
@@ -327,20 +328,6 @@ static pid_t randomnessPid = 0;
|
||||
# define lseek lseek64
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
** Linux-specific IOCTL magic numbers used for controlling F2FS
|
||||
*/
|
||||
#define F2FS_IOCTL_MAGIC 0xf5
|
||||
#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
|
||||
#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
|
||||
#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
|
||||
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
|
||||
#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
|
||||
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
/*
|
||||
** Different Unix systems declare open() in different ways. Same use
|
||||
** open(const char*,int,mode_t). Others use open(const char*,int,...).
|
||||
@@ -513,9 +500,6 @@ static struct unix_syscall {
|
||||
#endif
|
||||
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
|
||||
|
||||
{ "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
|
||||
#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
|
||||
@@ -3793,21 +3777,6 @@ static int unixGetTempname(int nBuf, char *zBuf);
|
||||
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
switch( op ){
|
||||
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
|
||||
int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
|
||||
return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
|
||||
int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
|
||||
return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
|
||||
int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
|
||||
return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
|
||||
}
|
||||
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
|
||||
|
||||
case SQLITE_FCNTL_LOCKSTATE: {
|
||||
*(int*)pArg = pFile->eFileLock;
|
||||
return SQLITE_OK;
|
||||
@@ -3858,14 +3827,6 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
if( newLimit>sqlite3GlobalConfig.mxMmap ){
|
||||
newLimit = sqlite3GlobalConfig.mxMmap;
|
||||
}
|
||||
|
||||
/* The value of newLimit may be eventually cast to (size_t) and passed
|
||||
** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
|
||||
** 64-bit type. */
|
||||
if( newLimit>0 && sizeof(size_t)<8 ){
|
||||
newLimit = (newLimit & 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
*(i64*)pArg = pFile->mmapSizeMax;
|
||||
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
|
||||
pFile->mmapSizeMax = newLimit;
|
||||
@@ -3899,41 +3860,30 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
|
||||
/*
|
||||
** If pFd->sectorSize is non-zero when this function is called, it is a
|
||||
** no-op. Otherwise, the values of pFd->sectorSize and
|
||||
** pFd->deviceCharacteristics are set according to the file-system
|
||||
** characteristics.
|
||||
** Return the sector size in bytes of the underlying block device for
|
||||
** the specified file. This is almost always 512 bytes, but may be
|
||||
** larger for some devices.
|
||||
**
|
||||
** There are two versions of this function. One for QNX and one for all
|
||||
** other systems.
|
||||
** SQLite code assumes this function cannot fail. It also assumes that
|
||||
** if two files are created in the same file-system directory (i.e.
|
||||
** a database and its journal file) that the sector size will be the
|
||||
** same for both.
|
||||
*/
|
||||
#ifndef __QNXNTO__
|
||||
static void setDeviceCharacteristics(unixFile *pFd){
|
||||
assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
|
||||
if( pFd->sectorSize==0 ){
|
||||
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
int res;
|
||||
u32 f = 0;
|
||||
|
||||
/* Check for support for F2FS atomic batch writes. */
|
||||
res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
|
||||
if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
|
||||
pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
|
||||
}
|
||||
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
|
||||
|
||||
/* Set the POWERSAFE_OVERWRITE flag if requested. */
|
||||
if( pFd->ctrlFlags & UNIXFILE_PSOW ){
|
||||
pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
|
||||
}
|
||||
|
||||
pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
#ifndef __QNXNTO__
|
||||
static int unixSectorSize(sqlite3_file *NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following version of unixSectorSize() is optimized for QNX.
|
||||
*/
|
||||
#ifdef __QNXNTO__
|
||||
#include <sys/dcmd_blk.h>
|
||||
#include <sys/statvfs.h>
|
||||
static void setDeviceCharacteristics(unixFile *pFile){
|
||||
static int unixSectorSize(sqlite3_file *id){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
if( pFile->sectorSize == 0 ){
|
||||
struct statvfs fsInfo;
|
||||
|
||||
@@ -4002,24 +3952,9 @@ static void setDeviceCharacteristics(unixFile *pFile){
|
||||
pFile->deviceCharacteristics = 0;
|
||||
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
return pFile->sectorSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the sector size in bytes of the underlying block device for
|
||||
** the specified file. This is almost always 512 bytes, but may be
|
||||
** larger for some devices.
|
||||
**
|
||||
** SQLite code assumes this function cannot fail. It also assumes that
|
||||
** if two files are created in the same file-system directory (i.e.
|
||||
** a database and its journal file) that the sector size will be the
|
||||
** same for both.
|
||||
*/
|
||||
static int unixSectorSize(sqlite3_file *id){
|
||||
unixFile *pFd = (unixFile*)id;
|
||||
setDeviceCharacteristics(pFd);
|
||||
return pFd->sectorSize;
|
||||
}
|
||||
#endif /* __QNXNTO__ */
|
||||
|
||||
/*
|
||||
** Return the device characteristics for the file.
|
||||
@@ -4035,9 +3970,16 @@ static int unixSectorSize(sqlite3_file *id){
|
||||
** available to turn it off and URI query parameter available to turn it off.
|
||||
*/
|
||||
static int unixDeviceCharacteristics(sqlite3_file *id){
|
||||
unixFile *pFd = (unixFile*)id;
|
||||
setDeviceCharacteristics(pFd);
|
||||
return pFd->deviceCharacteristics;
|
||||
unixFile *p = (unixFile*)id;
|
||||
int rc = 0;
|
||||
#ifdef __QNXNTO__
|
||||
if( p->sectorSize==0 ) unixSectorSize(id);
|
||||
rc = p->deviceCharacteristics;
|
||||
#endif
|
||||
if( p->ctrlFlags & UNIXFILE_PSOW ){
|
||||
rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
||||
@@ -7656,7 +7598,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==29 );
|
||||
assert( ArraySize(aSyscall)==28 );
|
||||
|
||||
/* Register all VFSes defined in the aVfs[] array */
|
||||
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
|
||||
|
||||
@@ -3559,14 +3559,6 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
if( newLimit>sqlite3GlobalConfig.mxMmap ){
|
||||
newLimit = sqlite3GlobalConfig.mxMmap;
|
||||
}
|
||||
|
||||
/* The value of newLimit may be eventually cast to (SIZE_T) and passed
|
||||
** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
|
||||
** least a 64-bit type. */
|
||||
if( newLimit>0 && sizeof(SIZE_T)<8 ){
|
||||
newLimit = (newLimit & 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
*(i64*)pArg = pFile->mmapSizeMax;
|
||||
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
|
||||
pFile->mmapSizeMax = newLimit;
|
||||
|
||||
+46
-106
@@ -947,7 +947,6 @@ static int assert_pager_state(Pager *p){
|
||||
assert( isOpen(p->jfd)
|
||||
|| p->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| p->journalMode==PAGER_JOURNALMODE_WAL
|
||||
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
|
||||
);
|
||||
assert( pPager->dbOrigSize<=pPager->dbHintSize );
|
||||
break;
|
||||
@@ -959,7 +958,6 @@ static int assert_pager_state(Pager *p){
|
||||
assert( isOpen(p->jfd)
|
||||
|| p->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| p->journalMode==PAGER_JOURNALMODE_WAL
|
||||
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -1170,45 +1168,34 @@ static int pagerLockDb(Pager *pPager, int eLock){
|
||||
}
|
||||
|
||||
/*
|
||||
** This function determines whether or not the atomic-write or
|
||||
** atomic-batch-write optimizations can be used with this pager. The
|
||||
** atomic-write optimization can be used if:
|
||||
** This function determines whether or not the atomic-write optimization
|
||||
** can be used with this pager. The optimization can be used if:
|
||||
**
|
||||
** (a) the value returned by OsDeviceCharacteristics() indicates that
|
||||
** a database page may be written atomically, and
|
||||
** (b) the value returned by OsSectorSize() is less than or equal
|
||||
** to the page size.
|
||||
**
|
||||
** If it can be used, then the value returned is the size of the journal
|
||||
** file when it contains rollback data for exactly one page.
|
||||
** The optimization is also always enabled for temporary files. It is
|
||||
** an error to call this function if pPager is opened on an in-memory
|
||||
** database.
|
||||
**
|
||||
** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
|
||||
** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
|
||||
** returned in this case.
|
||||
**
|
||||
** If neither optimization can be used, 0 is returned.
|
||||
** If the optimization cannot be used, 0 is returned. If it can be used,
|
||||
** then the value returned is the size of the journal file when it
|
||||
** contains rollback data for exactly one page.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
static int jrnlBufferSize(Pager *pPager){
|
||||
assert( !MEMDB );
|
||||
if( !pPager->tempFile ){
|
||||
int dc; /* Device characteristics */
|
||||
int nSector; /* Sector size */
|
||||
int szPage; /* Page size */
|
||||
|
||||
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
||||
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
int dc; /* Device characteristics */
|
||||
|
||||
assert( isOpen(pPager->fd) );
|
||||
dc = sqlite3OsDeviceCharacteristics(pPager->fd);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
{
|
||||
int nSector = pPager->sectorSize;
|
||||
int szPage = pPager->pageSize;
|
||||
assert( isOpen(pPager->fd) );
|
||||
dc = sqlite3OsDeviceCharacteristics(pPager->fd);
|
||||
nSector = pPager->sectorSize;
|
||||
szPage = pPager->pageSize;
|
||||
|
||||
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
|
||||
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
|
||||
@@ -1218,10 +1205,10 @@ static int jrnlBufferSize(Pager *pPager){
|
||||
}
|
||||
|
||||
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# define jrnlBufferSize(x) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
|
||||
@@ -2025,9 +2012,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
||||
}
|
||||
|
||||
releaseAllSavepoints(pPager);
|
||||
assert( isOpen(pPager->jfd) || pPager->pInJournal==0
|
||||
|| (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
|
||||
);
|
||||
assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
|
||||
if( isOpen(pPager->jfd) ){
|
||||
assert( !pagerUseWal(pPager) );
|
||||
|
||||
@@ -4582,13 +4567,6 @@ static int pagerStress(void *p, PgHdr *pPg){
|
||||
rc = pagerWalFrames(pPager, pPg, 0, 0);
|
||||
}
|
||||
}else{
|
||||
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
if( pPager->tempFile==0 ){
|
||||
rc = sqlite3JournalCreate(pPager->jfd);
|
||||
if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sync the journal file if required. */
|
||||
if( pPg->flags&PGHDR_NEED_SYNC
|
||||
@@ -6369,21 +6347,6 @@ int sqlite3PagerCommitPhaseOne(
|
||||
sqlite3PcacheCleanAll(pPager->pPCache);
|
||||
}
|
||||
}else{
|
||||
/* The bBatch boolean is true if the batch-atomic-write commit method
|
||||
** should be used. No rollback journal is created if batch-atomic-write
|
||||
** is enabled.
|
||||
*/
|
||||
sqlite3_file *fd = pPager->fd;
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
|
||||
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
|
||||
&& !pPager->noSync
|
||||
&& sqlite3JournalIsInMemory(pPager->jfd);
|
||||
#else
|
||||
# define bBatch 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
/* The following block updates the change-counter. Exactly how it
|
||||
** does this depends on whether or not the atomic-update optimization
|
||||
** was enabled at compile time, and if this transaction meets the
|
||||
@@ -6407,40 +6370,33 @@ int sqlite3PagerCommitPhaseOne(
|
||||
** in 'direct' mode. In this case the journal file will never be
|
||||
** created for this transaction.
|
||||
*/
|
||||
if( bBatch==0 ){
|
||||
PgHdr *pPg;
|
||||
assert( isOpen(pPager->jfd)
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
|
||||
);
|
||||
if( !zMaster && isOpen(pPager->jfd)
|
||||
&& pPager->journalOff==jrnlBufferSize(pPager)
|
||||
&& pPager->dbSize>=pPager->dbOrigSize
|
||||
&& (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
|
||||
){
|
||||
/* Update the db file change counter via the direct-write method. The
|
||||
** following call will modify the in-memory representation of page 1
|
||||
** to include the updated change counter and then write page 1
|
||||
** directly to the database file. Because of the atomic-write
|
||||
** property of the host file-system, this is safe.
|
||||
*/
|
||||
rc = pager_incr_changecounter(pPager, 1);
|
||||
}else{
|
||||
rc = sqlite3JournalCreate(pPager->jfd);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_incr_changecounter(pPager, 0);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
PgHdr *pPg;
|
||||
assert( isOpen(pPager->jfd)
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
|
||||
);
|
||||
if( !zMaster && isOpen(pPager->jfd)
|
||||
&& pPager->journalOff==jrnlBufferSize(pPager)
|
||||
&& pPager->dbSize>=pPager->dbOrigSize
|
||||
&& (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
|
||||
){
|
||||
/* Update the db file change counter via the direct-write method. The
|
||||
** following call will modify the in-memory representation of page 1
|
||||
** to include the updated change counter and then write page 1
|
||||
** directly to the database file. Because of the atomic-write
|
||||
** property of the host file-system, this is safe.
|
||||
*/
|
||||
rc = pager_incr_changecounter(pPager, 1);
|
||||
}else{
|
||||
rc = sqlite3JournalCreate(pPager->jfd);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_incr_changecounter(pPager, 0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
if( zMaster ){
|
||||
rc = sqlite3JournalCreate(pPager->jfd);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
rc = pager_incr_changecounter(pPager, 0);
|
||||
#endif
|
||||
#endif
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
|
||||
/* Write the master journal name into the journal file. If a master
|
||||
@@ -6463,24 +6419,8 @@ int sqlite3PagerCommitPhaseOne(
|
||||
*/
|
||||
rc = syncJournal(pPager, 0);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
|
||||
if( bBatch ){
|
||||
/* The pager is now in DBMOD state. But regardless of what happens
|
||||
** next, attempting to play the journal back into the database would
|
||||
** be unsafe. Close it now to make sure that does not happen. */
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
}
|
||||
|
||||
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
|
||||
if( bBatch ){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
|
||||
}else{
|
||||
sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( rc!=SQLITE_IOERR_BLOCKED );
|
||||
goto commit_phase_one_exit;
|
||||
|
||||
-13
@@ -192,19 +192,6 @@ columnlist ::= columnlist COMMA columnname carglist.
|
||||
columnlist ::= columnname carglist.
|
||||
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
|
||||
// Declare some tokens early in order to influence their values, to
|
||||
// improve performance and reduce the executable size. The goal here is
|
||||
// to get the "jump" operations in ISNULL through ESCAPE to have numeric
|
||||
// values that are early enough so that all jump operations are clustered
|
||||
// at the beginning, but also so that the comparison tokens NE through GE
|
||||
// are as large as possible so that they are near to FUNCTION, which is a
|
||||
// token synthesized by addopcodes.tcl.
|
||||
//
|
||||
%token ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST.
|
||||
%token CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL.
|
||||
%token OR AND NOT IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
|
||||
%token GT LE LT GE ESCAPE.
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
|
||||
+18
-17
@@ -96,6 +96,7 @@ typedef struct PGroup PGroup;
|
||||
struct PgHdr1 {
|
||||
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
|
||||
unsigned int iKey; /* Key value (page number) */
|
||||
u8 isPinned; /* Page in use, not on the LRU list */
|
||||
u8 isBulkLocal; /* This page from bulk local storage */
|
||||
u8 isAnchor; /* This is the PGroup.lru element */
|
||||
PgHdr1 *pNext; /* Next in hash table chain */
|
||||
@@ -104,12 +105,6 @@ struct PgHdr1 {
|
||||
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
|
||||
};
|
||||
|
||||
/*
|
||||
** A page is pinned if it is no on the LRU list
|
||||
*/
|
||||
#define PAGE_IS_PINNED(p) ((p)->pLruNext==0)
|
||||
#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0)
|
||||
|
||||
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
|
||||
** of one or more PCaches that are able to recycle each other's unpinned
|
||||
** pages when they are under memory pressure. A PGroup is an instance of
|
||||
@@ -562,18 +557,22 @@ static void pcache1ResizeHash(PCache1 *p){
|
||||
** The PGroup mutex must be held when this function is called.
|
||||
*/
|
||||
static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
|
||||
PCache1 *pCache;
|
||||
|
||||
assert( pPage!=0 );
|
||||
assert( PAGE_IS_UNPINNED(pPage) );
|
||||
assert( pPage->isPinned==0 );
|
||||
pCache = pPage->pCache;
|
||||
assert( pPage->pLruNext );
|
||||
assert( pPage->pLruPrev );
|
||||
assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
pPage->pLruPrev->pLruNext = pPage->pLruNext;
|
||||
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
|
||||
pPage->pLruNext = 0;
|
||||
pPage->pLruPrev = 0;
|
||||
pPage->isPinned = 1;
|
||||
assert( pPage->isAnchor==0 );
|
||||
assert( pPage->pCache->pGroup->lru.isAnchor==1 );
|
||||
pPage->pCache->nRecyclable--;
|
||||
assert( pCache->pGroup->lru.isAnchor==1 );
|
||||
pCache->nRecyclable--;
|
||||
return pPage;
|
||||
}
|
||||
|
||||
@@ -611,7 +610,7 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
|
||||
&& (p=pGroup->lru.pLruPrev)->isAnchor==0
|
||||
){
|
||||
assert( p->pCache->pGroup==pGroup );
|
||||
assert( PAGE_IS_UNPINNED(p) );
|
||||
assert( p->isPinned==0 );
|
||||
pcache1PinPage(p);
|
||||
pcache1RemoveFromHash(p, 1);
|
||||
}
|
||||
@@ -660,7 +659,7 @@ static void pcache1TruncateUnsafe(
|
||||
if( pPage->iKey>=iLimit ){
|
||||
pCache->nPage--;
|
||||
*pp = pPage->pNext;
|
||||
if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
|
||||
if( !pPage->isPinned ) pcache1PinPage(pPage);
|
||||
pcache1FreePage(pPage);
|
||||
}else{
|
||||
pp = &pPage->pNext;
|
||||
@@ -879,7 +878,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
||||
){
|
||||
PCache1 *pOther;
|
||||
pPage = pGroup->lru.pLruPrev;
|
||||
assert( PAGE_IS_UNPINNED(pPage) );
|
||||
assert( pPage->isPinned==0 );
|
||||
pcache1RemoveFromHash(pPage, 0);
|
||||
pcache1PinPage(pPage);
|
||||
pOther = pPage->pCache;
|
||||
@@ -906,6 +905,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
||||
pPage->pCache = pCache;
|
||||
pPage->pLruPrev = 0;
|
||||
pPage->pLruNext = 0;
|
||||
pPage->isPinned = 1;
|
||||
*(void **)pPage->page.pExtra = 0;
|
||||
pCache->apHash[h] = pPage;
|
||||
if( iKey>pCache->iMaxKey ){
|
||||
@@ -991,7 +991,7 @@ static PgHdr1 *pcache1FetchNoMutex(
|
||||
** Otherwise (page not in hash and createFlag!=0) continue with
|
||||
** subsequent steps to try to create the page. */
|
||||
if( pPage ){
|
||||
if( PAGE_IS_UNPINNED(pPage) ){
|
||||
if( !pPage->isPinned ){
|
||||
return pcache1PinPage(pPage);
|
||||
}else{
|
||||
return pPage;
|
||||
@@ -1066,7 +1066,7 @@ static void pcache1Unpin(
|
||||
** part of the PGroup LRU list.
|
||||
*/
|
||||
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
|
||||
assert( PAGE_IS_PINNED(pPage) );
|
||||
assert( pPage->isPinned==1 );
|
||||
|
||||
if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
|
||||
pcache1RemoveFromHash(pPage, 1);
|
||||
@@ -1077,6 +1077,7 @@ static void pcache1Unpin(
|
||||
(pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
|
||||
*ppFirst = pPage;
|
||||
pCache->nRecyclable++;
|
||||
pPage->isPinned = 0;
|
||||
}
|
||||
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
@@ -1220,7 +1221,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
nFree += sqlite3MemSize(p);
|
||||
#endif
|
||||
assert( PAGE_IS_UNPINNED(p) );
|
||||
assert( p->isPinned==0 );
|
||||
pcache1PinPage(p);
|
||||
pcache1RemoveFromHash(p, 1);
|
||||
}
|
||||
@@ -1244,7 +1245,7 @@ void sqlite3PcacheStats(
|
||||
PgHdr1 *p;
|
||||
int nRecyclable = 0;
|
||||
for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
|
||||
assert( PAGE_IS_UNPINNED(p) );
|
||||
assert( p->isPinned==0 );
|
||||
nRecyclable++;
|
||||
}
|
||||
*pnCurrent = pcache1.grp.nCurrentPage;
|
||||
|
||||
+9
-7
@@ -494,14 +494,16 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
** Free all memory allocations in the pParse object
|
||||
*/
|
||||
void sqlite3ParserReset(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
sqlite3DbFree(db, pParse->aLabel);
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
if( db ){
|
||||
assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
||||
db->lookaside.bDisable -= pParse->disableLookaside;
|
||||
if( pParse ){
|
||||
sqlite3 *db = pParse->db;
|
||||
sqlite3DbFree(db, pParse->aLabel);
|
||||
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
||||
if( db ){
|
||||
assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
||||
db->lookaside.bDisable -= pParse->disableLookaside;
|
||||
}
|
||||
pParse->disableLookaside = 0;
|
||||
}
|
||||
pParse->disableLookaside = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+99
-27
@@ -562,11 +562,11 @@ static void pushOntoSorter(
|
||||
if( pParse->db->mallocFailed ) return;
|
||||
pOp->p2 = nKey + nData;
|
||||
pKI = pOp->p4.pKeyInfo;
|
||||
memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
|
||||
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
|
||||
testcase( pKI->nAllField > pKI->nKeyField+2 );
|
||||
testcase( pKI->nXField>2 );
|
||||
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
|
||||
pKI->nAllField-pKI->nKeyField-1);
|
||||
pKI->nXField-1);
|
||||
addrJmp = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
|
||||
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
|
||||
@@ -1035,8 +1035,8 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
||||
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
|
||||
if( p ){
|
||||
p->aSortOrder = (u8*)&p->aColl[N+X];
|
||||
p->nKeyField = (u16)N;
|
||||
p->nAllField = (u16)(N+X);
|
||||
p->nField = (u16)N;
|
||||
p->nXField = (u16)X;
|
||||
p->enc = ENC(db);
|
||||
p->db = db;
|
||||
p->nRef = 1;
|
||||
@@ -1438,10 +1438,13 @@ static const char *columnTypeImpl(
|
||||
** of the SELECT statement. Return the declaration type and origin
|
||||
** data for the result-set column of the sub-select.
|
||||
*/
|
||||
if( iCol>=0 && iCol<pS->pEList->nExpr ){
|
||||
if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
|
||||
/* If iCol is less than zero, then the expression requests the
|
||||
** rowid of the sub-select or view. This expression is legal (see
|
||||
** test case misc2.2.2) - it always evaluates to NULL.
|
||||
**
|
||||
** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
|
||||
** caught already by name resolution.
|
||||
*/
|
||||
NameContext sNC;
|
||||
Expr *p = pS->pEList->a[iCol].pExpr;
|
||||
@@ -1551,6 +1554,18 @@ static void generateColumnTypes(
|
||||
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the Table objecct in the SrcList that has cursor iCursor.
|
||||
** Or return NULL if no such Table object exists in the SrcList.
|
||||
*/
|
||||
static Table *tableWithCursor(SrcList *pList, int iCursor){
|
||||
int j;
|
||||
for(j=0; j<pList->nSrc; j++){
|
||||
if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Compute the column names for a SELECT statement.
|
||||
@@ -1584,16 +1599,15 @@ static void generateColumnTypes(
|
||||
*/
|
||||
static void generateColumnNames(
|
||||
Parse *pParse, /* Parser context */
|
||||
Select *pSelect /* Generate column names for this SELECT statement */
|
||||
SrcList *pTabList, /* The FROM clause of the SELECT */
|
||||
ExprList *pEList /* Expressions defining the result set */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int i;
|
||||
Table *pTab;
|
||||
SrcList *pTabList;
|
||||
ExprList *pEList;
|
||||
sqlite3 *db = pParse->db;
|
||||
int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
|
||||
int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
|
||||
int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
|
||||
int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
/* If this is an EXPLAIN, skip this step */
|
||||
@@ -1603,10 +1617,6 @@ static void generateColumnNames(
|
||||
#endif
|
||||
|
||||
if( pParse->colNamesSet || db->mallocFailed ) return;
|
||||
/* Column names are determined by the left-most term of a compound select */
|
||||
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
|
||||
pTabList = pSelect->pSrc;
|
||||
pEList = pSelect->pEList;
|
||||
assert( v!=0 );
|
||||
assert( pTabList!=0 );
|
||||
pParse->colNamesSet = 1;
|
||||
@@ -1621,11 +1631,12 @@ static void generateColumnNames(
|
||||
/* An AS clause always takes first priority */
|
||||
char *zName = pEList->a[i].zName;
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
|
||||
}else if( srcName && p->op==TK_COLUMN ){
|
||||
}else if( srcName
|
||||
&& (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
|
||||
&& (pTab = tableWithCursor(pTabList, p->iTable))!=0
|
||||
){
|
||||
char *zCol;
|
||||
int iCol = p->iColumn;
|
||||
pTab = p->pTab;
|
||||
assert( pTab!=0 );
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||
if( iCol<0 ){
|
||||
@@ -2457,6 +2468,11 @@ static int multiSelect(
|
||||
if( dest.eDest!=priorOp ){
|
||||
int iCont, iBreak, iStart;
|
||||
assert( p->pEList );
|
||||
if( dest.eDest==SRT_Output ){
|
||||
Select *pFirst = p;
|
||||
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
||||
generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
|
||||
}
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
@@ -2527,6 +2543,11 @@ static int multiSelect(
|
||||
** tables.
|
||||
*/
|
||||
assert( p->pEList );
|
||||
if( dest.eDest==SRT_Output ){
|
||||
Select *pFirst = p;
|
||||
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
||||
generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
|
||||
}
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
@@ -3134,6 +3155,14 @@ static int multiSelectOrderBy(
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, labelEnd);
|
||||
|
||||
/* Set the number of output columns
|
||||
*/
|
||||
if( pDest->eDest==SRT_Output ){
|
||||
Select *pFirst = pPrior;
|
||||
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
||||
generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
|
||||
}
|
||||
|
||||
/* Reassembly the compound query so that it will be freed correctly
|
||||
** by the calling function */
|
||||
if( p->pPrior ){
|
||||
@@ -3428,6 +3457,7 @@ static int flattenSubquery(
|
||||
Select *pSub1; /* Pointer to the rightmost select in sub-query */
|
||||
SrcList *pSrc; /* The FROM clause of the outer query */
|
||||
SrcList *pSubSrc; /* The FROM clause of the subquery */
|
||||
ExprList *pList; /* The result set of the outer query */
|
||||
int iParent; /* VDBE cursor number of the pSub result set temp table */
|
||||
int iNewParent = -1;/* Replacement table for iParent */
|
||||
int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
|
||||
@@ -3739,7 +3769,46 @@ static int flattenSubquery(
|
||||
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
||||
}
|
||||
pSrc->a[iFrom].fg.jointype = jointype;
|
||||
|
||||
|
||||
/* For every result column in the outer query that does not have an AS
|
||||
** clause, if that column is a reference to an output column from the
|
||||
** inner query, then preserve the name of the column by adding an AS clause.
|
||||
** This prevents the outer query column from taking on a name derived
|
||||
** from inner query column name.
|
||||
**
|
||||
** Example:
|
||||
** CREATE TABLE t1(a,b);
|
||||
** CREATE VIEW v1(x,y) AS SELECT a,b FROM t1;
|
||||
** SELECT x,y FROM v1;
|
||||
**
|
||||
** The inner "v1" subquery will get flattened into the outer query. After
|
||||
** flattening, the outer query becomes: "SELECT a,b FROM t1". But the
|
||||
** new query gives column names of "a" and "b", not the "x" and "y" that
|
||||
** the programmer expected. This step adds AS clauses so that the
|
||||
** flattened query becomes: "SELECT a AS x, b AS y FROM t1".
|
||||
**
|
||||
** Update on 2017-07-29: The current implementation only adds AS clauses
|
||||
** to outer query result columns that are substituted directly for
|
||||
** columns of the inner query. Formerly, all result columns in the outer
|
||||
** query got new AS clauses if they didn't have them all ready. Also,
|
||||
** the name of the AS clause is taken from the result column name of
|
||||
** the inner query. Formerly, the name was a copy of the text of the
|
||||
** original SQL statement that specified the column.
|
||||
*/
|
||||
pList = pParent->pEList;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *p;
|
||||
if( pList->a[i].zName==0
|
||||
&& (p = pList->a[i].pExpr)->op==TK_COLUMN
|
||||
&& p->iTable==iParent
|
||||
&& p->iColumn>=0
|
||||
&& ALWAYS(p->pTab!=0)
|
||||
){
|
||||
char *zName = sqlite3DbStrDup(db, p->pTab->aCol[p->iColumn].zName);
|
||||
pList->a[i].zName = zName;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now begin substituting subquery result set expressions for
|
||||
** references to the iParent in the outer query.
|
||||
**
|
||||
@@ -5181,14 +5250,6 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get a pointer the VDBE under construction, allocating a new VDBE if one
|
||||
** does not already exist */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto select_end;
|
||||
if( pDest->eDest==SRT_Output ){
|
||||
generateColumnNames(pParse, p);
|
||||
}
|
||||
|
||||
/* Try to flatten subqueries in the FROM clause up into the main query
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
@@ -5224,6 +5285,11 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get a pointer the VDBE under construction, allocating a new VDBE if one
|
||||
** does not already exist */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto select_end;
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
/* Handle compound SELECT statements using the separate multiSelect()
|
||||
** procedure.
|
||||
@@ -6023,6 +6089,12 @@ int sqlite3Select(
|
||||
select_end:
|
||||
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
||||
|
||||
/* Identify column names if results of the SELECT are to be output.
|
||||
*/
|
||||
if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){
|
||||
generateColumnNames(pParse, pTabList, pEList);
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, sAggInfo.aCol);
|
||||
sqlite3DbFree(db, sAggInfo.aFunc);
|
||||
#if SELECTTRACE_ENABLED
|
||||
|
||||
@@ -494,9 +494,6 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
|
||||
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
|
||||
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
|
||||
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
|
||||
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
|
||||
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
||||
@@ -583,11 +580,6 @@ int sqlite3_exec(
|
||||
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
|
||||
** read-only media and cannot be changed even by processes with
|
||||
** elevated privileges.
|
||||
**
|
||||
** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
|
||||
** filesystem supports doing multiple write operations atomically when those
|
||||
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
|
||||
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
|
||||
*/
|
||||
#define SQLITE_IOCAP_ATOMIC 0x00000001
|
||||
#define SQLITE_IOCAP_ATOMIC512 0x00000002
|
||||
@@ -603,7 +595,6 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
|
||||
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
|
||||
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
|
||||
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
|
||||
|
||||
/*
|
||||
** CAPI3REF: File Locking Levels
|
||||
@@ -738,7 +729,6 @@ struct sqlite3_file {
|
||||
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
|
||||
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
|
||||
** <li> [SQLITE_IOCAP_IMMUTABLE]
|
||||
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
|
||||
** </ul>
|
||||
**
|
||||
** The SQLITE_IOCAP_ATOMIC property means that all writes of
|
||||
@@ -1022,40 +1012,6 @@ struct sqlite3_io_methods {
|
||||
** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
|
||||
** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
|
||||
** this opcode.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
|
||||
** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
|
||||
** the file descriptor is placed in "batch write mode", which
|
||||
** means all subsequent write operations will be deferred and done
|
||||
** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
|
||||
** that do not support batch atomic writes will return SQLITE_NOTFOUND.
|
||||
** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
|
||||
** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
|
||||
** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
|
||||
** no VFS interface calls on the same [sqlite3_file] file descriptor
|
||||
** except for calls to the xWrite method and the xFileControl method
|
||||
** with [SQLITE_FCNTL_SIZE_HINT].
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
|
||||
** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
|
||||
** operations since the previous successful call to
|
||||
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
|
||||
** This file control returns [SQLITE_OK] if and only if the writes were
|
||||
** all performed successfully and have been committed to persistent storage.
|
||||
** ^Regardless of whether or not it is successful, this file control takes
|
||||
** the file descriptor out of batch write mode so that all subsequent
|
||||
** write operations are independent.
|
||||
** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
|
||||
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
|
||||
** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
|
||||
** operations since the previous successful call to
|
||||
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
|
||||
** ^This file control takes the file descriptor out of batch write mode
|
||||
** so that all subsequent write operations are independent.
|
||||
** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
|
||||
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@@ -1087,9 +1043,6 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_JOURNAL_POINTER 28
|
||||
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
|
||||
#define SQLITE_FCNTL_PDB 30
|
||||
#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
|
||||
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
|
||||
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
|
||||
+3
-13
@@ -630,15 +630,6 @@
|
||||
# define SQLITE_DEFAULT_PCACHE_INITSZ 20
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The compile-time options SQLITE_MMAP_READWRITE and
|
||||
** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
|
||||
** You must choose one or the other (or neither) but not both.
|
||||
*/
|
||||
#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** GCC does not define the offsetof() macro so we'll have to do it
|
||||
** ourselves.
|
||||
@@ -2052,8 +2043,8 @@ struct FKey {
|
||||
struct KeyInfo {
|
||||
u32 nRef; /* Number of references to this KeyInfo object */
|
||||
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
|
||||
u16 nKeyField; /* Number of key columns in the index */
|
||||
u16 nAllField; /* Total columns, including key plus others */
|
||||
u16 nField; /* Number of key columns in the index */
|
||||
u16 nXField; /* Number of columns beyond the key columns */
|
||||
sqlite3 *db; /* The database connection */
|
||||
u8 *aSortOrder; /* Sort order for each column. */
|
||||
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
|
||||
@@ -4296,8 +4287,7 @@ int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
|
||||
|
||||
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
||||
int sqlite3JournalSize(sqlite3_vfs *);
|
||||
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
||||
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
int sqlite3JournalCreate(sqlite3_file *);
|
||||
#endif
|
||||
|
||||
|
||||
+4
-15
@@ -3882,39 +3882,28 @@ static int SQLITE_TCLAPI md5file_cmd(
|
||||
const char **argv
|
||||
){
|
||||
FILE *in;
|
||||
int ofst;
|
||||
int amt;
|
||||
MD5Context ctx;
|
||||
void (*converter)(unsigned char*, char*);
|
||||
unsigned char digest[16];
|
||||
char zBuf[10240];
|
||||
|
||||
if( argc!=2 && argc!=4 ){
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" FILENAME [OFFSET AMT]\"", (char*)0);
|
||||
" FILENAME\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( argc==4 ){
|
||||
ofst = atoi(argv[2]);
|
||||
amt = atoi(argv[3]);
|
||||
}else{
|
||||
ofst = 0;
|
||||
amt = 2147483647;
|
||||
}
|
||||
in = fopen(argv[1],"rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
"\" for reading", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
fseek(in, ofst, SEEK_SET);
|
||||
MD5Init(&ctx);
|
||||
while( amt>0 ){
|
||||
for(;;){
|
||||
int n;
|
||||
n = (int)fread(zBuf, 1, sizeof(zBuf)<=amt ? sizeof(zBuf) : amt, in);
|
||||
n = (int)fread(zBuf, 1, sizeof(zBuf), in);
|
||||
if( n<=0 ) break;
|
||||
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
|
||||
amt -= n;
|
||||
}
|
||||
fclose(in);
|
||||
MD5Final(digest, &ctx);
|
||||
|
||||
-41
@@ -2553,46 +2553,6 @@ static int SQLITE_TCLAPI test_delete_database(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: atomic_batch_write PATH
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_atomic_batch_write(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
char *zFile = 0; /* Path to file to test */
|
||||
sqlite3 *db = 0; /* Database handle */
|
||||
sqlite3_file *pFd = 0; /* SQLite fd open on zFile */
|
||||
int bRes = 0; /* Integer result of this command */
|
||||
int dc = 0; /* Device-characteristics mask */
|
||||
int rc; /* sqlite3_open() return code */
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "PATH");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zFile = Tcl_GetString(objv[1]);
|
||||
|
||||
rc = sqlite3_open(zFile, &db);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
|
||||
sqlite3_close(db);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
|
||||
dc = pFd->pMethods->xDeviceCharacteristics(pFd);
|
||||
if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
|
||||
bRes = 1;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
|
||||
sqlite3_close(db);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_next_stmt DB STMT
|
||||
**
|
||||
@@ -7685,7 +7645,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
|
||||
#endif
|
||||
{ "sqlite3_delete_database", test_delete_database, 0 },
|
||||
{ "atomic_batch_write", test_atomic_batch_write, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
|
||||
|
||||
-25
@@ -736,7 +736,6 @@ static int processDevSymArgs(
|
||||
{ "sequential", SQLITE_IOCAP_SEQUENTIAL },
|
||||
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
|
||||
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
|
||||
{ "batch-atomic", SQLITE_IOCAP_BATCH_ATOMIC },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -977,30 +976,7 @@ static int SQLITE_TCLAPI devSymObjCmd(
|
||||
devsym_register(iDc, iSectorSize);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_crash_on_write N
|
||||
*/
|
||||
static int SQLITE_TCLAPI writeCrashObjCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
void devsym_crash_on_write(int);
|
||||
int nWrite = 0;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "NWRITE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &nWrite) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
devsym_crash_on_write(nWrite);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1092,7 +1068,6 @@ int Sqlitetest6_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_crash_on_write", writeCrashObjCmd,0,0);
|
||||
Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
|
||||
|
||||
+50
-168
@@ -28,7 +28,6 @@
|
||||
** Name used to identify this VFS.
|
||||
*/
|
||||
#define DEVSYM_VFS_NAME "devsym"
|
||||
#define WRITECRASH_NAME "writecrash"
|
||||
|
||||
typedef struct devsym_file devsym_file;
|
||||
struct devsym_file {
|
||||
@@ -73,13 +72,61 @@ static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int devsymSleep(sqlite3_vfs*, int microseconds);
|
||||
static int devsymCurrentTime(sqlite3_vfs*, double*);
|
||||
|
||||
static sqlite3_vfs devsym_vfs = {
|
||||
2, /* iVersion */
|
||||
sizeof(devsym_file), /* szOsFile */
|
||||
DEVSYM_MAX_PATHNAME, /* mxPathname */
|
||||
0, /* pNext */
|
||||
DEVSYM_VFS_NAME, /* zName */
|
||||
0, /* pAppData */
|
||||
devsymOpen, /* xOpen */
|
||||
devsymDelete, /* xDelete */
|
||||
devsymAccess, /* xAccess */
|
||||
devsymFullPathname, /* xFullPathname */
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
devsymDlOpen, /* xDlOpen */
|
||||
devsymDlError, /* xDlError */
|
||||
devsymDlSym, /* xDlSym */
|
||||
devsymDlClose, /* xDlClose */
|
||||
#else
|
||||
0, /* xDlOpen */
|
||||
0, /* xDlError */
|
||||
0, /* xDlSym */
|
||||
0, /* xDlClose */
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
devsymRandomness, /* xRandomness */
|
||||
devsymSleep, /* xSleep */
|
||||
devsymCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods devsym_io_methods = {
|
||||
2, /* iVersion */
|
||||
devsymClose, /* xClose */
|
||||
devsymRead, /* xRead */
|
||||
devsymWrite, /* xWrite */
|
||||
devsymTruncate, /* xTruncate */
|
||||
devsymSync, /* xSync */
|
||||
devsymFileSize, /* xFileSize */
|
||||
devsymLock, /* xLock */
|
||||
devsymUnlock, /* xUnlock */
|
||||
devsymCheckReservedLock, /* xCheckReservedLock */
|
||||
devsymFileControl, /* xFileControl */
|
||||
devsymSectorSize, /* xSectorSize */
|
||||
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
devsymShmMap, /* xShmMap */
|
||||
devsymShmLock, /* xShmLock */
|
||||
devsymShmBarrier, /* xShmBarrier */
|
||||
devsymShmUnmap /* xShmUnmap */
|
||||
};
|
||||
|
||||
struct DevsymGlobal {
|
||||
sqlite3_vfs *pVfs;
|
||||
int iDeviceChar;
|
||||
int iSectorSize;
|
||||
int nWriteCrash;
|
||||
};
|
||||
struct DevsymGlobal g = {0, 0, 512, 0};
|
||||
struct DevsymGlobal g = {0, 0, 512};
|
||||
|
||||
/*
|
||||
** Close an devsym-file.
|
||||
@@ -224,26 +271,6 @@ static int devsymOpen(
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
static sqlite3_io_methods devsym_io_methods = {
|
||||
2, /* iVersion */
|
||||
devsymClose, /* xClose */
|
||||
devsymRead, /* xRead */
|
||||
devsymWrite, /* xWrite */
|
||||
devsymTruncate, /* xTruncate */
|
||||
devsymSync, /* xSync */
|
||||
devsymFileSize, /* xFileSize */
|
||||
devsymLock, /* xLock */
|
||||
devsymUnlock, /* xUnlock */
|
||||
devsymCheckReservedLock, /* xCheckReservedLock */
|
||||
devsymFileControl, /* xFileControl */
|
||||
devsymSectorSize, /* xSectorSize */
|
||||
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
devsymShmMap, /* xShmMap */
|
||||
devsymShmLock, /* xShmLock */
|
||||
devsymShmBarrier, /* xShmBarrier */
|
||||
devsymShmUnmap /* xShmUnmap */
|
||||
};
|
||||
|
||||
int rc;
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
p->pReal = (sqlite3_file *)&p[1];
|
||||
@@ -345,137 +372,6 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for an writecrash-file.
|
||||
*/
|
||||
static int writecrashSectorSize(sqlite3_file *pFile){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsSectorSize(p->pReal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by an writecrash-file.
|
||||
*/
|
||||
static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
return sqlite3OsDeviceCharacteristics(p->pReal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to an writecrash-file.
|
||||
*/
|
||||
static int writecrashWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
if( g.nWriteCrash>0 ){
|
||||
g.nWriteCrash--;
|
||||
if( g.nWriteCrash==0 ) abort();
|
||||
}
|
||||
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an writecrash file handle.
|
||||
*/
|
||||
static int writecrashOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
static sqlite3_io_methods writecrash_io_methods = {
|
||||
2, /* iVersion */
|
||||
devsymClose, /* xClose */
|
||||
devsymRead, /* xRead */
|
||||
writecrashWrite, /* xWrite */
|
||||
devsymTruncate, /* xTruncate */
|
||||
devsymSync, /* xSync */
|
||||
devsymFileSize, /* xFileSize */
|
||||
devsymLock, /* xLock */
|
||||
devsymUnlock, /* xUnlock */
|
||||
devsymCheckReservedLock, /* xCheckReservedLock */
|
||||
devsymFileControl, /* xFileControl */
|
||||
writecrashSectorSize, /* xSectorSize */
|
||||
writecrashDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
devsymShmMap, /* xShmMap */
|
||||
devsymShmLock, /* xShmLock */
|
||||
devsymShmBarrier, /* xShmBarrier */
|
||||
devsymShmUnmap /* xShmUnmap */
|
||||
};
|
||||
|
||||
int rc;
|
||||
devsym_file *p = (devsym_file *)pFile;
|
||||
p->pReal = (sqlite3_file *)&p[1];
|
||||
rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
|
||||
if( p->pReal->pMethods ){
|
||||
pFile->pMethods = &writecrash_io_methods;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static sqlite3_vfs devsym_vfs = {
|
||||
2, /* iVersion */
|
||||
sizeof(devsym_file), /* szOsFile */
|
||||
DEVSYM_MAX_PATHNAME, /* mxPathname */
|
||||
0, /* pNext */
|
||||
DEVSYM_VFS_NAME, /* zName */
|
||||
0, /* pAppData */
|
||||
devsymOpen, /* xOpen */
|
||||
devsymDelete, /* xDelete */
|
||||
devsymAccess, /* xAccess */
|
||||
devsymFullPathname, /* xFullPathname */
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
devsymDlOpen, /* xDlOpen */
|
||||
devsymDlError, /* xDlError */
|
||||
devsymDlSym, /* xDlSym */
|
||||
devsymDlClose, /* xDlClose */
|
||||
#else
|
||||
0, /* xDlOpen */
|
||||
0, /* xDlError */
|
||||
0, /* xDlSym */
|
||||
0, /* xDlClose */
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
devsymRandomness, /* xRandomness */
|
||||
devsymSleep, /* xSleep */
|
||||
devsymCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
static sqlite3_vfs writecrash_vfs = {
|
||||
2, /* iVersion */
|
||||
sizeof(devsym_file), /* szOsFile */
|
||||
DEVSYM_MAX_PATHNAME, /* mxPathname */
|
||||
0, /* pNext */
|
||||
WRITECRASH_NAME, /* zName */
|
||||
0, /* pAppData */
|
||||
writecrashOpen, /* xOpen */
|
||||
devsymDelete, /* xDelete */
|
||||
devsymAccess, /* xAccess */
|
||||
devsymFullPathname, /* xFullPathname */
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
devsymDlOpen, /* xDlOpen */
|
||||
devsymDlError, /* xDlError */
|
||||
devsymDlSym, /* xDlSym */
|
||||
devsymDlClose, /* xDlClose */
|
||||
#else
|
||||
0, /* xDlOpen */
|
||||
0, /* xDlError */
|
||||
0, /* xDlSym */
|
||||
0, /* xDlClose */
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
devsymRandomness, /* xRandomness */
|
||||
devsymSleep, /* xSleep */
|
||||
devsymCurrentTime, /* xCurrentTime */
|
||||
0, /* xGetLastError */
|
||||
0 /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** This procedure registers the devsym vfs with SQLite. If the argument is
|
||||
@@ -483,13 +379,10 @@ static sqlite3_vfs writecrash_vfs = {
|
||||
** available function in this file.
|
||||
*/
|
||||
void devsym_register(int iDeviceChar, int iSectorSize){
|
||||
|
||||
if( g.pVfs==0 ){
|
||||
g.pVfs = sqlite3_vfs_find(0);
|
||||
devsym_vfs.szOsFile += g.pVfs->szOsFile;
|
||||
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
|
||||
sqlite3_vfs_register(&devsym_vfs, 0);
|
||||
sqlite3_vfs_register(&writecrash_vfs, 0);
|
||||
}
|
||||
if( iDeviceChar>=0 ){
|
||||
g.iDeviceChar = iDeviceChar;
|
||||
@@ -510,15 +403,4 @@ void devsym_unregister(){
|
||||
g.iSectorSize = 0;
|
||||
}
|
||||
|
||||
void devsym_crash_on_write(int nWrite){
|
||||
if( g.pVfs==0 ){
|
||||
g.pVfs = sqlite3_vfs_find(0);
|
||||
devsym_vfs.szOsFile += g.pVfs->szOsFile;
|
||||
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
|
||||
sqlite3_vfs_register(&devsym_vfs, 0);
|
||||
sqlite3_vfs_register(&writecrash_vfs, 0);
|
||||
}
|
||||
g.nWriteCrash = nWrite;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+31
-46
@@ -1955,23 +1955,13 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
|
||||
}
|
||||
compare_op:
|
||||
/* At this point, res is negative, zero, or positive if reg[P1] is
|
||||
** less than, equal to, or greater than reg[P3], respectively. Compute
|
||||
** the answer to this operator in res2, depending on what the comparison
|
||||
** operator actually is. The next block of code depends on the fact
|
||||
** that the 6 comparison operators are consecutive integers in this
|
||||
** order: NE, EQ, GT, LE, LT, GE */
|
||||
assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 );
|
||||
assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 );
|
||||
if( res<0 ){ /* ne, eq, gt, le, lt, ge */
|
||||
static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 };
|
||||
res2 = aLTb[pOp->opcode - OP_Ne];
|
||||
}else if( res==0 ){
|
||||
static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 };
|
||||
res2 = aEQb[pOp->opcode - OP_Ne];
|
||||
}else{
|
||||
static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 };
|
||||
res2 = aGTb[pOp->opcode - OP_Ne];
|
||||
switch( pOp->opcode ){
|
||||
case OP_Eq: res2 = res==0; break;
|
||||
case OP_Ne: res2 = res; break;
|
||||
case OP_Lt: res2 = res<0; break;
|
||||
case OP_Le: res2 = res<=0; break;
|
||||
case OP_Gt: res2 = res>0; break;
|
||||
default: res2 = res>=0; break;
|
||||
}
|
||||
|
||||
/* Undo any changes made by applyAffinity() to the input registers. */
|
||||
@@ -1983,6 +1973,7 @@ compare_op:
|
||||
if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
pOut = &aMem[pOp->p2];
|
||||
iCompare = res;
|
||||
res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */
|
||||
if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
|
||||
/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
|
||||
** and prevents OP_Ne from overwriting NULL with 0. This flag
|
||||
@@ -2113,7 +2104,7 @@ case OP_Compare: {
|
||||
assert( memIsValid(&aMem[p2+idx]) );
|
||||
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
|
||||
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
|
||||
assert( i<pKeyInfo->nKeyField );
|
||||
assert( i<pKeyInfo->nField );
|
||||
pColl = pKeyInfo->aColl[i];
|
||||
bRev = pKeyInfo->aSortOrder[i];
|
||||
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
|
||||
@@ -3407,7 +3398,7 @@ case OP_OpenWrite:
|
||||
pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( pKeyInfo->enc==ENC(db) );
|
||||
assert( pKeyInfo->db==db );
|
||||
nField = pKeyInfo->nAllField;
|
||||
nField = pKeyInfo->nField+pKeyInfo->nXField;
|
||||
}else if( pOp->p4type==P4_INT32 ){
|
||||
nField = pOp->p4.i;
|
||||
}
|
||||
@@ -4785,17 +4776,7 @@ case OP_NullRow: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SeekEnd P1 * * * *
|
||||
**
|
||||
** Position cursor P1 at the end of the btree for the purpose of
|
||||
** appending a new entry onto the btree.
|
||||
**
|
||||
** It is assumed that the cursor is used only for appending and so
|
||||
** if the cursor is valid, then the cursor must already be pointing
|
||||
** at the end of the btree and so no changes are made to
|
||||
** the cursor.
|
||||
*/
|
||||
/* Opcode: Last P1 P2 * * *
|
||||
/* Opcode: Last P1 P2 P3 * *
|
||||
**
|
||||
** The next use of the Rowid or Column or Prev instruction for P1
|
||||
** will refer to the last entry in the database table or index.
|
||||
@@ -4806,8 +4787,14 @@ case OP_NullRow: {
|
||||
** This opcode leaves the cursor configured to move in reverse order,
|
||||
** from the end toward the beginning. In other words, the cursor is
|
||||
** configured to use Prev, not Next.
|
||||
**
|
||||
** If P3 is -1, then the cursor is positioned at the end of the btree
|
||||
** for the purpose of appending a new entry onto the btree. In that
|
||||
** case P2 must be 0. It is assumed that the cursor is used only for
|
||||
** appending and so if the cursor is valid, then the cursor must already
|
||||
** be pointing at the end of the btree and so no changes are made to
|
||||
** the cursor.
|
||||
*/
|
||||
case OP_SeekEnd:
|
||||
case OP_Last: { /* jump */
|
||||
VdbeCursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
@@ -4820,24 +4807,22 @@ case OP_Last: { /* jump */
|
||||
pCrsr = pC->uc.pCursor;
|
||||
res = 0;
|
||||
assert( pCrsr!=0 );
|
||||
pC->seekResult = pOp->p3;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pC->seekOp = pOp->opcode;
|
||||
pC->seekOp = OP_Last;
|
||||
#endif
|
||||
if( pOp->opcode==OP_SeekEnd ){
|
||||
assert( pOp->p2==0 );
|
||||
pC->seekResult = -1;
|
||||
if( sqlite3BtreeCursorIsValidNN(pCrsr) ){
|
||||
break;
|
||||
if( pOp->p3==0 || !sqlite3BtreeCursorIsValidNN(pCrsr) ){
|
||||
rc = sqlite3BtreeLast(pCrsr, &res);
|
||||
pC->nullRow = (u8)res;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pOp->p2>0 ){
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeLast(pCrsr, &res);
|
||||
pC->nullRow = (u8)res;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pOp->p2>0 ){
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
}else{
|
||||
assert( pOp->p2==0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+27
-25
@@ -523,7 +523,7 @@ static int doWalCallbacks(sqlite3 *db){
|
||||
sqlite3BtreeEnter(pBt);
|
||||
nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
|
||||
sqlite3BtreeLeave(pBt);
|
||||
if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
|
||||
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
|
||||
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
|
||||
}
|
||||
}
|
||||
@@ -633,7 +633,7 @@ static int sqlite3Step(Vdbe *p){
|
||||
if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
|
||||
#endif
|
||||
|
||||
if( rc==SQLITE_DONE && db->autoCommit ){
|
||||
if( rc==SQLITE_DONE ){
|
||||
assert( p->rc==SQLITE_OK );
|
||||
p->rc = doWalCallbacks(db);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
@@ -677,6 +677,7 @@ end_of_step:
|
||||
*/
|
||||
int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
int rc = SQLITE_OK; /* Result from sqlite3Step() */
|
||||
int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
|
||||
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
|
||||
int cnt = 0; /* Counter to prevent infinite loop of reprepares */
|
||||
sqlite3 *db; /* The database connection */
|
||||
@@ -690,31 +691,32 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
|
||||
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
|
||||
int savedPc = v->pc;
|
||||
rc = sqlite3Reprepare(v);
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* This case occurs after failing to recompile an sql statement.
|
||||
** The error message from the SQL compiler has already been loaded
|
||||
** into the database handle. This block copies the error message
|
||||
** from the database handle into the statement and sets the statement
|
||||
** program counter to 0 to ensure that when the statement is
|
||||
** finalized or reset the parser error message is available via
|
||||
** sqlite3_errmsg() and sqlite3_errcode().
|
||||
*/
|
||||
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
|
||||
sqlite3DbFree(db, v->zErrMsg);
|
||||
if( !db->mallocFailed ){
|
||||
v->zErrMsg = sqlite3DbStrDup(db, zErr);
|
||||
v->rc = rc = sqlite3ApiExit(db, rc);
|
||||
} else {
|
||||
v->zErrMsg = 0;
|
||||
v->rc = rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
rc2 = rc = sqlite3Reprepare(v);
|
||||
if( rc!=SQLITE_OK) break;
|
||||
sqlite3_reset(pStmt);
|
||||
if( savedPc>=0 ) v->doingRerun = 1;
|
||||
assert( v->expired==0 );
|
||||
}
|
||||
if( rc2!=SQLITE_OK ){
|
||||
/* This case occurs after failing to recompile an sql statement.
|
||||
** The error message from the SQL compiler has already been loaded
|
||||
** into the database handle. This block copies the error message
|
||||
** from the database handle into the statement and sets the statement
|
||||
** program counter to 0 to ensure that when the statement is
|
||||
** finalized or reset the parser error message is available via
|
||||
** sqlite3_errmsg() and sqlite3_errcode().
|
||||
*/
|
||||
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
|
||||
sqlite3DbFree(db, v->zErrMsg);
|
||||
if( !db->mallocFailed ){
|
||||
v->zErrMsg = sqlite3DbStrDup(db, zErr);
|
||||
v->rc = rc2;
|
||||
} else {
|
||||
v->zErrMsg = 0;
|
||||
v->rc = rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
@@ -1720,7 +1722,7 @@ static UnpackedRecord *vdbeUnpackRecord(
|
||||
|
||||
pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
|
||||
if( pRet ){
|
||||
memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
|
||||
memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
|
||||
sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
|
||||
}
|
||||
return pRet;
|
||||
@@ -1793,7 +1795,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
*/
|
||||
int sqlite3_preupdate_count(sqlite3 *db){
|
||||
PreUpdate *p = db->pPreUpdate;
|
||||
return (p ? p->keyinfo.nKeyField : 0);
|
||||
return (p ? p->keyinfo.nField : 0);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
|
||||
|
||||
+32
-51
@@ -597,27 +597,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
p->bIsReader = 1;
|
||||
break;
|
||||
}
|
||||
case OP_Next:
|
||||
case OP_NextIfOpen:
|
||||
case OP_SorterNext: {
|
||||
pOp->p4.xAdvance = sqlite3BtreeNext;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
/* The code generator never codes any of these opcodes as a jump
|
||||
** to a label. They are always coded as a jump backwards to a
|
||||
** known address */
|
||||
assert( pOp->p2>=0 );
|
||||
break;
|
||||
}
|
||||
case OP_Prev:
|
||||
case OP_PrevIfOpen: {
|
||||
pOp->p4.xAdvance = sqlite3BtreePrevious;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
/* The code generator never codes any of these opcodes as a jump
|
||||
** to a label. They are always coded as a jump backwards to a
|
||||
** known address */
|
||||
assert( pOp->p2>=0 );
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
case OP_VUpdate: {
|
||||
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
||||
@@ -629,25 +608,27 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
assert( pOp[-1].opcode==OP_Integer );
|
||||
n = pOp[-1].p1;
|
||||
if( n>nMaxArgs ) nMaxArgs = n;
|
||||
/* Fall through into the default case */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
if( pOp->p2<0 ){
|
||||
/* The mkopcodeh.tcl script has so arranged things that the only
|
||||
** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
|
||||
** have non-negative values for P2. */
|
||||
assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
|
||||
assert( ADDR(pOp->p2)<pParse->nLabel );
|
||||
pOp->p2 = aLabel[ADDR(pOp->p2)];
|
||||
}
|
||||
case OP_Next:
|
||||
case OP_NextIfOpen:
|
||||
case OP_SorterNext: {
|
||||
pOp->p4.xAdvance = sqlite3BtreeNext;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
}
|
||||
case OP_Prev:
|
||||
case OP_PrevIfOpen: {
|
||||
pOp->p4.xAdvance = sqlite3BtreePrevious;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* The mkopcodeh.tcl script has so arranged things that the only
|
||||
** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
|
||||
** have non-negative values for P2. */
|
||||
assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
|
||||
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
|
||||
assert( ADDR(pOp->p2)<pParse->nLabel );
|
||||
pOp->p2 = aLabel[ADDR(pOp->p2)];
|
||||
}
|
||||
}
|
||||
if( pOp==p->aOp ) break;
|
||||
pOp--;
|
||||
@@ -1320,8 +1301,8 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
int j;
|
||||
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField);
|
||||
for(j=0; j<pKeyInfo->nKeyField; j++){
|
||||
sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField);
|
||||
for(j=0; j<pKeyInfo->nField; j++){
|
||||
CollSeq *pColl = pKeyInfo->aColl[j];
|
||||
const char *zColl = pColl ? pColl->zName : "";
|
||||
if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
|
||||
@@ -3547,13 +3528,13 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
|
||||
){
|
||||
UnpackedRecord *p; /* Unpacked record to return */
|
||||
int nByte; /* Number of bytes required for *p */
|
||||
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
|
||||
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
|
||||
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
||||
if( !p ) return 0;
|
||||
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
p->pKeyInfo = pKeyInfo;
|
||||
p->nField = pKeyInfo->nKeyField + 1;
|
||||
p->nField = pKeyInfo->nField + 1;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -3593,7 +3574,7 @@ void sqlite3VdbeRecordUnpack(
|
||||
pMem++;
|
||||
if( (++u)>=p->nField ) break;
|
||||
}
|
||||
assert( u<=pKeyInfo->nKeyField + 1 );
|
||||
assert( u<=pKeyInfo->nField + 1 );
|
||||
p->nField = u;
|
||||
}
|
||||
|
||||
@@ -3642,9 +3623,9 @@ static int vdbeRecordCompareDebug(
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
if( szHdr1>98307 ) return SQLITE_CORRUPT;
|
||||
d1 = szHdr1;
|
||||
assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
|
||||
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
assert( pKeyInfo->nKeyField>0 );
|
||||
assert( pKeyInfo->nField>0 );
|
||||
assert( idx1<=szHdr1 || CORRUPT_DB );
|
||||
do{
|
||||
u32 serial_type1;
|
||||
@@ -3706,12 +3687,12 @@ debugCompareEnd:
|
||||
/*
|
||||
** Count the number of fields (a.k.a. columns) in the record given by
|
||||
** pKey,nKey. The verify that this count is less than or equal to the
|
||||
** limit given by pKeyInfo->nAllField.
|
||||
** limit given by pKeyInfo->nField + pKeyInfo->nXField.
|
||||
**
|
||||
** If this constraint is not satisfied, it means that the high-speed
|
||||
** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
|
||||
** not work correctly. If this assert() ever fires, it probably means
|
||||
** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed
|
||||
** that the KeyInfo.nField or KeyInfo.nXField values were computed
|
||||
** incorrectly.
|
||||
*/
|
||||
static void vdbeAssertFieldCountWithinLimits(
|
||||
@@ -3732,7 +3713,7 @@ static void vdbeAssertFieldCountWithinLimits(
|
||||
idx += getVarint32(aKey+idx, notUsed);
|
||||
nField++;
|
||||
}
|
||||
assert( nField <= pKeyInfo->nAllField );
|
||||
assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
|
||||
}
|
||||
#else
|
||||
# define vdbeAssertFieldCountWithinLimits(A,B,C)
|
||||
@@ -4037,10 +4018,10 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
}
|
||||
|
||||
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
|
||||
assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|
||||
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
|
||||
|| CORRUPT_DB );
|
||||
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
|
||||
assert( pPKey2->pKeyInfo->nKeyField>0 );
|
||||
assert( pPKey2->pKeyInfo->nField>0 );
|
||||
assert( idx1<=szHdr1 || CORRUPT_DB );
|
||||
do{
|
||||
u32 serial_type;
|
||||
@@ -4373,7 +4354,7 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
||||
** The easiest way to enforce this limit is to consider only records with
|
||||
** 13 fields or less. If the first field is an integer, the maximum legal
|
||||
** header size is (12*5 + 1 + 1) bytes. */
|
||||
if( p->pKeyInfo->nAllField<=13 ){
|
||||
if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
|
||||
int flags = p->aMem[0].flags;
|
||||
if( p->pKeyInfo->aSortOrder[0] ){
|
||||
p->r1 = 1;
|
||||
@@ -4708,7 +4689,7 @@ void sqlite3VdbePreUpdateHook(
|
||||
preupdate.iNewReg = iReg;
|
||||
preupdate.keyinfo.db = db;
|
||||
preupdate.keyinfo.enc = ENC(db);
|
||||
preupdate.keyinfo.nKeyField = pTab->nCol;
|
||||
preupdate.keyinfo.nField = pTab->nCol;
|
||||
preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
|
||||
preupdate.iKey1 = iKey1;
|
||||
preupdate.iKey2 = iKey2;
|
||||
@@ -4718,8 +4699,8 @@ void sqlite3VdbePreUpdateHook(
|
||||
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
|
||||
db->pPreUpdate = 0;
|
||||
sqlite3DbFree(db, preupdate.aRecord);
|
||||
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
|
||||
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
|
||||
vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked);
|
||||
vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked);
|
||||
if( preupdate.aNew ){
|
||||
int i;
|
||||
for(i=0; i<pCsr->nField; i++){
|
||||
|
||||
+21
-17
@@ -129,8 +129,8 @@ int sqlite3_blob_open(
|
||||
int rc = SQLITE_OK;
|
||||
char *zErr = 0;
|
||||
Table *pTab;
|
||||
Parse *pParse = 0;
|
||||
Incrblob *pBlob = 0;
|
||||
Parse sParse;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppBlob==0 ){
|
||||
@@ -148,34 +148,37 @@ int sqlite3_blob_open(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
|
||||
if( !pBlob ) goto blob_open_out;
|
||||
pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
|
||||
if( !pParse ) goto blob_open_out;
|
||||
|
||||
do {
|
||||
memset(&sParse, 0, sizeof(Parse));
|
||||
if( !pBlob ) goto blob_open_out;
|
||||
sParse.db = db;
|
||||
memset(pParse, 0, sizeof(Parse));
|
||||
pParse->db = db;
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = 0;
|
||||
|
||||
sqlite3BtreeEnterAll(db);
|
||||
pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
|
||||
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
|
||||
if( pTab && IsVirtual(pTab) ){
|
||||
pTab = 0;
|
||||
sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
|
||||
sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
|
||||
}
|
||||
if( pTab && !HasRowid(pTab) ){
|
||||
pTab = 0;
|
||||
sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
|
||||
sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
if( pTab && pTab->pSelect ){
|
||||
pTab = 0;
|
||||
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
|
||||
sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
|
||||
}
|
||||
#endif
|
||||
if( !pTab ){
|
||||
if( sParse.zErrMsg ){
|
||||
if( pParse->zErrMsg ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sParse.zErrMsg;
|
||||
sParse.zErrMsg = 0;
|
||||
zErr = pParse->zErrMsg;
|
||||
pParse->zErrMsg = 0;
|
||||
}
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
@@ -239,7 +242,7 @@ int sqlite3_blob_open(
|
||||
}
|
||||
}
|
||||
|
||||
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
|
||||
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
|
||||
assert( pBlob->pStmt || db->mallocFailed );
|
||||
if( pBlob->pStmt ){
|
||||
|
||||
@@ -312,10 +315,10 @@ int sqlite3_blob_open(
|
||||
aOp[1].p4.i = pTab->nCol+1;
|
||||
aOp[3].p2 = pTab->nCol;
|
||||
|
||||
sParse.nVar = 0;
|
||||
sParse.nMem = 1;
|
||||
sParse.nTab = 1;
|
||||
sqlite3VdbeMakeReady(v, &sParse);
|
||||
pParse->nVar = 0;
|
||||
pParse->nMem = 1;
|
||||
pParse->nTab = 1;
|
||||
sqlite3VdbeMakeReady(v, pParse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +340,8 @@ blob_open_out:
|
||||
}
|
||||
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParserReset(pParse);
|
||||
sqlite3StackFree(db, pParse);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
|
||||
+2
-2
@@ -1163,7 +1163,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
if( pRec ){
|
||||
pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
|
||||
if( pRec->pKeyInfo ){
|
||||
assert( pRec->pKeyInfo->nAllField==nCol );
|
||||
assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
|
||||
assert( pRec->pKeyInfo->enc==ENC(db) );
|
||||
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
|
||||
for(i=0; i<nCol; i++){
|
||||
@@ -1699,7 +1699,7 @@ int sqlite3Stat4Column(
|
||||
void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
|
||||
if( pRec ){
|
||||
int i;
|
||||
int nCol = pRec->pKeyInfo->nAllField;
|
||||
int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
|
||||
Mem *aMem = pRec->aMem;
|
||||
sqlite3 *db = aMem[0].db;
|
||||
for(i=0; i<nCol; i++){
|
||||
|
||||
+8
-7
@@ -823,7 +823,7 @@ static int vdbeSorterCompareText(
|
||||
}
|
||||
|
||||
if( res==0 ){
|
||||
if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
|
||||
if( pTask->pSorter->pKeyInfo->nField>1 ){
|
||||
res = vdbeSorterCompareTail(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
@@ -892,7 +892,7 @@ static int vdbeSorterCompareInt(
|
||||
}
|
||||
|
||||
if( res==0 ){
|
||||
if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
|
||||
if( pTask->pSorter->pKeyInfo->nField>1 ){
|
||||
res = vdbeSorterCompareTail(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
@@ -907,7 +907,7 @@ static int vdbeSorterCompareInt(
|
||||
/*
|
||||
** Initialize the temporary index cursor just opened as a sorter cursor.
|
||||
**
|
||||
** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
|
||||
** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
|
||||
** to determine the number of fields that should be compared from the
|
||||
** records being sorted. However, if the value passed as argument nField
|
||||
** is non-zero and the sorter is able to guarantee a stable sort, nField
|
||||
@@ -960,7 +960,7 @@ int sqlite3VdbeSorterInit(
|
||||
|
||||
assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
|
||||
assert( pCsr->eCurType==CURTYPE_SORTER );
|
||||
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
|
||||
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
|
||||
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
|
||||
|
||||
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
|
||||
@@ -972,7 +972,8 @@ int sqlite3VdbeSorterInit(
|
||||
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
|
||||
pKeyInfo->db = 0;
|
||||
if( nField && nWorker==0 ){
|
||||
pKeyInfo->nKeyField = nField;
|
||||
pKeyInfo->nXField += (pKeyInfo->nField - nField);
|
||||
pKeyInfo->nField = nField;
|
||||
}
|
||||
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
|
||||
pSorter->nTask = nWorker + 1;
|
||||
@@ -1012,7 +1013,7 @@ int sqlite3VdbeSorterInit(
|
||||
}
|
||||
}
|
||||
|
||||
if( pKeyInfo->nAllField<13
|
||||
if( (pKeyInfo->nField+pKeyInfo->nXField)<13
|
||||
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
|
||||
){
|
||||
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
|
||||
@@ -1327,7 +1328,7 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
|
||||
if( pTask->pUnpacked==0 ){
|
||||
pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
|
||||
if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
|
||||
pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
|
||||
pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
|
||||
pTask->pUnpacked->errCode = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
+48
-42
@@ -733,10 +733,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
||||
*/
|
||||
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
VtabCtx *pCtx;
|
||||
Parse *pParse;
|
||||
int rc = SQLITE_OK;
|
||||
Table *pTab;
|
||||
char *zErr = 0;
|
||||
Parse sParse;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
|
||||
@@ -753,49 +753,55 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pTab = pCtx->pTab;
|
||||
assert( IsVirtual(pTab) );
|
||||
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.declareVtab = 1;
|
||||
sParse.db = db;
|
||||
sParse.nQueryLoop = 1;
|
||||
if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
|
||||
&& sParse.pNewTable
|
||||
&& !db->mallocFailed
|
||||
&& !sParse.pNewTable->pSelect
|
||||
&& !IsVirtual(sParse.pNewTable)
|
||||
){
|
||||
if( !pTab->aCol ){
|
||||
Table *pNew = sParse.pNewTable;
|
||||
Index *pIdx;
|
||||
pTab->aCol = pNew->aCol;
|
||||
pTab->nCol = pNew->nCol;
|
||||
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
|
||||
pNew->nCol = 0;
|
||||
pNew->aCol = 0;
|
||||
assert( pTab->pIndex==0 );
|
||||
if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
pIdx = pNew->pIndex;
|
||||
if( pIdx ){
|
||||
assert( pIdx->pNext==0 );
|
||||
pTab->pIndex = pIdx;
|
||||
pNew->pIndex = 0;
|
||||
pIdx->pTable = pTab;
|
||||
}
|
||||
}
|
||||
pCtx->bDeclared = 1;
|
||||
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
||||
if( pParse==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
}else{
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
rc = SQLITE_ERROR;
|
||||
pParse->declareVtab = 1;
|
||||
pParse->db = db;
|
||||
pParse->nQueryLoop = 1;
|
||||
|
||||
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
|
||||
&& pParse->pNewTable
|
||||
&& !db->mallocFailed
|
||||
&& !pParse->pNewTable->pSelect
|
||||
&& !IsVirtual(pParse->pNewTable)
|
||||
){
|
||||
if( !pTab->aCol ){
|
||||
Table *pNew = pParse->pNewTable;
|
||||
Index *pIdx;
|
||||
pTab->aCol = pNew->aCol;
|
||||
pTab->nCol = pNew->nCol;
|
||||
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
|
||||
pNew->nCol = 0;
|
||||
pNew->aCol = 0;
|
||||
assert( pTab->pIndex==0 );
|
||||
if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
pIdx = pNew->pIndex;
|
||||
if( pIdx ){
|
||||
assert( pIdx->pNext==0 );
|
||||
pTab->pIndex = pIdx;
|
||||
pNew->pIndex = 0;
|
||||
pIdx->pTable = pTab;
|
||||
}
|
||||
}
|
||||
pCtx->bDeclared = 1;
|
||||
}else{
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
pParse->declareVtab = 0;
|
||||
|
||||
if( pParse->pVdbe ){
|
||||
sqlite3VdbeFinalize(pParse->pVdbe);
|
||||
}
|
||||
sqlite3DeleteTable(db, pParse->pNewTable);
|
||||
sqlite3ParserReset(pParse);
|
||||
sqlite3StackFree(db, pParse);
|
||||
}
|
||||
sParse.declareVtab = 0;
|
||||
|
||||
if( sParse.pVdbe ){
|
||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
}
|
||||
sqlite3DeleteTable(db, sParse.pNewTable);
|
||||
sqlite3ParserReset(&sParse);
|
||||
|
||||
assert( (rc&0xff)==rc );
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# 2015-11-07
|
||||
#
|
||||
# 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 file is testing the WITH clause.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix atomic
|
||||
|
||||
db close
|
||||
if {[atomic_batch_write test.db]==0} {
|
||||
puts "No f2fs atomic-batch-write support. Skipping tests..."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
reset_db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
|
||||
do_test 1.1 { file exists test.db-journal } {0}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+8
-3
@@ -374,9 +374,8 @@ do_test attach2-6.1 {
|
||||
do_test attach2-6.2 {
|
||||
catchsql {
|
||||
ATTACH 'test3.db' as aux2;
|
||||
DETACH aux2;
|
||||
}
|
||||
} {0 {}}
|
||||
} {1 {cannot ATTACH database within transaction}}
|
||||
|
||||
# EVIDENCE-OF: R-59740-55581 This statement will fail if SQLite is in
|
||||
# the middle of a transaction.
|
||||
@@ -385,7 +384,13 @@ do_test attach2-6.3 {
|
||||
catchsql {
|
||||
DETACH aux;
|
||||
}
|
||||
} {0 {}}
|
||||
} {1 {cannot DETACH database within transaction}}
|
||||
do_test attach2-6.4 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
DETACH aux;
|
||||
}
|
||||
} {}
|
||||
|
||||
db close
|
||||
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
# 2017 August 07
|
||||
#
|
||||
# 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 testing the ability of SQLite to use mmap
|
||||
# to access files larger than 4GiB.
|
||||
#
|
||||
|
||||
if {[file exists skip-big-file]} return
|
||||
if {$tcl_platform(os)=="Darwin"} return
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bigmmap
|
||||
|
||||
ifcapable !mmap {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set mmap_limit 0
|
||||
db eval {
|
||||
SELECT compile_options AS x FROM pragma_compile_options
|
||||
WHERE x LIKE 'max_mmap_size=%'
|
||||
} {
|
||||
regexp {MAX_MMAP_SIZE=([0-9]*)} $x -> mmap_limit
|
||||
}
|
||||
if {$mmap_limit < [expr 8 * 1<<30]} {
|
||||
puts "Skipping bigmmap.test - requires SQLITE_MAX_MMAP_SIZE >= 8G"
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Create the database file roughly 8GiB in size. Most pages are unused,
|
||||
# except that there is a table and index clustered around each 1GiB
|
||||
# boundary.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 4096;
|
||||
CREATE TABLE t0(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
|
||||
INSERT INTO t0 SELECT i, 't0', randomblob(800) FROM s;
|
||||
}
|
||||
|
||||
for {set i 1} {$i < 8} {incr i} {
|
||||
fake_big_file [expr $i*1024] [get_pwd]/test.db
|
||||
hexio_write test.db 28 [format %.8x [expr ($i*1024*1024*1024/4096) - 5]]
|
||||
|
||||
do_execsql_test 1.$i "
|
||||
CREATE TABLE t$i (a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
|
||||
INSERT INTO t$i SELECT i, 't$i', randomblob(800) FROM s;
|
||||
"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that data can be retrieved from the db with a variety of
|
||||
# configured mmap size limits.
|
||||
#
|
||||
for {set i 0} {$i < 9} {incr i} {
|
||||
|
||||
# Configure a memory mapping $i GB in size.
|
||||
#
|
||||
set val [expr $i*1024*1024*1024]
|
||||
execsql "PRAGMA main.mmap_size = $val"
|
||||
do_execsql_test 2.$i.0 {
|
||||
PRAGMA main.mmap_size
|
||||
} $val
|
||||
|
||||
for {set t 0} {$t < 8} {incr t} {
|
||||
do_execsql_test 2.$i.$t.1 "
|
||||
SELECT count(*) FROM t$t;
|
||||
SELECT count(b || c) FROM t$t GROUP BY b;
|
||||
" {100 100}
|
||||
|
||||
do_execsql_test 2.$i.$t.2 "
|
||||
SELECT * FROM t$t AS o WHERE
|
||||
NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
|
||||
ORDER BY b, c;
|
||||
" {}
|
||||
|
||||
do_eqp_test 2.$i.$t.3 "
|
||||
SELECT * FROM t$t AS o WHERE
|
||||
NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
|
||||
ORDER BY b, c;
|
||||
" "
|
||||
0 0 0 {SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1}
|
||||
0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1}
|
||||
1 0 0 {SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-54
@@ -13,6 +13,7 @@
|
||||
# The focus of this file is testing how SQLite generates the names
|
||||
# of columns in a result set.
|
||||
#
|
||||
# $Id: colname.test,v 1.7 2009/06/02 15:47:38 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -325,58 +326,4 @@ do_test colname-8.1 {
|
||||
}
|
||||
} {123}
|
||||
|
||||
# 2017-07-29: Interaction between column naming and query flattening.
|
||||
# For years now, the query flattener has inserted AS clauses on the
|
||||
# outer query that were the original SQL text of the column. This caused
|
||||
# column-name shifts when the query flattener was enhanced, breaking
|
||||
# legacy applications. See https://sqlite.org/src/info/41c27bc0ff1d3135
|
||||
# for details.
|
||||
#
|
||||
# To fix this, the column naming logic was moved ahead of the query
|
||||
# flattener so that column names are assigned before the query flattener
|
||||
# runs.
|
||||
#
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
do_test colname-9.100 {
|
||||
db eval {
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
CREATE VIEW v1(x,y) AS SELECT a,b FROM t1;
|
||||
}
|
||||
execsql2 {SELECT v1.x, (Y) FROM v1}
|
||||
# Prior to the fix, this would return: "v1.x 1 (Y) 2"
|
||||
} {x 1 y 2}
|
||||
do_test colname-9.110 {
|
||||
execsql2 {SELECT * FROM v1}
|
||||
} {x 1 y 2}
|
||||
do_test colname-9.120 {
|
||||
db eval {
|
||||
CREATE VIEW v2(x,y) AS SELECT a,b FROM t1 LIMIT 10;
|
||||
}
|
||||
execsql2 {SELECT * FROM v2 WHERE 1}
|
||||
} {x 1 y 2}
|
||||
do_test colname-9.130 {
|
||||
execsql2 {SELECT v2.x, [v2].[y] FROM v2 WHERE 1}
|
||||
} {x 1 y 2}
|
||||
do_test colname-9.140 {
|
||||
execsql2 {SELECT +x, +y FROM v2 WHERE 1}
|
||||
} {+x 1 +y 2}
|
||||
|
||||
do_test colname-9.200 {
|
||||
db eval {
|
||||
CREATE TABLE t2(c,d);
|
||||
INSERT INTO t2 VALUES(3,4);
|
||||
CREATE VIEW v3 AS SELECT c AS a, d AS b FROM t2;
|
||||
}
|
||||
execsql2 {SELECT t1.a, v3.a AS n FROM t1 LEFT JOIN v3}
|
||||
} {a 1 n 3}
|
||||
do_test colname-9.211 {
|
||||
execsql2 {SELECT t1.a AS n, v3.a FROM t1 JOIN v3}
|
||||
} {n 1 a 3}
|
||||
do_test colname-9.210 {
|
||||
execsql2 {SELECT t1.a, v3.a AS n FROM t1 JOIN v3}
|
||||
} {a 1 n 3}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-3
@@ -59,9 +59,7 @@ do_test fallocate-1.6 {
|
||||
#
|
||||
do_test fallocate-1.7 {
|
||||
execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
|
||||
if {[permutation] != "inmemory_journal"
|
||||
&& [permutation] != "atomic-batch-write"
|
||||
} {
|
||||
if {[permutation] != "inmemory_journal"} {
|
||||
hexio_get_int [hexio_read test.db-journal 16 4]
|
||||
} else {
|
||||
set {} 1024
|
||||
|
||||
+20
-22
@@ -479,28 +479,26 @@ ifcapable curdir {
|
||||
# Make sure a database connection still works after changing the
|
||||
# working directory.
|
||||
#
|
||||
if {[atomic_batch_write test.db]==0} {
|
||||
do_test misc1-14.1 {
|
||||
file mkdir tempdir
|
||||
cd tempdir
|
||||
execsql {BEGIN}
|
||||
file exists ./test.db-journal
|
||||
} {0}
|
||||
do_test misc1-14.2a {
|
||||
execsql {UPDATE t1 SET a=a||'x' WHERE 0}
|
||||
file exists ../test.db-journal
|
||||
} {0}
|
||||
do_test misc1-14.2b {
|
||||
execsql {UPDATE t1 SET a=a||'y' WHERE 1}
|
||||
file exists ../test.db-journal
|
||||
} {1}
|
||||
do_test misc1-14.3 {
|
||||
cd ..
|
||||
forcedelete tempdir
|
||||
execsql {COMMIT}
|
||||
file exists ./test.db-journal
|
||||
} {0}
|
||||
}
|
||||
do_test misc1-14.1 {
|
||||
file mkdir tempdir
|
||||
cd tempdir
|
||||
execsql {BEGIN}
|
||||
file exists ./test.db-journal
|
||||
} {0}
|
||||
do_test misc1-14.2a {
|
||||
execsql {UPDATE t1 SET a=a||'x' WHERE 0}
|
||||
file exists ../test.db-journal
|
||||
} {0}
|
||||
do_test misc1-14.2b {
|
||||
execsql {UPDATE t1 SET a=a||'y' WHERE 1}
|
||||
file exists ../test.db-journal
|
||||
} {1}
|
||||
do_test misc1-14.3 {
|
||||
cd ..
|
||||
forcedelete tempdir
|
||||
execsql {COMMIT}
|
||||
file exists ./test.db-journal
|
||||
} {0}
|
||||
}
|
||||
|
||||
# A failed create table should not leave the table in the internal
|
||||
|
||||
@@ -70,28 +70,6 @@ static int progress_handler(void *pClientData) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and
|
||||
** "PRAGMA parser_trace" since they can dramatically increase the
|
||||
** amount of output without actually testing anything useful.
|
||||
*/
|
||||
static int block_debug_pragmas(
|
||||
void *Notused,
|
||||
int eCode,
|
||||
const char *zArg1,
|
||||
const char *zArg2,
|
||||
const char *zArg3,
|
||||
const char *zArg4
|
||||
){
|
||||
if( eCode==SQLITE_PRAGMA
|
||||
&& (sqlite3_strnicmp("vdbe_", zArg1, 5)==0
|
||||
|| sqlite3_stricmp("parser_trace", zArg1)==0)
|
||||
){
|
||||
return SQLITE_DENY;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Callback for sqlite3_exec().
|
||||
*/
|
||||
@@ -150,9 +128,6 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc);
|
||||
uSelector >>= 1;
|
||||
|
||||
/* Do not allow debugging pragma statements that might cause excess output */
|
||||
sqlite3_set_authorizer(cx.db, block_debug_pragmas, 0);
|
||||
|
||||
/* Remaining bits of the selector determine a limit on the number of
|
||||
** output rows */
|
||||
execCnt = uSelector + 1;
|
||||
|
||||
@@ -389,30 +389,6 @@ test_suite "vfslog" -prefix "" -description {
|
||||
wal* mmap*
|
||||
]
|
||||
|
||||
test_suite "atomic-batch-write" -prefix "" -description {
|
||||
Like veryquick.test, but must be run on a file-system that supports
|
||||
atomic-batch-writes. Tests that depend on the journal file being present
|
||||
are omitted.
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \
|
||||
*fts5corrupt* *fts5big* *fts5aj* \
|
||||
crash8.test delete_db.test \
|
||||
exclusive.test journal3.test \
|
||||
journal1.test \
|
||||
jrnlmode.test jrnlmode2.test \
|
||||
lock4.test pager1.test \
|
||||
pager3.test sharedA.test \
|
||||
symlink.test stmt.test \
|
||||
sync.test sync2.test \
|
||||
tempdb.test tkt3457.test \
|
||||
vacuum5.test wal2.test \
|
||||
walmode.test zerodamage.test
|
||||
] -initialize {
|
||||
if {[atomic_batch_write test.db]==0} {
|
||||
error "File system does NOT support atomic-batch-write"
|
||||
}
|
||||
}
|
||||
|
||||
lappend ::testsuitelist xxx
|
||||
#-------------------------------------------------------------------------
|
||||
# Define the coverage related test suites:
|
||||
|
||||
@@ -82,7 +82,6 @@ do_test rollback-1.9 {
|
||||
if {$tcl_platform(platform) == "unix"
|
||||
&& [permutation] ne "onefile"
|
||||
&& [permutation] ne "inmemory_journal"
|
||||
&& [permutation] ne "atomic-batch-write"
|
||||
} {
|
||||
do_test rollback-2.1 {
|
||||
execsql {
|
||||
|
||||
+2
-7
@@ -616,16 +616,12 @@ ifcapable auth {
|
||||
# First make sure it is not possible to attach or detach a database while
|
||||
# a savepoint is open (it is not possible if any transaction is open).
|
||||
#
|
||||
# UPDATE 2017-07-26: It is not possible to ATTACH and DETACH within a
|
||||
# a transaction.
|
||||
#
|
||||
do_test savepoint-10.1.1 {
|
||||
catchsql {
|
||||
SAVEPOINT one;
|
||||
ATTACH 'test2.db' AS aux;
|
||||
DETACH aux;
|
||||
}
|
||||
} {0 {}}
|
||||
} {1 {cannot ATTACH database within transaction}}
|
||||
do_test savepoint-10.1.2 {
|
||||
execsql {
|
||||
RELEASE one;
|
||||
@@ -634,9 +630,8 @@ do_test savepoint-10.1.2 {
|
||||
catchsql {
|
||||
SAVEPOINT one;
|
||||
DETACH aux;
|
||||
ATTACH 'test2.db' AS aux;
|
||||
}
|
||||
} {0 {}}
|
||||
} {1 {cannot DETACH database within transaction}}
|
||||
do_test savepoint-10.1.3 {
|
||||
execsql {
|
||||
RELEASE one;
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
# 2017-07-30
|
||||
#
|
||||
# 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 tests to show that certain CREATE TABLE statements
|
||||
# generate identical database files. For example, changes in identifier
|
||||
# names, white-space, and formatting of the CREATE TABLE statement should
|
||||
# produce identical table content.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix schema6
|
||||
|
||||
# Command: check_same_database_content TESTNAME SQL1 SQL2 SQL3 ...
|
||||
#
|
||||
# This command creates fresh databases using SQL1 and subsequent arguments
|
||||
# and checks to make sure the content of all database files is byte-for-byte
|
||||
# identical. Page 1 of the database files is allowed to be different, since
|
||||
# page 1 contains the sqlite_master table which is expected to vary.
|
||||
#
|
||||
proc check_same_database_content {basename args} {
|
||||
set i 0
|
||||
set hash {}
|
||||
foreach sql $args {
|
||||
catch {db close}
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval $sql
|
||||
set pgsz [db one {PRAGMA page_size}]
|
||||
db close
|
||||
set sz [file size test.db]
|
||||
set thishash [md5file test.db $pgsz [expr {$sz-$pgsz}]]
|
||||
if {$i==0} {
|
||||
set hash $thishash
|
||||
} else {
|
||||
do_test $basename-$i "set x $thishash" $hash
|
||||
}
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
# Command: check_different_database_content TESTNAME SQL1 SQL2 SQL3 ...
|
||||
#
|
||||
# This command creates fresh databases using SQL1 and subsequent arguments
|
||||
# and checks to make sure the content of all database files is different
|
||||
# in ways other than on page 1.
|
||||
#
|
||||
proc check_different_database_content {basename args} {
|
||||
set i 0
|
||||
set hashes {}
|
||||
foreach sql $args {
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval $sql
|
||||
set pgsz [db one {PRAGMA page_size}]
|
||||
db close
|
||||
set sz [file size test.db]
|
||||
set thishash [md5file test.db $pgsz [expr {$sz-$pgsz}]]
|
||||
set j [lsearch $hashes $thishash]
|
||||
if {$j>=0} {
|
||||
do_test $basename-$i "set x {$i is the same as $j}" "All are different"
|
||||
} else {
|
||||
do_test $basename-$i "set x {All are different}" "All are different"
|
||||
}
|
||||
lappend hashes $thishash
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
check_same_database_content 100 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(xyz INTEGER, abc, PRIMARY KEY(xyz), UNIQUE(abc));
|
||||
INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(xyz INTEGER, abc, UNIQUE(abc), PRIMARY KEY(xyz));
|
||||
INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY ASC, b UNIQUE);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||
}
|
||||
|
||||
check_same_database_content 110 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE, UNIQUE(a));
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b);
|
||||
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||
}
|
||||
|
||||
check_same_database_content 120 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(xyz INTEGER, abc, PRIMARY KEY(xyz), UNIQUE(abc))WITHOUT ROWID;
|
||||
INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(xyz INTEGER, abc, UNIQUE(abc), PRIMARY KEY(xyz))WITHOUT ROWID;
|
||||
INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY ASC, b UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE, UNIQUE(a))
|
||||
WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
|
||||
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
CREATE UNIQUE INDEX t1b ON t1(b);
|
||||
}
|
||||
|
||||
check_different_database_content 130 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE);
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
} {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -1,246 +0,0 @@
|
||||
# 2017-07-15
|
||||
#
|
||||
# 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 file is the "swarmvtab" extension
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix swarmvtab
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
load_static_extension db unionvtab
|
||||
|
||||
set nFile $sqlite_open_file_count
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t0(a INTEGER PRIMARY KEY, b TEXT);
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<400)
|
||||
INSERT INTO t0 SELECT i, hex(randomblob(50)) FROM s;
|
||||
|
||||
CREATE TABLE dir(f, t, imin, imax);
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
for {set i 0} {$i < 40} {incr i} {
|
||||
set iMin [expr $i*10 + 1]
|
||||
set iMax [expr $iMin+9]
|
||||
|
||||
forcedelete "test.db$i"
|
||||
execsql [subst {
|
||||
ATTACH 'test.db$i' AS aux;
|
||||
CREATE TABLE aux.t$i (a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO aux.t$i SELECT * FROM t0 WHERE a BETWEEN $iMin AND $iMax;
|
||||
DETACH aux;
|
||||
INSERT INTO dir VALUES('test.db$i', 't$i', $iMin, $iMax);
|
||||
}]
|
||||
}
|
||||
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE temp.s1 USING swarmvtab('SELECT * FROM dir');
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
DROP TABLE s1;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
CREATE VIRTUAL TABLE temp.s1 USING swarmvtab('SELECT * FROM dir');
|
||||
SELECT count(*) FROM s1 WHERE rowid<50;
|
||||
} {49}
|
||||
|
||||
proc do_compare_test {tn where} {
|
||||
set sql [subst {
|
||||
SELECT (SELECT group_concat(a || ',' || b, ',') FROM t0 WHERE $where)
|
||||
IS
|
||||
(SELECT group_concat(a || ',' || b, ',') FROM s1 WHERE $where)
|
||||
}]
|
||||
|
||||
uplevel [list do_execsql_test $tn $sql 1]
|
||||
}
|
||||
|
||||
do_compare_test 1.4.1 "rowid = 700"
|
||||
do_compare_test 1.4.2 "rowid = -1"
|
||||
do_compare_test 1.4.3 "rowid = 0"
|
||||
do_compare_test 1.4.4 "rowid = 55"
|
||||
do_compare_test 1.4.5 "rowid BETWEEN 20 AND 100"
|
||||
do_compare_test 1.4.6 "rowid > 350"
|
||||
do_compare_test 1.4.7 "rowid >= 350"
|
||||
do_compare_test 1.4.8 "rowid >= 200"
|
||||
do_compare_test 1.4.9 "1"
|
||||
|
||||
# Multiple simultaneous cursors.
|
||||
#
|
||||
do_execsql_test 1.5.1.(5-seconds-or-so) {
|
||||
SELECT count(*) FROM s1 a, s1 b WHERE b.rowid<=200;
|
||||
} {80000}
|
||||
do_execsql_test 1.5.2 {
|
||||
SELECT count(*) FROM s1 a, s1 b, s1 c
|
||||
WHERE a.rowid=b.rowid AND b.rowid=c.rowid;
|
||||
} {400}
|
||||
|
||||
# Empty source tables.
|
||||
#
|
||||
do_test 1.6.0 {
|
||||
for {set i 0} {$i < 20} {incr i} {
|
||||
sqlite3 db2 test.db$i
|
||||
db2 eval " DELETE FROM t$i "
|
||||
db2 close
|
||||
}
|
||||
db eval { DELETE FROM t0 WHERE rowid<=200 }
|
||||
} {}
|
||||
|
||||
do_compare_test 1.6.1 "rowid = 700"
|
||||
do_compare_test 1.6.2 "rowid = -1"
|
||||
do_compare_test 1.6.3 "rowid = 0"
|
||||
do_compare_test 1.6.4 "rowid = 55"
|
||||
do_compare_test 1.6.5 "rowid BETWEEN 20 AND 100"
|
||||
do_compare_test 1.6.6 "rowid > 350"
|
||||
do_compare_test 1.6.7 "rowid >= 350"
|
||||
do_compare_test 1.6.8 "rowid >= 200"
|
||||
do_compare_test 1.6.9 "1"
|
||||
do_compare_test 1.6.10 "rowid >= 5"
|
||||
|
||||
do_test 1.x {
|
||||
set sqlite_open_file_count
|
||||
} [expr $nFile+9]
|
||||
|
||||
do_test 1.y { db close } {}
|
||||
|
||||
# Delete all the database files created above.
|
||||
#
|
||||
for {set i 0} {$i < 40} {incr i} { forcedelete "test.db$i" }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test some error conditions:
|
||||
#
|
||||
# 2.1: Database file does not exist.
|
||||
# 2.2: Table does not exist.
|
||||
# 2.3: Table schema does not match.
|
||||
# 2.4: Syntax error in SELECT statement.
|
||||
#
|
||||
reset_db
|
||||
load_static_extension db unionvtab
|
||||
do_test 2.0.1 {
|
||||
db eval {
|
||||
CREATE TABLE t0(a INTEGER PRIMARY KEY, b TEXT);
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<400)
|
||||
INSERT INTO t0 SELECT i, hex(randomblob(50)) FROM s;
|
||||
CREATE TABLE dir(f, t, imin, imax);
|
||||
}
|
||||
|
||||
for {set i 0} {$i < 40} {incr i} {
|
||||
set iMin [expr $i*10 + 1]
|
||||
set iMax [expr $iMin+9]
|
||||
|
||||
forcedelete "test.db$i"
|
||||
db eval [subst {
|
||||
ATTACH 'test.db$i' AS aux;
|
||||
CREATE TABLE aux.t$i (a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO aux.t$i SELECT * FROM t0 WHERE a BETWEEN $iMin AND $iMax;
|
||||
DETACH aux;
|
||||
INSERT INTO dir VALUES('test.db$i', 't$i', $iMin, $iMax);
|
||||
}]
|
||||
}
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE temp.s1 USING swarmvtab('SELECT * FROM dir');
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 2.0.2 {
|
||||
forcedelete test.db5
|
||||
|
||||
sqlite3 db2 test.db15
|
||||
db2 eval { DROP TABLE t15 }
|
||||
db2 close
|
||||
|
||||
sqlite3 db2 test.db25
|
||||
db2 eval {
|
||||
DROP TABLE t25;
|
||||
CREATE TABLE t25(x, y, z PRIMARY KEY);
|
||||
}
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
do_catchsql_test 2.1 {
|
||||
SELECT * FROM s1 WHERE rowid BETWEEN 1 AND 100;
|
||||
} {1 {unable to open database file}}
|
||||
do_catchsql_test 2.2 {
|
||||
SELECT * FROM s1 WHERE rowid BETWEEN 101 AND 200;
|
||||
} {1 {no such rowid table: t15}}
|
||||
do_catchsql_test 2.3 {
|
||||
SELECT * FROM s1 WHERE rowid BETWEEN 201 AND 300;
|
||||
} {1 {source table schema mismatch}}
|
||||
|
||||
do_catchsql_test 2.4 {
|
||||
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab('SELECT * FROMdir');
|
||||
} {1 {sql error: near "FROMdir": syntax error}}
|
||||
do_catchsql_test 2.5 {
|
||||
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab('SELECT * FROMdir', 'fetchdb');
|
||||
} {1 {sql error: near "FROMdir": syntax error}}
|
||||
|
||||
for {set i 0} {$i < 40} {incr i} {
|
||||
forcedelete "test.db$i"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the outcome of the fetch function throwing an exception.
|
||||
#
|
||||
proc fetch_db {file} {
|
||||
error "fetch_db error!"
|
||||
}
|
||||
|
||||
db func fetch_db fetch_db
|
||||
|
||||
do_catchsql_test 3.1 {
|
||||
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
|
||||
'VALUES
|
||||
("test.db1", "t1", 1, 10),
|
||||
("test.db2", "t1", 11, 20)
|
||||
', 'fetch_db_no_such_function'
|
||||
);
|
||||
} {1 {no such function: fetch_db_no_such_function}}
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
|
||||
'VALUES
|
||||
("test.db1", "t1", 1, 10),
|
||||
("test.db2", "t1", 11, 20)
|
||||
', 'fetch_db'
|
||||
);
|
||||
} {1 {fetch_db error!}}
|
||||
|
||||
do_execsql_test 3.3.1 {
|
||||
ATTACH 'test.db1' AS aux;
|
||||
CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO aux.t1 VALUES(1, NULL);
|
||||
INSERT INTO aux.t1 VALUES(2, NULL);
|
||||
INSERT INTO aux.t1 VALUES(9, NULL);
|
||||
DETACH aux;
|
||||
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
|
||||
'VALUES
|
||||
("test.db1", "t1", 1, 10),
|
||||
("test.db2", "t1", 11, 20)
|
||||
', 'fetch_db'
|
||||
);
|
||||
} {}
|
||||
|
||||
do_catchsql_test 3.3.2 { SELECT * FROM xyz } {1 {fetch_db error!}}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# 2017-07-15
|
||||
#
|
||||
# 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 file is the "swarmvtab" extension
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix swarmvtab
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
db close
|
||||
foreach name [glob -nocomplain test*.db] {
|
||||
forcedelete $name
|
||||
}
|
||||
sqlite3 db test.db
|
||||
load_static_extension db unionvtab
|
||||
proc create_database {filename} {
|
||||
sqlite3 dbx $filename
|
||||
set num [regsub -all {[^0-9]+} $filename {}]
|
||||
set num [string trimleft $num 0]
|
||||
set start [expr {$num*1000}]
|
||||
set end [expr {$start+999}]
|
||||
dbx eval {
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY,b);
|
||||
WITH RECURSIVE c(x) AS (
|
||||
VALUES($start) UNION ALL SELECT x+1 FROM c WHERE x<$end
|
||||
)
|
||||
INSERT INTO t2(a,b) SELECT x, printf('**%05d**',x) FROM c;
|
||||
}
|
||||
dbx close
|
||||
}
|
||||
db func create_database create_database
|
||||
do_execsql_test 100 {
|
||||
CREATE TABLE t1(filename, tablename, istart, iend);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<99)
|
||||
INSERT INTO t1 SELECT printf('test%03d.db',x),'t2',x*1000,x*1000+999 FROM c;
|
||||
CREATE VIRTUAL TABLE temp.v1 USING swarmvtab(
|
||||
'SELECT * FROM t1', 'create_database'
|
||||
);
|
||||
} {}
|
||||
do_execsql_test 110 {
|
||||
SELECT b FROM v1 WHERE a=3875;
|
||||
} {**03875**}
|
||||
do_test 120 {
|
||||
lsort [glob -nocomplain test?*.db]
|
||||
} {test001.db test003.db}
|
||||
do_execsql_test 130 {
|
||||
SELECT b FROM v1 WHERE a BETWEEN 3999 AND 4000 ORDER BY a;
|
||||
} {**03999** **04000**}
|
||||
do_test 140 {
|
||||
lsort [glob -nocomplain test?*.db]
|
||||
} {test001.db test003.db test004.db}
|
||||
do_execsql_test 150 {
|
||||
SELECT b FROM v1 WHERE a>=99998;
|
||||
} {**99998** **99999**}
|
||||
do_test 160 {
|
||||
lsort -dictionary [glob -nocomplain test?*.db]
|
||||
} {test001.db test003.db test004.db test099.db}
|
||||
|
||||
finish_test
|
||||
@@ -1,61 +0,0 @@
|
||||
# 2017-07-15
|
||||
#
|
||||
# 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 file is error handling in the swarmvtab extension.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix swarmvtabfault
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc fetch_db {file} {
|
||||
forcedelete $file
|
||||
sqlite3 dbX $file
|
||||
dbX eval { CREATE TABLE t1(a INTEGER PRIMARY KEY, b) }
|
||||
dbX close
|
||||
}
|
||||
|
||||
forcedelete test.db1
|
||||
do_execsql_test 1.0 {
|
||||
ATTACH 'test.db1' AS aux;
|
||||
CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO aux.t1 VALUES(1, NULL);
|
||||
INSERT INTO aux.t1 VALUES(2, NULL);
|
||||
INSERT INTO aux.t1 VALUES(9, NULL);
|
||||
DETACH aux;
|
||||
} {}
|
||||
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 1.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func fetch_db fetch_db
|
||||
load_static_extension db unionvtab
|
||||
db eval {
|
||||
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
|
||||
'VALUES
|
||||
("test.db1", "t1", 1, 10),
|
||||
("test.db2", "t1", 11, 20)
|
||||
', 'fetch_db'
|
||||
);
|
||||
}
|
||||
} -body {
|
||||
execsql { SELECT a FROM xyz }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 9}} {1 {sql error: out of memory}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ foreach s {
|
||||
fcntl read pread write pwrite fchmod fallocate
|
||||
pread64 pwrite64 unlink openDirectory mkdir rmdir
|
||||
statvfs fchown geteuid umask mmap munmap mremap
|
||||
getpagesize readlink lstat ioctl
|
||||
getpagesize readlink lstat
|
||||
} {
|
||||
if {[test_syscall exists $s]} {lappend syscall_list $s}
|
||||
}
|
||||
|
||||
@@ -1608,54 +1608,6 @@ proc crashsql {args} {
|
||||
lappend r $msg
|
||||
}
|
||||
|
||||
# crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL
|
||||
#
|
||||
proc crash_on_write {args} {
|
||||
|
||||
set nArg [llength $args]
|
||||
if {$nArg<2 || $nArg%2} {
|
||||
error "bad args: $args"
|
||||
}
|
||||
set zSql [lindex $args end]
|
||||
set nDelay [lindex $args end-1]
|
||||
|
||||
set devchar {}
|
||||
for {set ii 0} {$ii < $nArg-2} {incr ii 2} {
|
||||
set opt [lindex $args $ii]
|
||||
switch -- [lindex $args $ii] {
|
||||
-devchar {
|
||||
set devchar [lindex $args [expr $ii+1]]
|
||||
}
|
||||
|
||||
default { error "unrecognized option: $opt" }
|
||||
}
|
||||
}
|
||||
|
||||
set f [open crash.tcl w]
|
||||
puts $f "sqlite3_crash_on_write $nDelay"
|
||||
puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
|
||||
puts $f "sqlite3 db test.db -vfs writecrash"
|
||||
puts $f "db eval {$zSql}"
|
||||
puts $f "set {} {}"
|
||||
|
||||
close $f
|
||||
set r [catch {
|
||||
exec [info nameofexec] crash.tcl >@stdout
|
||||
} msg]
|
||||
|
||||
# Windows/ActiveState TCL returns a slightly different
|
||||
# error message. We map that to the expected message
|
||||
# so that we don't have to change all of the test
|
||||
# cases.
|
||||
if {$::tcl_platform(platform)=="windows"} {
|
||||
if {$msg=="child killed: unknown signal"} {
|
||||
set msg "child process exited abnormally"
|
||||
}
|
||||
}
|
||||
|
||||
lappend r $msg
|
||||
}
|
||||
|
||||
proc run_ioerr_prep {} {
|
||||
set ::sqlite_io_error_pending 0
|
||||
catch {db close}
|
||||
|
||||
@@ -67,18 +67,6 @@ do_faultsim_test 1.2 -faults oom* -prep {
|
||||
faultsim_test_result {0 {1 one 2 two 3 three 10 ten 11 eleven 12 twelve 20 twenty 21 twenty-one 22 twenty-two}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Error while registering the two vtab modules.
|
||||
do_faultsim_test 2.0 -faults * -prep {
|
||||
catch { db close }
|
||||
sqlite3 db :memory:
|
||||
} -body {
|
||||
load_static_extension db unionvtab
|
||||
} -test {
|
||||
faultsim_test_result {0 {}} {1 {initialization of unionvtab failed: }}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -158,17 +158,5 @@ do_test whereA-4.6 {
|
||||
}
|
||||
} {2 1 1}
|
||||
|
||||
# Ticket https://sqlite.org/src/tktview/cb91bf4290c211 2017-08-01
|
||||
# Assertion fault following PRAGMA reverse_unordered_selects=ON.
|
||||
#
|
||||
do_execsql_test whereA-5.1 {
|
||||
PRAGMA reverse_unordered_selects=on;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
SELECT a FROM t1 WHERE b=-99 OR b>1;
|
||||
} {1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -328,19 +328,5 @@ do_catchsql_test 7.3 {
|
||||
) WITHOUT ROWID;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# 2017-07-30: OSSFuzz discovered that an extra entry was being
|
||||
# added in the sqlite_master table for an "INTEGER PRIMARY KEY UNIQUE"
|
||||
# WITHOUT ROWID table. Make sure this has now been fixed.
|
||||
#
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY UNIQUE, b) WITHOUT ROWID;
|
||||
CREATE INDEX t1x ON t1(x);
|
||||
INSERT INTO t1(x,b) VALUES('funny','buffalo');
|
||||
SELECT type, name, '|' FROM sqlite_master;
|
||||
} {table t1 | index t1x |}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
# 2009 January 8
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test the outcome of a writer crashing within a call to the VFS
|
||||
# xWrite function.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix writecrash
|
||||
|
||||
do_not_use_codec
|
||||
|
||||
|
||||
if {$tcl_platform(platform)=="windows"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB UNIQUE);
|
||||
WITH s(i) AS (
|
||||
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO t1 SELECT NULL, randomblob(900) FROM s;
|
||||
} {}
|
||||
|
||||
set bGo 1
|
||||
for {set tn 1} {$bGo} {incr tn} {
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_test 1.$tn.1 {
|
||||
set res [crash_on_write $tn {
|
||||
UPDATE t1 SET b = randomblob(899) WHERE (a%3)==0
|
||||
}]
|
||||
set bGo 0
|
||||
if {[string match {1 {child killed:*}} $res]} {
|
||||
set res {0 {}}
|
||||
set bGo 1
|
||||
}
|
||||
set res
|
||||
} {0 {}}
|
||||
|
||||
#db close
|
||||
#sqlite3 db test.db
|
||||
|
||||
do_execsql_test 1.$tn.2 { PRAGMA integrity_check } {ok}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_execsql_test 1.$tn.3 { PRAGMA integrity_check } {ok}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -29,8 +29,6 @@ IF DEFINED PROCESSOR (
|
||||
GOTO usage
|
||||
)
|
||||
|
||||
SET PROCESSOR=%PROCESSOR:AMD64=x64%
|
||||
|
||||
%_VECHO% Processor = '%PROCESSOR%'
|
||||
|
||||
SET DUMMY2=%2
|
||||
|
||||
+7
-2
@@ -22,7 +22,14 @@ close $in
|
||||
# ILLEGAL *must* be the last two token codes and they must be in that order.
|
||||
#
|
||||
set extras {
|
||||
TO_TEXT
|
||||
TO_BLOB
|
||||
TO_NUMERIC
|
||||
TO_INT
|
||||
TO_REAL
|
||||
ISNOT
|
||||
END_OF_FILE
|
||||
UNCLOSED_STRING
|
||||
FUNCTION
|
||||
COLUMN
|
||||
AGG_FUNCTION
|
||||
@@ -35,8 +42,6 @@ set extras {
|
||||
IF_NULL_ROW
|
||||
ASTERISK
|
||||
SPAN
|
||||
END_OF_FILE
|
||||
UNCLOSED_STRING
|
||||
SPACE
|
||||
ILLEGAL
|
||||
}
|
||||
|
||||
+1
-24
@@ -2155,8 +2155,7 @@ enum e_state {
|
||||
WAITING_FOR_FALLBACK_ID,
|
||||
WAITING_FOR_WILDCARD_ID,
|
||||
WAITING_FOR_CLASS_ID,
|
||||
WAITING_FOR_CLASS_TOKEN,
|
||||
WAITING_FOR_TOKEN_NAME
|
||||
WAITING_FOR_CLASS_TOKEN
|
||||
};
|
||||
struct pstate {
|
||||
char *filename; /* Name of the input file */
|
||||
@@ -2471,8 +2470,6 @@ to follow the previous rule.");
|
||||
}else if( strcmp(x,"fallback")==0 ){
|
||||
psp->fallback = 0;
|
||||
psp->state = WAITING_FOR_FALLBACK_ID;
|
||||
}else if( strcmp(x,"token")==0 ){
|
||||
psp->state = WAITING_FOR_TOKEN_NAME;
|
||||
}else if( strcmp(x,"wildcard")==0 ){
|
||||
psp->state = WAITING_FOR_WILDCARD_ID;
|
||||
}else if( strcmp(x,"token_class")==0 ){
|
||||
@@ -2627,26 +2624,6 @@ to follow the previous rule.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WAITING_FOR_TOKEN_NAME:
|
||||
/* Tokens do not have to be declared before use. But they can be
|
||||
** in order to control their assigned integer number. The number for
|
||||
** each token is assigned when it is first seen. So by including
|
||||
**
|
||||
** %token ONE TWO THREE
|
||||
**
|
||||
** early in the grammar file, that assigns small consecutive values
|
||||
** to each of the tokens ONE TWO and THREE.
|
||||
*/
|
||||
if( x[0]=='.' ){
|
||||
psp->state = WAITING_FOR_DECL_OR_RULE;
|
||||
}else if( !ISUPPER(x[0]) ){
|
||||
ErrorMsg(psp->filename, psp->tokenlineno,
|
||||
"%%token argument \"%s\" should be a token", x);
|
||||
psp->errorcnt++;
|
||||
}else{
|
||||
(void)Symbol_new(x);
|
||||
}
|
||||
break;
|
||||
case WAITING_FOR_WILDCARD_ID:
|
||||
if( x[0]=='.' ){
|
||||
psp->state = WAITING_FOR_DECL_OR_RULE;
|
||||
|
||||
+9
-7
@@ -202,17 +202,19 @@ for {set i 0} {$i<=$max} {incr i} {
|
||||
set name $def($i)
|
||||
puts -nonewline [format {#define %-16s %3d} $name $i]
|
||||
set com {}
|
||||
if {$jump($name)} {
|
||||
lappend com "jump"
|
||||
}
|
||||
if {[info exists sameas($i)]} {
|
||||
lappend com "same as $sameas($i)"
|
||||
set com "same as $sameas($i)"
|
||||
}
|
||||
if {[info exists synopsis($name)]} {
|
||||
lappend com "synopsis: $synopsis($name)"
|
||||
set x $synopsis($name)
|
||||
if {$com==""} {
|
||||
set com "synopsis: $x"
|
||||
} else {
|
||||
append com ", synopsis: $x"
|
||||
}
|
||||
}
|
||||
if {[llength $com]} {
|
||||
puts -nonewline [format " /* %-42s */" [join $com {, }]]
|
||||
if {$com!=""} {
|
||||
puts -nonewline [format " /* %-42s */" $com]
|
||||
}
|
||||
puts ""
|
||||
}
|
||||
|
||||
@@ -224,8 +224,6 @@ proc copy_file {filename} {
|
||||
if {![info exists varonly_hdr($tail)]
|
||||
&& [regexp $declpattern $line all rettype funcname rest]} {
|
||||
regsub {^SQLITE_API } $line {} line
|
||||
regsub {^SQLITE_API } $rettype {} rettype
|
||||
|
||||
# Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
|
||||
# so that linkage can be modified at compile-time.
|
||||
if {[regexp {^sqlite3[a-z]*_} $funcname]} {
|
||||
|
||||
Reference in New Issue
Block a user