mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Merge latest trunk into this branch.
FossilOrigin-Name: cb721d0b36268a7b0ef493fa4d7f6bcbaa9ead8b1990e3c3fae015fa1d545226
This commit is contained in:
199
src/main.c
199
src/main.c
@@ -789,6 +789,11 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
|
||||
int rc;
|
||||
va_start(ap, op);
|
||||
switch( op ){
|
||||
case SQLITE_DBCONFIG_MAINDBNAME: {
|
||||
db->aDb[0].zDbSName = va_arg(ap,char*);
|
||||
rc = SQLITE_OK;
|
||||
break;
|
||||
}
|
||||
case SQLITE_DBCONFIG_LOOKASIDE: {
|
||||
void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */
|
||||
int sz = va_arg(ap, int); /* IMP: R-47871-25994 */
|
||||
@@ -811,6 +816,8 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
|
||||
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
|
||||
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
|
||||
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
|
||||
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
|
||||
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
|
||||
};
|
||||
unsigned int i;
|
||||
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
|
||||
@@ -921,6 +928,21 @@ sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
|
||||
return db->lastRowid;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the value returned by the sqlite3_last_insert_rowid() API function.
|
||||
*/
|
||||
void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->lastRowid = iRowid;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of changes in the most recent call to sqlite3_exec().
|
||||
*/
|
||||
@@ -1039,6 +1061,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( db->mTrace & SQLITE_TRACE_CLOSE ){
|
||||
db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
|
||||
}
|
||||
|
||||
/* Force xDisconnect calls on all virtual tables */
|
||||
disconnectAllVtab(db);
|
||||
@@ -1565,7 +1590,7 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
|
||||
*/
|
||||
void sqlite3_interrupt(sqlite3 *db){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
return;
|
||||
}
|
||||
@@ -1807,7 +1832,8 @@ int sqlite3_overload_function(
|
||||
** trace is a pointer to a function that is invoked at the start of each
|
||||
** SQL statement.
|
||||
*/
|
||||
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
|
||||
void *pOld;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
@@ -1818,11 +1844,38 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pOld = db->pTraceArg;
|
||||
db->xTrace = xTrace;
|
||||
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
|
||||
db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
|
||||
db->pTraceArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pOld;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_DEPRECATED */
|
||||
|
||||
/* Register a trace callback using the version-2 interface.
|
||||
*/
|
||||
int sqlite3_trace_v2(
|
||||
sqlite3 *db, /* Trace this connection */
|
||||
unsigned mTrace, /* Mask of events to be traced */
|
||||
int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */
|
||||
void *pArg /* Context */
|
||||
){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( mTrace==0 ) xTrace = 0;
|
||||
if( xTrace==0 ) mTrace = 0;
|
||||
db->mTrace = mTrace;
|
||||
db->xTrace = xTrace;
|
||||
db->pTraceArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/*
|
||||
** Register a profile function. The pArg from the previously registered
|
||||
** profile function is returned.
|
||||
@@ -1851,6 +1904,7 @@ void *sqlite3_profile(
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pOld;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_DEPRECATED */
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
|
||||
/*
|
||||
@@ -1929,6 +1983,27 @@ void *sqlite3_rollback_hook(
|
||||
return pRet;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
/*
|
||||
** Register a callback to be invoked each time a row is updated,
|
||||
** inserted or deleted using this database connection.
|
||||
*/
|
||||
void *sqlite3_preupdate_hook(
|
||||
sqlite3 *db, /* Attach the hook to this database */
|
||||
void(*xCallback)( /* Callback function */
|
||||
void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64),
|
||||
void *pArg /* First callback argument */
|
||||
){
|
||||
void *pRet;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pRet = db->pPreUpdateArg;
|
||||
db->xPreUpdateCallback = xCallback;
|
||||
db->pPreUpdateArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pRet;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
|
||||
@@ -2054,6 +2129,13 @@ int sqlite3_wal_checkpoint_v2(
|
||||
sqlite3Error(db, rc);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
|
||||
/* If there are no active statements, clear the interrupt flag at this
|
||||
** point. */
|
||||
if( db->nVdbeActive==0 ){
|
||||
db->u1.isInterrupted = 0;
|
||||
}
|
||||
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
#endif
|
||||
@@ -2247,6 +2329,9 @@ int sqlite3_extended_errcode(sqlite3 *db){
|
||||
}
|
||||
return db->errCode;
|
||||
}
|
||||
int sqlite3_system_errno(sqlite3 *db){
|
||||
return db ? db->iSysErrno : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a string that describes the kind of error specified in the
|
||||
@@ -2553,6 +2638,7 @@ int sqlite3ParseUri(
|
||||
|
||||
assert( octet>=0 && octet<256 );
|
||||
if( octet==0 ){
|
||||
#ifndef SQLITE_ENABLE_URI_00_ERROR
|
||||
/* This branch is taken when "%00" appears within the URI. In this
|
||||
** case we ignore all text in the remainder of the path, name or
|
||||
** value currently being parsed. So ignore the current character
|
||||
@@ -2565,6 +2651,12 @@ int sqlite3ParseUri(
|
||||
iIn++;
|
||||
}
|
||||
continue;
|
||||
#else
|
||||
/* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */
|
||||
*pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri");
|
||||
rc = SQLITE_ERROR;
|
||||
goto parse_uri_out;
|
||||
#endif
|
||||
}
|
||||
c = octet;
|
||||
}else if( eState==1 && (c=='&' || c=='=') ){
|
||||
@@ -2669,7 +2761,9 @@ int sqlite3ParseUri(
|
||||
}else{
|
||||
zFile = sqlite3_malloc64(nUri+2);
|
||||
if( !zFile ) return SQLITE_NOMEM_BKPT;
|
||||
memcpy(zFile, zUri, nUri);
|
||||
if( nUri ){
|
||||
memcpy(zFile, zUri, nUri);
|
||||
}
|
||||
zFile[nUri] = '\0';
|
||||
zFile[nUri+1] = '\0';
|
||||
flags &= ~SQLITE_OPEN_URI;
|
||||
@@ -2884,9 +2978,9 @@ static int openDatabase(
|
||||
/* The default safety_level for the main database is FULL; for the temp
|
||||
** database it is OFF. This matches the pager layer defaults.
|
||||
*/
|
||||
db->aDb[0].zName = "main";
|
||||
db->aDb[0].zDbSName = "main";
|
||||
db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
|
||||
db->aDb[1].zName = "temp";
|
||||
db->aDb[1].zDbSName = "temp";
|
||||
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
|
||||
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
@@ -2900,11 +2994,20 @@ static int openDatabase(
|
||||
*/
|
||||
sqlite3Error(db, SQLITE_OK);
|
||||
sqlite3RegisterPerConnectionBuiltinFunctions(db);
|
||||
rc = sqlite3_errcode(db);
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
/* Register any built-in FTS5 module before loading the automatic
|
||||
** extensions. This allows automatic extensions to register FTS5
|
||||
** tokenizers and auxiliary functions. */
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5Init(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load automatic extensions - extensions that have been registered
|
||||
** using the sqlite3_automatic_extension() API.
|
||||
*/
|
||||
rc = sqlite3_errcode(db);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3AutoLoadExtensions(db);
|
||||
rc = sqlite3_errcode(db);
|
||||
@@ -2933,12 +3036,6 @@ static int openDatabase(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5Init(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ICU
|
||||
if( !db->mallocFailed && rc==SQLITE_OK ){
|
||||
rc = sqlite3IcuInit(db);
|
||||
@@ -3347,8 +3444,7 @@ int sqlite3_table_column_metadata(
|
||||
** explicitly declared column. Copy meta information from *pCol.
|
||||
*/
|
||||
if( pCol ){
|
||||
zDataType = sqlite3StrNext(pCol->zName);
|
||||
if( zDataType[0]==0 ) zDataType = 0;
|
||||
zDataType = sqlite3ColumnType(pCol,0);
|
||||
zCollSeq = pCol->zColl;
|
||||
notnull = pCol->notNull!=0;
|
||||
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
|
||||
@@ -3461,7 +3557,7 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
*/
|
||||
int sqlite3_test_control(int op, ...){
|
||||
int rc = 0;
|
||||
#ifdef SQLITE_OMIT_BUILTIN_TEST
|
||||
#ifdef SQLITE_UNTESTABLE
|
||||
UNUSED_PARAMETER(op);
|
||||
#else
|
||||
va_list ap;
|
||||
@@ -3727,6 +3823,15 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the threshold at which OP_Once counters reset back to zero.
|
||||
** By default this is 0x7ffffffe (over 2 billion), but that value is
|
||||
** too big to test in a reasonable amount of time, so this control is
|
||||
** provided to set a small and easily reachable reset value.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: {
|
||||
sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
|
||||
**
|
||||
@@ -3789,7 +3894,7 @@ int sqlite3_test_control(int op, ...){
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
#endif /* SQLITE_UNTESTABLE */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3845,15 +3950,8 @@ sqlite3_int64 sqlite3_uri_int64(
|
||||
** Return the Btree pointer identified by zDbName. Return NULL if not found.
|
||||
*/
|
||||
Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt
|
||||
&& (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
|
||||
){
|
||||
return db->aDb[i].pBt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
|
||||
return iDb<0 ? 0 : db->aDb[iDb].pBt;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3900,7 +3998,6 @@ int sqlite3_snapshot_get(
|
||||
){
|
||||
int rc = SQLITE_ERROR;
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
int iDb;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
@@ -3909,13 +4006,15 @@ int sqlite3_snapshot_get(
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
iDb = sqlite3FindDbName(db, zDb);
|
||||
if( iDb==0 || iDb>1 ){
|
||||
Btree *pBt = db->aDb[iDb].pBt;
|
||||
if( 0==sqlite3BtreeIsInTrans(pBt) ){
|
||||
rc = sqlite3BtreeBeginTrans(pBt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
|
||||
if( db->autoCommit==0 ){
|
||||
int iDb = sqlite3FindDbName(db, zDb);
|
||||
if( iDb==0 || iDb>1 ){
|
||||
Btree *pBt = db->aDb[iDb].pBt;
|
||||
if( 0==sqlite3BtreeIsInTrans(pBt) ){
|
||||
rc = sqlite3BtreeBeginTrans(pBt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3962,6 +4061,38 @@ int sqlite3_snapshot_open(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Recover as many snapshots as possible from the wal file associated with
|
||||
** schema zDb of database db.
|
||||
*/
|
||||
int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
|
||||
int rc = SQLITE_ERROR;
|
||||
int iDb;
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
iDb = sqlite3FindDbName(db, zDb);
|
||||
if( iDb==0 || iDb>1 ){
|
||||
Btree *pBt = db->aDb[iDb].pBt;
|
||||
if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
|
||||
rc = sqlite3BtreeBeginTrans(pBt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
|
||||
sqlite3BtreeCommit(pBt);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
#endif /* SQLITE_OMIT_WAL */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a snapshot handle obtained from sqlite3_snapshot_get().
|
||||
*/
|
||||
|
Reference in New Issue
Block a user