mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-23 21:49:02 +03:00
Merge updates from trunk.
FossilOrigin-Name: 4ab1ffd45d4c25368b9b393a3336068b747d8b22
This commit is contained in:
@@ -932,6 +932,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
int eType; /* Datatype of a sample */
|
||||
IndexSample *pSample; /* A slot in pIdx->aSample[] */
|
||||
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
if( !sqlite3FindTable(db, "sqlite_stat3", zDb) ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -958,7 +959,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
if( pIdx==0 ) continue;
|
||||
assert( pIdx->nSample==0 );
|
||||
pIdx->nSample = nSample;
|
||||
pIdx->aSample = sqlite3MallocZero( nSample*sizeof(IndexSample) );
|
||||
pIdx->aSample = sqlite3DbMallocZero(db, nSample*sizeof(IndexSample));
|
||||
pIdx->avgEq = pIdx->aiRowEst[1];
|
||||
if( pIdx->aSample==0 ){
|
||||
db->mallocFailed = 1;
|
||||
@@ -1031,7 +1032,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
if( n < 1){
|
||||
pSample->u.z = 0;
|
||||
}else{
|
||||
pSample->u.z = sqlite3Malloc(n);
|
||||
pSample->u.z = sqlite3DbMallocRaw(db, n);
|
||||
if( pSample->u.z==0 ){
|
||||
db->mallocFailed = 1;
|
||||
sqlite3_finalize(pStmt);
|
||||
@@ -1107,7 +1108,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
/* Load the statistics from the sqlite_stat3 table. */
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
if( rc==SQLITE_OK ){
|
||||
int lookasideEnabled = db->lookaside.bEnabled;
|
||||
db->lookaside.bEnabled = 0;
|
||||
rc = loadStat3(db, sInfo.zDatabase);
|
||||
db->lookaside.bEnabled = lookasideEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
75
src/main.c
75
src/main.c
@@ -2725,35 +2725,27 @@ int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
|
||||
*/
|
||||
int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
int rc = SQLITE_ERROR;
|
||||
int iDb;
|
||||
Btree *pBtree;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( zDbName==0 ){
|
||||
iDb = 0;
|
||||
}else{
|
||||
for(iDb=0; iDb<db->nDb; iDb++){
|
||||
if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break;
|
||||
}
|
||||
}
|
||||
if( iDb<db->nDb ){
|
||||
Btree *pBtree = db->aDb[iDb].pBt;
|
||||
if( pBtree ){
|
||||
Pager *pPager;
|
||||
sqlite3_file *fd;
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
pPager = sqlite3BtreePager(pBtree);
|
||||
assert( pPager!=0 );
|
||||
fd = sqlite3PagerFile(pPager);
|
||||
assert( fd!=0 );
|
||||
if( op==SQLITE_FCNTL_FILE_POINTER ){
|
||||
*(sqlite3_file**)pArg = fd;
|
||||
rc = SQLITE_OK;
|
||||
}else if( fd->pMethods ){
|
||||
rc = sqlite3OsFileControl(fd, op, pArg);
|
||||
}else{
|
||||
rc = SQLITE_NOTFOUND;
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
pBtree = sqlite3DbNameToBtree(db, zDbName);
|
||||
if( pBtree ){
|
||||
Pager *pPager;
|
||||
sqlite3_file *fd;
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
pPager = sqlite3BtreePager(pBtree);
|
||||
assert( pPager!=0 );
|
||||
fd = sqlite3PagerFile(pPager);
|
||||
assert( fd!=0 );
|
||||
if( op==SQLITE_FCNTL_FILE_POINTER ){
|
||||
*(sqlite3_file**)pArg = fd;
|
||||
rc = SQLITE_OK;
|
||||
}else if( fd->pMethods ){
|
||||
rc = sqlite3OsFileControl(fd, op, pArg);
|
||||
}else{
|
||||
rc = SQLITE_NOTFOUND;
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
@@ -3049,15 +3041,34 @@ sqlite3_int64 sqlite3_uri_int64(
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the filename of the database associated with a database
|
||||
** connection.
|
||||
** Return the Btree pointer identified by zDbName. Return NULL if not found.
|
||||
*/
|
||||
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
|
||||
Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt && sqlite3StrICmp(zDbName, db->aDb[i].zName)==0 ){
|
||||
return sqlite3BtreeGetFilename(db->aDb[i].pBt);
|
||||
if( db->aDb[i].pBt
|
||||
&& (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
|
||||
){
|
||||
return db->aDb[i].pBt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the filename of the database associated with a database
|
||||
** connection.
|
||||
*/
|
||||
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
|
||||
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
|
||||
return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return 1 if database is read-only or 0 if read/write. Return -1 if
|
||||
** no such database exists.
|
||||
*/
|
||||
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
|
||||
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
|
||||
return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1;
|
||||
}
|
||||
|
||||
@@ -4530,6 +4530,15 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
||||
*/
|
||||
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine if a database is read-only
|
||||
**
|
||||
** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
|
||||
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
|
||||
** the name of a database on connection D.
|
||||
*/
|
||||
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find the next prepared statement
|
||||
**
|
||||
|
||||
@@ -2701,6 +2701,7 @@ void sqlite3AddCollateType(Parse*, Token*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
||||
sqlite3_vfs**,char**,char **);
|
||||
Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
|
||||
int sqlite3CodeOnce(Parse *);
|
||||
|
||||
Bitvec *sqlite3BitvecCreate(u32);
|
||||
|
||||
25
src/test1.c
25
src/test1.c
@@ -4665,6 +4665,30 @@ static int test_db_filename(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_db_readonly DB DBNAME
|
||||
**
|
||||
** Return 1 or 0 if DBNAME is readonly or not. Return -1 if DBNAME does
|
||||
** not exist.
|
||||
*/
|
||||
static int test_db_readonly(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zDbName;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zDbName = Tcl_GetString(objv[2]);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_db_readonly(db, zDbName)));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_soft_heap_limit ?N?
|
||||
**
|
||||
@@ -6055,6 +6079,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_release_memory", test_release_memory, 0},
|
||||
{ "sqlite3_db_release_memory", test_db_release_memory, 0},
|
||||
{ "sqlite3_db_filename", test_db_filename, 0},
|
||||
{ "sqlite3_db_readonly", test_db_readonly, 0},
|
||||
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
|
||||
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0},
|
||||
{ "sqlite3_pager_refcounts", test_pager_refcounts, 0},
|
||||
|
||||
10
src/util.c
10
src/util.c
@@ -216,11 +216,11 @@ int sqlite3Dequote(char *z){
|
||||
** Some systems have stricmp(). Others have strcasecmp(). Because
|
||||
** there is no consistency, we will define our own.
|
||||
**
|
||||
** IMPLEMENTATION-OF: R-20522-24639 The sqlite3_strnicmp() API allows
|
||||
** applications and extensions to compare the contents of two buffers
|
||||
** containing UTF-8 strings in a case-independent fashion, using the same
|
||||
** definition of case independence that SQLite uses internally when
|
||||
** comparing identifiers.
|
||||
** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and
|
||||
** sqlite3_strnicmp() APIs allow applications and extensions to compare
|
||||
** the contents of two buffers containing UTF-8 strings in a
|
||||
** case-independent fashion, using the same definition of "case
|
||||
** independence" that SQLite uses internally when comparing identifiers.
|
||||
*/
|
||||
int sqlite3_stricmp(const char *zLeft, const char *zRight){
|
||||
register unsigned char *a, *b;
|
||||
|
||||
29
src/where.c
29
src/where.c
@@ -3802,8 +3802,7 @@ static Bitmask codeOneLoopStart(
|
||||
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
|
||||
int iLevel, /* Which level of pWInfo->a[] should be coded */
|
||||
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
|
||||
Bitmask notReady, /* Which tables are currently available */
|
||||
Expr *pWhere /* Complete WHERE clause */
|
||||
Bitmask notReady /* Which tables are currently available */
|
||||
){
|
||||
int j, k; /* Loop counters */
|
||||
int iCur; /* The VDBE cursor for the table */
|
||||
@@ -4342,10 +4341,25 @@ static Bitmask codeOneLoopStart(
|
||||
** Then for every term xN, evaluate as the subexpression: xN AND z
|
||||
** That way, terms in y that are factored into the disjunction will
|
||||
** be picked up by the recursive calls to sqlite3WhereBegin() below.
|
||||
**
|
||||
** Actually, each subexpression is converted to "xN AND w" where w is
|
||||
** the "interesting" terms of z - terms that did not originate in the
|
||||
** ON or USING clause of a LEFT JOIN, and terms that are usable as
|
||||
** indices.
|
||||
*/
|
||||
if( pWC->nTerm>1 ){
|
||||
pAndExpr = sqlite3ExprAlloc(pParse->db, TK_AND, 0, 0);
|
||||
pAndExpr->pRight = pWhere;
|
||||
int iTerm;
|
||||
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
|
||||
Expr *pExpr = pWC->a[iTerm].pExpr;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue;
|
||||
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
|
||||
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
|
||||
pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
|
||||
}
|
||||
if( pAndExpr ){
|
||||
pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(ii=0; ii<pOrWc->nTerm; ii++){
|
||||
@@ -4387,7 +4401,10 @@ static Bitmask codeOneLoopStart(
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(pParse->db, pAndExpr);
|
||||
if( pAndExpr ){
|
||||
pAndExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(pParse->db, pAndExpr);
|
||||
}
|
||||
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
|
||||
sqlite3VdbeResolveLabel(v, iLoopBody);
|
||||
@@ -5043,7 +5060,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
for(i=0; i<nTabList; i++){
|
||||
pLevel = &pWInfo->a[i];
|
||||
explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
|
||||
notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady, pWhere);
|
||||
notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
|
||||
pWInfo->iContinue = pLevel->addrCont;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user