mirror of
https://github.com/php/php-src.git
synced 2025-08-20 01:14:28 +02:00
Upgrade bundled library to 2.8.14 + misc fixes
(http://www.sqlite.org/cvstrac/chngview?cn=1742)
This commit is contained in:
parent
cd732f1a3f
commit
e563b4eafa
43 changed files with 5953 additions and 5559 deletions
|
|
@ -33,8 +33,9 @@ typedef struct {
|
|||
** Fill the InitData structure with an error message that indicates
|
||||
** that the database is corrupt.
|
||||
*/
|
||||
static void corruptSchema(InitData *pData){
|
||||
sqliteSetString(pData->pzErrMsg, "malformed database schema", (char*)0);
|
||||
static void corruptSchema(InitData *pData, const char *zExtra){
|
||||
sqliteSetString(pData->pzErrMsg, "malformed database schema",
|
||||
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -54,36 +55,39 @@ static void corruptSchema(InitData *pData){
|
|||
static
|
||||
int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
|
||||
InitData *pData = (InitData*)pInit;
|
||||
Parse sParse;
|
||||
int nErr = 0;
|
||||
|
||||
assert( argc==5 );
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[0]==0 ){
|
||||
corruptSchema(pData);
|
||||
corruptSchema(pData, 0);
|
||||
return 1;
|
||||
}
|
||||
switch( argv[0][0] ){
|
||||
case 'v':
|
||||
case 'i':
|
||||
case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
|
||||
sqlite *db = pData->db;
|
||||
if( argv[2]==0 || argv[4]==0 ){
|
||||
corruptSchema(pData);
|
||||
corruptSchema(pData, 0);
|
||||
return 1;
|
||||
}
|
||||
if( argv[3] && argv[3][0] ){
|
||||
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
||||
** But because sParse.initFlag is set to 1, no VDBE code is generated
|
||||
** But because db->init.busy is set to 1, no VDBE code is generated
|
||||
** or executed. All the parser does is build the internal data
|
||||
** structures that describe the table, index, or view.
|
||||
*/
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = pData->db;
|
||||
sParse.initFlag = 1;
|
||||
sParse.iDb = atoi(argv[4]);
|
||||
sParse.newTnum = atoi(argv[2]);
|
||||
sParse.useCallback = 1;
|
||||
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
|
||||
char *zErr;
|
||||
assert( db->init.busy );
|
||||
db->init.iDb = atoi(argv[4]);
|
||||
assert( db->init.iDb>=0 && db->init.iDb<db->nDb );
|
||||
db->init.newTnum = atoi(argv[2]);
|
||||
if( sqlite_exec(db, argv[3], 0, 0, &zErr) ){
|
||||
corruptSchema(pData, zErr);
|
||||
sqlite_freemem(zErr);
|
||||
}
|
||||
db->init.iDb = 0;
|
||||
}else{
|
||||
/* If the SQL column is blank it means this is an index that
|
||||
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
|
||||
|
|
@ -95,8 +99,8 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
|
|||
Index *pIndex;
|
||||
|
||||
iDb = atoi(argv[4]);
|
||||
assert( iDb>=0 && iDb<pData->db->nDb );
|
||||
pIndex = sqliteFindIndex(pData->db, argv[1], pData->db->aDb[iDb].zName);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
pIndex = sqliteFindIndex(db, argv[1], db->aDb[iDb].zName);
|
||||
if( pIndex==0 || pIndex->tnum!=0 ){
|
||||
/* This can occur if there exists an index on a TEMP table which
|
||||
** has the same name as another index on a permanent index. Since
|
||||
|
|
@ -127,6 +131,9 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
|
|||
** format version 1 or 2 to version 3. The correct operation of
|
||||
** this routine relys on the fact that no indices are used when
|
||||
** copying a table out to a temporary file.
|
||||
**
|
||||
** The change from version 2 to version 3 occurred between SQLite
|
||||
** version 2.5.6 and 2.6.0 on 2002-July-18.
|
||||
*/
|
||||
static
|
||||
int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
|
|
@ -150,8 +157,8 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
|
|||
"DROP TABLE sqlite_x;",
|
||||
0, 0, &zErr, argv[0], argv[0], argv[0]);
|
||||
if( zErr ){
|
||||
sqliteSetString(pData->pzErrMsg, zErr, (char*)0);
|
||||
sqlite_freemem(zErr);
|
||||
if( *pData->pzErrMsg ) sqlite_freemem(*pData->pzErrMsg);
|
||||
*pData->pzErrMsg = zErr;
|
||||
}
|
||||
|
||||
/* If an error occurred in the SQL above, then the transaction will
|
||||
|
|
@ -185,7 +192,6 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
char *azArg[6];
|
||||
char zDbNum[30];
|
||||
int meta[SQLITE_N_BTREE_META];
|
||||
Parse sParse;
|
||||
InitData initData;
|
||||
|
||||
/*
|
||||
|
|
@ -242,6 +248,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
|
||||
/* Construct the schema tables: sqlite_master and sqlite_temp_master
|
||||
*/
|
||||
sqliteSafetyOff(db);
|
||||
azArg[0] = "table";
|
||||
azArg[1] = MASTER_NAME;
|
||||
azArg[2] = "2";
|
||||
|
|
@ -266,6 +273,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
pTab->readOnly = 1;
|
||||
}
|
||||
}
|
||||
sqliteSafetyOn(db);
|
||||
|
||||
/* Create a cursor to hold the database open
|
||||
*/
|
||||
|
|
@ -292,6 +300,9 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
if( size==0 ){ size = MAX_PAGES; }
|
||||
db->cache_size = size;
|
||||
db->safety_level = meta[4];
|
||||
if( meta[6]>0 && meta[6]<=2 && db->temp_store==0 ){
|
||||
db->temp_store = meta[6];
|
||||
}
|
||||
if( db->safety_level==0 ) db->safety_level = 2;
|
||||
|
||||
/*
|
||||
|
|
@ -327,31 +338,28 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
|
||||
/* Read the schema information out of the schema tables
|
||||
*/
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.xCallback = sqliteInitCallback;
|
||||
sParse.pArg = (void*)&initData;
|
||||
sParse.initFlag = 1;
|
||||
sParse.useCallback = 1;
|
||||
assert( db->init.busy );
|
||||
sqliteSafetyOff(db);
|
||||
if( iDb==0 ){
|
||||
sqliteRunParser(&sParse,
|
||||
rc = sqlite_exec(db,
|
||||
db->file_format>=2 ? init_script : older_init_script,
|
||||
pzErrMsg);
|
||||
sqliteInitCallback, &initData, 0);
|
||||
}else{
|
||||
char *zSql = 0;
|
||||
sqliteSetString(&zSql,
|
||||
"SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
|
||||
db->aDb[iDb].zName, "\".sqlite_master", (char*)0);
|
||||
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
||||
rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0);
|
||||
sqliteFree(zSql);
|
||||
}
|
||||
sqliteSafetyOn(db);
|
||||
sqliteBtreeCloseCursor(curMain);
|
||||
if( sqlite_malloc_failed ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
rc = SQLITE_NOMEM;
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
}
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK ){
|
||||
DbSetProperty(db, iDb, DB_SchemaLoaded);
|
||||
if( iDb==0 ){
|
||||
DbSetProperty(db, 1, DB_SchemaLoaded);
|
||||
|
|
@ -359,7 +367,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
}else{
|
||||
sqliteResetInternalSchema(db, iDb);
|
||||
}
|
||||
return sParse.rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -378,17 +386,58 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||
int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
int i, rc;
|
||||
|
||||
if( db->init.busy ) return SQLITE_OK;
|
||||
assert( (db->flags & SQLITE_Initialized)==0 );
|
||||
rc = SQLITE_OK;
|
||||
db->init.busy = 1;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
|
||||
assert( i!=1 ); /* Should have been initialized together with 0 */
|
||||
rc = sqliteInitOne(db, i, pzErrMsg);
|
||||
if( rc ){
|
||||
sqliteResetInternalSchema(db, i);
|
||||
}
|
||||
}
|
||||
db->init.busy = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
db->flags |= SQLITE_Initialized;
|
||||
sqliteCommitInternalChanges(db);
|
||||
}else{
|
||||
}
|
||||
|
||||
/* If the database is in formats 1 or 2, then upgrade it to
|
||||
** version 3. This will reconstruct all indices. If the
|
||||
** upgrade fails for any reason (ex: out of disk space, database
|
||||
** is read only, interrupt received, etc.) then fail the init.
|
||||
*/
|
||||
if( rc==SQLITE_OK && db->file_format<3 ){
|
||||
char *zErr = 0;
|
||||
InitData initData;
|
||||
int meta[SQLITE_N_BTREE_META];
|
||||
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
initData.db = db;
|
||||
initData.pzErrMsg = &zErr;
|
||||
db->file_format = 3;
|
||||
rc = sqlite_exec(db,
|
||||
"BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
|
||||
upgrade_3_callback,
|
||||
&initData,
|
||||
&zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
|
||||
meta[2] = 4;
|
||||
sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
|
||||
sqlite_exec(db, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteSetString(pzErrMsg,
|
||||
"unable to upgrade database to the version 2.6 format",
|
||||
zErr ? ": " : 0, zErr, (char*)0);
|
||||
}
|
||||
sqlite_freemem(zErr);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
}
|
||||
return rc;
|
||||
|
|
@ -432,6 +481,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
|||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
db->nDb = 2;
|
||||
db->aDb = db->aDbStatic;
|
||||
/* db->flags |= SQLITE_ShortColNames; */
|
||||
sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
|
||||
|
|
@ -475,42 +525,6 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
|||
*pzErrMsg = 0;
|
||||
}
|
||||
|
||||
/* If the database is in formats 1 or 2, then upgrade it to
|
||||
** version 3. This will reconstruct all indices. If the
|
||||
** upgrade fails for any reason (ex: out of disk space, database
|
||||
** is read only, interrupt received, etc.) then refuse to open.
|
||||
*/
|
||||
if( rc==SQLITE_OK && db->file_format<3 ){
|
||||
char *zErr = 0;
|
||||
InitData initData;
|
||||
int meta[SQLITE_N_BTREE_META];
|
||||
|
||||
initData.db = db;
|
||||
initData.pzErrMsg = &zErr;
|
||||
db->file_format = 3;
|
||||
rc = sqlite_exec(db,
|
||||
"BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
|
||||
upgrade_3_callback,
|
||||
&initData,
|
||||
&zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
|
||||
meta[2] = 4;
|
||||
sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
|
||||
sqlite_exec(db, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteSetString(pzErrMsg,
|
||||
"unable to upgrade database to the version 2.6 format",
|
||||
zErr ? ": " : 0, zErr, (char*)0);
|
||||
sqlite_freemem(zErr);
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
sqlite_close(db);
|
||||
return 0;
|
||||
}
|
||||
sqlite_freemem(zErr);
|
||||
}
|
||||
|
||||
/* Return a pointer to the newly opened database structure */
|
||||
return db;
|
||||
|
||||
|
|
@ -534,6 +548,16 @@ int sqlite_changes(sqlite *db){
|
|||
return db->nChange;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of changes produced by the last INSERT, UPDATE, or
|
||||
** DELETE statement to complete execution. The count does not include
|
||||
** changes due to SQL statements executed in trigger programs that were
|
||||
** triggered by that statement
|
||||
*/
|
||||
int sqlite_last_statement_changes(sqlite *db){
|
||||
return db->lsChange;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an existing SQLite database
|
||||
*/
|
||||
|
|
@ -547,13 +571,10 @@ void sqlite_close(sqlite *db){
|
|||
}
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
for(j=0; j<db->nDb; j++){
|
||||
if( db->aDb[j].pBt ){
|
||||
sqliteBtreeClose(db->aDb[j].pBt);
|
||||
db->aDb[j].pBt = 0;
|
||||
}
|
||||
if( j>=2 ){
|
||||
sqliteFree(db->aDb[j].zName);
|
||||
db->aDb[j].zName = 0;
|
||||
struct Db *pDb = &db->aDb[j];
|
||||
if( pDb->pBt ){
|
||||
sqliteBtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
}
|
||||
}
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
|
|
@ -581,84 +602,8 @@ void sqliteRollbackAll(sqlite *db){
|
|||
db->aDb[i].inTrans = 0;
|
||||
}
|
||||
}
|
||||
sqliteRollbackInternalChanges(db);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine does the work of either sqlite_exec() or sqlite_compile().
|
||||
** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile()
|
||||
** otherwise.
|
||||
*/
|
||||
static int sqliteMain(
|
||||
sqlite *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
sqlite_callback xCallback, /* Invoke this callback routine */
|
||||
void *pArg, /* First argument to xCallback() */
|
||||
const char **pzTail, /* OUT: Next statement after the first */
|
||||
sqlite_vm **ppVm, /* OUT: The virtual machine */
|
||||
char **pzErrMsg /* OUT: Write error messages here */
|
||||
){
|
||||
Parse sParse;
|
||||
|
||||
if( pzErrMsg ) *pzErrMsg = 0;
|
||||
if( sqliteSafetyOn(db) ) goto exec_misuse;
|
||||
if( (db->flags & SQLITE_Initialized)==0 ){
|
||||
int rc, cnt = 1;
|
||||
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
|
||||
&& db->xBusyCallback && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
sqliteSafetyOff(db);
|
||||
return rc;
|
||||
}
|
||||
if( pzErrMsg ){
|
||||
sqliteFree(*pzErrMsg);
|
||||
*pzErrMsg = 0;
|
||||
}
|
||||
}
|
||||
if( db->file_format<3 ){
|
||||
sqliteSafetyOff(db);
|
||||
sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( db->pVdbe==0 ){ db->nChange = 0; }
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.xCallback = xCallback;
|
||||
sParse.pArg = pArg;
|
||||
sParse.useCallback = ppVm==0;
|
||||
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
|
||||
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
||||
if( sqlite_malloc_failed ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
sqliteRollbackAll(db);
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
}
|
||||
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
|
||||
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
|
||||
}
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
}
|
||||
if( sParse.useCallback==0 ){
|
||||
assert( ppVm );
|
||||
*ppVm = (sqlite_vm*)sParse.pVdbe;
|
||||
if( pzTail ) *pzTail = sParse.zTail;
|
||||
}
|
||||
if( sqliteSafetyOff(db) ) goto exec_misuse;
|
||||
return sParse.rc;
|
||||
|
||||
exec_misuse:
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = 0;
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
}
|
||||
return SQLITE_MISUSE;
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
/* sqliteRollbackInternalChanges(db); */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -678,9 +623,62 @@ int sqlite_exec(
|
|||
void *pArg, /* First argument to xCallback() */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
return sqliteMain(db, zSql, xCallback, pArg, 0, 0, pzErrMsg);
|
||||
int rc = SQLITE_OK;
|
||||
const char *zLeftover;
|
||||
sqlite_vm *pVm;
|
||||
int nRetry = 0;
|
||||
int nChange = 0;
|
||||
int nCallback;
|
||||
|
||||
if( zSql==0 ) return SQLITE_OK;
|
||||
while( rc==SQLITE_OK && zSql[0] ){
|
||||
pVm = 0;
|
||||
rc = sqlite_compile(db, zSql, &zLeftover, &pVm, pzErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( pVm==0 || sqlite_malloc_failed );
|
||||
return rc;
|
||||
}
|
||||
if( pVm==0 ){
|
||||
/* This happens if the zSql input contained only whitespace */
|
||||
break;
|
||||
}
|
||||
db->nChange += nChange;
|
||||
nCallback = 0;
|
||||
while(1){
|
||||
int nArg;
|
||||
char **azArg, **azCol;
|
||||
rc = sqlite_step(pVm, &nArg, (const char***)&azArg,(const char***)&azCol);
|
||||
if( rc==SQLITE_ROW ){
|
||||
if( xCallback!=0 && xCallback(pArg, nArg, azArg, azCol) ){
|
||||
sqlite_finalize(pVm, 0);
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
nCallback++;
|
||||
}else{
|
||||
if( rc==SQLITE_DONE && nCallback==0
|
||||
&& (db->flags & SQLITE_NullCallback)!=0 && xCallback!=0 ){
|
||||
xCallback(pArg, nArg, azArg, azCol);
|
||||
}
|
||||
rc = sqlite_finalize(pVm, pzErrMsg);
|
||||
if( rc==SQLITE_SCHEMA && nRetry<2 ){
|
||||
nRetry++;
|
||||
rc = SQLITE_OK;
|
||||
break;
|
||||
}
|
||||
if( db->pVdbe==0 ){
|
||||
nChange = db->nChange;
|
||||
}
|
||||
nRetry = 0;
|
||||
zSql = zLeftover;
|
||||
while( isspace(zSql[0]) ) zSql++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Compile a single statement of SQL into a virtual machine. Return one
|
||||
** of the SQLITE_ success/failure codes. Also write an error message into
|
||||
|
|
@ -693,7 +691,88 @@ int sqlite_compile(
|
|||
sqlite_vm **ppVm, /* OUT: The virtual machine */
|
||||
char **pzErrMsg /* OUT: Write error messages here */
|
||||
){
|
||||
return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg);
|
||||
Parse sParse;
|
||||
|
||||
if( pzErrMsg ) *pzErrMsg = 0;
|
||||
if( sqliteSafetyOn(db) ) goto exec_misuse;
|
||||
if( !db->init.busy ){
|
||||
if( (db->flags & SQLITE_Initialized)==0 ){
|
||||
int rc, cnt = 1;
|
||||
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
|
||||
&& db->xBusyCallback
|
||||
&& db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
sqliteSafetyOff(db);
|
||||
return rc;
|
||||
}
|
||||
if( pzErrMsg ){
|
||||
sqliteFree(*pzErrMsg);
|
||||
*pzErrMsg = 0;
|
||||
}
|
||||
}
|
||||
if( db->file_format<3 ){
|
||||
sqliteSafetyOff(db);
|
||||
sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy );
|
||||
if( db->pVdbe==0 ){ db->nChange = 0; }
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
||||
if( db->xTrace && !db->init.busy ){
|
||||
/* Trace only the statment that was compiled.
|
||||
** Make a copy of that part of the SQL string since zSQL is const
|
||||
** and we must pass a zero terminated string to the trace function
|
||||
** The copy is unnecessary if the tail pointer is pointing at the
|
||||
** beginnig or end of the SQL string.
|
||||
*/
|
||||
if( sParse.zTail && sParse.zTail!=zSql && *sParse.zTail ){
|
||||
char *tmpSql = sqliteStrNDup(zSql, sParse.zTail - zSql);
|
||||
if( tmpSql ){
|
||||
db->xTrace(db->pTraceArg, tmpSql);
|
||||
free(tmpSql);
|
||||
}else{
|
||||
/* If a memory error occurred during the copy,
|
||||
** trace entire SQL string and fall through to the
|
||||
** sqlite_malloc_failed test to report the error.
|
||||
*/
|
||||
db->xTrace(db->pTraceArg, zSql);
|
||||
}
|
||||
}else{
|
||||
db->xTrace(db->pTraceArg, zSql);
|
||||
}
|
||||
}
|
||||
if( sqlite_malloc_failed ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
sqliteRollbackAll(db);
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
}
|
||||
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
|
||||
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
|
||||
}
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
}
|
||||
assert( ppVm );
|
||||
*ppVm = (sqlite_vm*)sParse.pVdbe;
|
||||
if( pzTail ) *pzTail = sParse.zTail;
|
||||
if( sqliteSafetyOff(db) ) goto exec_misuse;
|
||||
return sParse.rc;
|
||||
|
||||
exec_misuse:
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = 0;
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
}
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -729,7 +808,7 @@ int sqlite_reset(
|
|||
char **pzErrMsg /* OUT: Write error messages here */
|
||||
){
|
||||
int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg);
|
||||
sqliteVdbeMakeReady((Vdbe*)pVm, -1, 0, 0, 0);
|
||||
sqliteVdbeMakeReady((Vdbe*)pVm, -1, 0);
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -767,6 +846,7 @@ const char *sqlite_error_string(int rc){
|
|||
case SQLITE_AUTH: z = "authorization denied"; break;
|
||||
case SQLITE_FORMAT: z = "auxiliary database format error"; break;
|
||||
case SQLITE_RANGE: z = "bind index out of range"; break;
|
||||
case SQLITE_NOTADB: z = "file is encrypted or is not a database";break;
|
||||
default: z = "unknown error"; break;
|
||||
}
|
||||
return z;
|
||||
|
|
@ -784,22 +864,23 @@ static int sqliteDefaultBusyCallback(
|
|||
int count /* Number of times table has been busy */
|
||||
){
|
||||
#if SQLITE_MIN_SLEEP_MS==1
|
||||
int delay = 10;
|
||||
int prior_delay = 0;
|
||||
static const char delays[] =
|
||||
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 50, 100};
|
||||
static const short int totals[] =
|
||||
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228, 287};
|
||||
# define NDELAY (sizeof(delays)/sizeof(delays[0]))
|
||||
int timeout = (int)(long)Timeout;
|
||||
int i;
|
||||
int delay, prior;
|
||||
|
||||
for(i=1; i<count; i++){
|
||||
prior_delay += delay;
|
||||
delay = delay*2;
|
||||
if( delay>=1000 ){
|
||||
delay = 1000;
|
||||
prior_delay += 1000*(count - i - 1);
|
||||
break;
|
||||
}
|
||||
if( count <= NDELAY ){
|
||||
delay = delays[count-1];
|
||||
prior = totals[count-1];
|
||||
}else{
|
||||
delay = delays[NDELAY-1];
|
||||
prior = totals[NDELAY-1] + delay*(count-NDELAY-1);
|
||||
}
|
||||
if( prior_delay + delay > timeout ){
|
||||
delay = timeout - prior_delay;
|
||||
if( prior + delay > timeout ){
|
||||
delay = timeout - prior;
|
||||
if( delay<=0 ) return 0;
|
||||
}
|
||||
sqliteOsSleep(delay);
|
||||
|
|
@ -856,9 +937,9 @@ void sqlite_progress_handler(
|
|||
** This routine installs a default busy handler that waits for the
|
||||
** specified number of milliseconds before returning 0.
|
||||
*/
|
||||
void sqlite_busy_timeout(sqlite *db, long ms){
|
||||
void sqlite_busy_timeout(sqlite *db, int ms){
|
||||
if( ms>0 ){
|
||||
sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)ms);
|
||||
sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)(long)ms);
|
||||
}else{
|
||||
sqlite_busy_handler(db, 0, 0);
|
||||
}
|
||||
|
|
@ -903,7 +984,7 @@ const char *sqlite_libencoding(void){ return sqlite_encoding; }
|
|||
** sqlite_create_aggregate(), and vice versa.
|
||||
**
|
||||
** If nArg is -1 it means that this function will accept any number
|
||||
** of arguments, including 0.
|
||||
** of arguments, including 0. The maximum allowed value of nArg is 127.
|
||||
*/
|
||||
int sqlite_create_function(
|
||||
sqlite *db, /* Add the function to this database connection */
|
||||
|
|
@ -915,6 +996,7 @@ int sqlite_create_function(
|
|||
FuncDef *p;
|
||||
int nName;
|
||||
if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
|
||||
if( nArg<-1 || nArg>127 ) return 1;
|
||||
nName = strlen(zName);
|
||||
if( nName>255 ) return 1;
|
||||
p = sqliteFindFunction(db, zName, nName, nArg, 1);
|
||||
|
|
@ -936,6 +1018,7 @@ int sqlite_create_aggregate(
|
|||
FuncDef *p;
|
||||
int nName;
|
||||
if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
|
||||
if( nArg<-1 || nArg>127 ) return 1;
|
||||
nName = strlen(zName);
|
||||
if( nName>255 ) return 1;
|
||||
p = sqliteFindFunction(db, zName, nName, nArg, 1);
|
||||
|
|
@ -976,6 +1059,24 @@ void *sqlite_trace(sqlite *db, void (*xTrace)(void*,const char*), void *pArg){
|
|||
return pOld;
|
||||
}
|
||||
|
||||
/*** EXPERIMENTAL ***
|
||||
**
|
||||
** Register a function to be invoked when a transaction comments.
|
||||
** If either function returns non-zero, then the commit becomes a
|
||||
** rollback.
|
||||
*/
|
||||
void *sqlite_commit_hook(
|
||||
sqlite *db, /* Attach the hook to this database */
|
||||
int (*xCallback)(void*), /* Function to invoke on each commit */
|
||||
void *pArg /* Argument to the function */
|
||||
){
|
||||
void *pOld = db->pCommitArg;
|
||||
db->xCommitCallback = xCallback;
|
||||
db->pCommitArg = pArg;
|
||||
return pOld;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine is called to create a connection to a database BTree
|
||||
** driver. If zFilename is the name of a file, then that file is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue