summaryrefslogtreecommitdiff
path: root/ext/sqlite/libsqlite/src/main.c
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2004-07-10 12:27:51 +0000
committerWez Furlong <wez@php.net>2004-07-10 12:27:51 +0000
commite563b4eafa63ba8beb88defa1e36f037a7a97a60 (patch)
tree2e72dfa1c4b7fe62fde9ab326a67047ba2f4cc9e /ext/sqlite/libsqlite/src/main.c
parentcd732f1a3f5df97407797fe7ebb97830552479ad (diff)
downloadphp-git-e563b4eafa63ba8beb88defa1e36f037a7a97a60.tar.gz
Upgrade bundled library to 2.8.14 + misc fixes
(http://www.sqlite.org/cvstrac/chngview?cn=1742)
Diffstat (limited to 'ext/sqlite/libsqlite/src/main.c')
-rw-r--r--ext/sqlite/libsqlite/src/main.c413
1 files changed, 257 insertions, 156 deletions
diff --git a/ext/sqlite/libsqlite/src/main.c b/ext/sqlite/libsqlite/src/main.c
index f79f266293..e6cc80f450 100644
--- a/ext/sqlite/libsqlite/src/main.c
+++ b/ext/sqlite/libsqlite/src/main.c
@@ -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;
@@ -535,6 +549,16 @@ int sqlite_changes(sqlite *db){
}
/*
+** 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
*/
void sqlite_close(sqlite *db){
@@ -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,19 +602,91 @@ void sqliteRollbackAll(sqlite *db){
db->aDb[i].inTrans = 0;
}
}
- sqliteRollbackInternalChanges(db);
+ sqliteResetInternalSchema(db, 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.
+** Execute SQL code. Return one of the SQLITE_ success/failure
+** codes. Also write an error message into memory obtained from
+** malloc() and make *pzErrMsg point to that message.
+**
+** If the SQL is a query, then for each row in the query result
+** the xCallback() function is called. pArg becomes the first
+** argument to xCallback(). If xCallback=NULL then no callback
+** is invoked, even for queries.
*/
-static int sqliteMain(
+int sqlite_exec(
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() */
+ char **pzErrMsg /* Write error messages here */
+){
+ 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
+** memory obtained from malloc() and make *pzErrMsg point to that message.
+*/
+int sqlite_compile(
+ sqlite *db, /* The database on which the SQL executes */
+ const char *zSql, /* The SQL to be executed */
const char **pzTail, /* OUT: Next statement after the first */
sqlite_vm **ppVm, /* OUT: The virtual machine */
char **pzErrMsg /* OUT: Write error messages here */
@@ -602,33 +695,56 @@ static int sqliteMain(
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( !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( 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->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;
- sParse.xCallback = xCallback;
- sParse.pArg = pArg;
- sParse.useCallback = ppVm==0;
- if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
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;
@@ -644,11 +760,9 @@ static int sqliteMain(
if( sParse.rc==SQLITE_SCHEMA ){
sqliteResetInternalSchema(db, 0);
}
- if( sParse.useCallback==0 ){
- assert( ppVm );
- *ppVm = (sqlite_vm*)sParse.pVdbe;
- if( pzTail ) *pzTail = sParse.zTail;
- }
+ assert( ppVm );
+ *ppVm = (sqlite_vm*)sParse.pVdbe;
+ if( pzTail ) *pzTail = sParse.zTail;
if( sqliteSafetyOff(db) ) goto exec_misuse;
return sParse.rc;
@@ -661,41 +775,6 @@ exec_misuse:
return SQLITE_MISUSE;
}
-/*
-** Execute SQL code. Return one of the SQLITE_ success/failure
-** codes. Also write an error message into memory obtained from
-** malloc() and make *pzErrMsg point to that message.
-**
-** If the SQL is a query, then for each row in the query result
-** the xCallback() function is called. pArg becomes the first
-** argument to xCallback(). If xCallback=NULL then no callback
-** is invoked, even for queries.
-*/
-int sqlite_exec(
- 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() */
- char **pzErrMsg /* Write error messages here */
-){
- return sqliteMain(db, zSql, xCallback, pArg, 0, 0, pzErrMsg);
-}
-
-/*
-** Compile a single statement of SQL into a virtual machine. Return one
-** of the SQLITE_ success/failure codes. Also write an error message into
-** memory obtained from malloc() and make *pzErrMsg point to that message.
-*/
-int sqlite_compile(
- sqlite *db, /* The database on which the SQL executes */
- const char *zSql, /* The SQL to be executed */
- const char **pzTail, /* OUT: Next statement after the first */
- sqlite_vm **ppVm, /* OUT: The virtual machine */
- char **pzErrMsg /* OUT: Write error messages here */
-){
- return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg);
-}
-
/*
** The following routine destroys a virtual machine that is created by
@@ -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