mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Modifications to the VDBE to support more than one database file. (CVS 878)
FossilOrigin-Name: 875da9eed981bfa27b98e95025f9fdbed74b4098
This commit is contained in:
101
src/btree.c
101
src/btree.c
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.83 2003/02/12 14:09:43 drh Exp $
|
||||
** $Id: btree.c,v 1.84 2003/03/19 03:14:01 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@@ -2874,6 +2874,105 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if 0 /* UNTESTED */
|
||||
/*
|
||||
** Copy all cell data from one database file into another.
|
||||
** pages back the freelist.
|
||||
*/
|
||||
static int copyCell(Btree *pBtFrom, BTree *pBtTo, Cell *pCell){
|
||||
Pager *pFromPager = pBtFrom->pPager;
|
||||
OverflowPage *pOvfl;
|
||||
Pgno ovfl, nextOvfl;
|
||||
Pgno *pPrev;
|
||||
int rc = SQLITE_OK;
|
||||
MemPage *pNew, *pPrevPg;
|
||||
Pgno new;
|
||||
|
||||
if( NKEY(pBtTo, pCell->h) + NDATA(pBtTo, pCell->h) <= MX_LOCAL_PAYLOAD ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pPrev = &pCell->ovfl;
|
||||
pPrevPg = 0;
|
||||
ovfl = SWAB32(pBtTo, pCell->ovfl);
|
||||
while( ovfl && rc==SQLITE_OK ){
|
||||
rc = sqlitepager_get(pFromPager, ovfl, (void**)&pOvfl);
|
||||
if( rc ) return rc;
|
||||
nextOvfl = SWAB32(pBtFrom, pOvfl->iNext);
|
||||
rc = allocatePage(pBtTo, &pNew, &new, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlitepager_write(pNew);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pNew, pOvfl, SQLITE_PAGE_SIZE);
|
||||
*pPrev = SWAB32(pBtTo, new);
|
||||
if( pPrevPg ){
|
||||
sqlitepager_unref(pPrevPg);
|
||||
}
|
||||
pPrev = &pOvfl->iNext;
|
||||
pPrevPg = pNew;
|
||||
}
|
||||
}
|
||||
sqlitepager_unref(pOvfl);
|
||||
ovfl = nextOvfl;
|
||||
}
|
||||
if( pPrevPg ){
|
||||
sqlitepager_unref(pPrevPg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0 /* UNTESTED */
|
||||
/*
|
||||
** Copy a page of data from one database over to another.
|
||||
*/
|
||||
static int copyDatabasePage(
|
||||
Btree *pBtFrom,
|
||||
Pgno pgnoFrom,
|
||||
Btree *pBtTo,
|
||||
Pgno *pTo
|
||||
){
|
||||
MemPage *pPageFrom, *pPage;
|
||||
Pgno to;
|
||||
int rc;
|
||||
Cell *pCell;
|
||||
int idx;
|
||||
|
||||
rc = sqlitepager_get(pBtFrom->pPager, pgno, (void**)&pPageFrom);
|
||||
if( rc ) return rc;
|
||||
rc = allocatePage(pBt, &pPage, pTo, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlitepager_write(pPage);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pPage, pPageFrom, SQLITE_PAGE_SIZE);
|
||||
idx = SWAB16(pBt, pPage->u.hdr.firstCell);
|
||||
while( idx>0 ){
|
||||
pCell = (Cell*)&pPage->u.aDisk[idx];
|
||||
idx = SWAB16(pBt, pCell->h.iNext);
|
||||
if( pCell->h.leftChild ){
|
||||
Pgno newChld;
|
||||
rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pCell->h.leftChild),
|
||||
pBtTo, &newChld);
|
||||
if( rc ) return rc;
|
||||
pCell->h.leftChild = SWAB32(pBtFrom, newChld);
|
||||
}
|
||||
rc = copyCell(pBtFrom, pBtTo, pCell);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
if( pPage->u.hdr.rightChild ){
|
||||
Pgno newChld;
|
||||
rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pPage->u.hdr.rightChild),
|
||||
pBtTo, &newChld);
|
||||
if( rc ) return rc;
|
||||
pPage->u.hdr.rightChild = SWAB32(pBtTo, newChild);
|
||||
}
|
||||
}
|
||||
sqlitepager_unref(pPage);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Read the meta-information out of a database file.
|
||||
*/
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.27 2003/02/12 14:09:44 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.28 2003/03/19 03:14:01 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -37,6 +37,7 @@ int sqliteBtreeCreateTable(Btree*, int*);
|
||||
int sqliteBtreeCreateIndex(Btree*, int*);
|
||||
int sqliteBtreeDropTable(Btree*, int);
|
||||
int sqliteBtreeClearTable(Btree*, int);
|
||||
int sqliteBtreeCopyTable(Btree *pFrom, int iFrom, Btree *pTo, int iTo);
|
||||
|
||||
int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
|
||||
int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes);
|
||||
|
||||
109
src/build.c
109
src/build.c
@@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.131 2003/03/01 19:45:34 drh Exp $
|
||||
** $Id: build.c,v 1.132 2003/03/19 03:14:01 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -85,7 +85,7 @@ void sqliteExec(Parse *pParse){
|
||||
if( pParse->useCallback ){
|
||||
if( pParse->explain ){
|
||||
rc = sqliteVdbeList(v);
|
||||
db->next_cookie = db->schema_cookie;
|
||||
db->next_cookie = db->aDb[0].schema_cookie;
|
||||
}else{
|
||||
sqliteVdbeExec(v);
|
||||
}
|
||||
@@ -211,7 +211,7 @@ void sqliteRollbackInternalChanges(sqlite *db){
|
||||
** This routine is called when a commit occurs.
|
||||
*/
|
||||
void sqliteCommitInternalChanges(sqlite *db){
|
||||
db->schema_cookie = db->next_cookie;
|
||||
db->aDb[0].schema_cookie = db->next_cookie;
|
||||
db->flags &= ~SQLITE_InternChanges;
|
||||
}
|
||||
|
||||
@@ -310,13 +310,8 @@ char *sqliteTableNameFromToken(Token *pName){
|
||||
** on cursor 0.
|
||||
*/
|
||||
void sqliteOpenMasterTable(Vdbe *v, int isTemp){
|
||||
if( isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_OpenWrAux, 0, 2);
|
||||
sqliteVdbeChangeP3(v, -1, TEMP_MASTER_NAME, P3_STATIC);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
|
||||
sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -383,8 +378,8 @@ void sqliteStartTable(
|
||||
/* Before trying to create a temporary table, make sure the Btree for
|
||||
** holding temporary tables is open.
|
||||
*/
|
||||
if( isTemp && db->pBeTemp==0 ){
|
||||
int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->pBeTemp);
|
||||
if( isTemp && db->aDb[1].pBt==0 ){
|
||||
int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->aDb[1].pBt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database "
|
||||
"file for storing temporary tables", 0);
|
||||
@@ -392,7 +387,7 @@ void sqliteStartTable(
|
||||
return;
|
||||
}
|
||||
if( db->flags & SQLITE_InTrans ){
|
||||
rc = sqliteBtreeBeginTrans(db->pBeTemp);
|
||||
rc = sqliteBtreeBeginTrans(db->aDb[1].pBt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on "
|
||||
"the temporary database file", 0);
|
||||
@@ -713,8 +708,8 @@ void sqliteAddCollateType(Parse *pParse, int collType){
|
||||
** 1 chance in 2^32. So we're safe enough.
|
||||
*/
|
||||
void sqliteChangeCookie(sqlite *db, Vdbe *v){
|
||||
if( db->next_cookie==db->schema_cookie ){
|
||||
db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
|
||||
if( db->next_cookie==db->aDb[0].schema_cookie ){
|
||||
db->next_cookie = db->aDb[0].schema_cookie + sqliteRandomByte() + 1;
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
|
||||
@@ -901,8 +896,8 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
if( pSelect ){
|
||||
int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, op, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, p->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
|
||||
pParse->nTab = 2;
|
||||
sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
|
||||
}
|
||||
@@ -1647,11 +1642,8 @@ void sqliteCreateIndex(
|
||||
pIndex->tnum = 0;
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
|
||||
}
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pStart && pEnd ){
|
||||
@@ -1661,7 +1653,8 @@ void sqliteCreateIndex(
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
lbl2 = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
|
||||
@@ -1940,16 +1933,16 @@ void sqliteCopy(
|
||||
}
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
int openOp;
|
||||
sqliteBeginWriteOperation(pParse, 1, pTab->isTemp);
|
||||
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
||||
sqliteVdbeDequoteP3(v, addr);
|
||||
openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, openOp, 0, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
sqliteVdbeAddOp(v, openOp, i, pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
@@ -2019,7 +2012,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
|
||||
void sqliteBeginTransaction(Parse *pParse, int onError){
|
||||
sqlite *db;
|
||||
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
|
||||
if( pParse->nErr || sqlite_malloc_failed ) return;
|
||||
if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0) ) return;
|
||||
if( db->flags & SQLITE_InTrans ){
|
||||
@@ -2039,7 +2032,7 @@ void sqliteBeginTransaction(Parse *pParse, int onError){
|
||||
void sqliteCommitTransaction(Parse *pParse){
|
||||
sqlite *db;
|
||||
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
|
||||
if( pParse->nErr || sqlite_malloc_failed ) return;
|
||||
if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0) ) return;
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
@@ -2060,7 +2053,7 @@ void sqliteRollbackTransaction(Parse *pParse){
|
||||
sqlite *db;
|
||||
Vdbe *v;
|
||||
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
|
||||
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
|
||||
if( pParse->nErr || sqlite_malloc_failed ) return;
|
||||
if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0) ) return;
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
@@ -2077,6 +2070,21 @@ void sqliteRollbackTransaction(Parse *pParse){
|
||||
db->onError = OE_Default;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code that will verify the schema cookie for all
|
||||
** named database files.
|
||||
*/
|
||||
void sqliteCodeVerifySchema(Parse *pParse){
|
||||
int i;
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v = sqliteGetVdbe(pParse);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].zName==0 || db->aDb[i].pBt==0 ) continue;
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, 0, db->aDb[i].schema_cookie);
|
||||
}
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code that prepares for doing an operation that
|
||||
** might change the database.
|
||||
@@ -2101,13 +2109,14 @@ void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int tempOnly){
|
||||
if( v==0 ) return;
|
||||
if( pParse->trigStack ) return; /* if this is in a trigger */
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, tempOnly, 0);
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 1, 0);
|
||||
if( !tempOnly ){
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
|
||||
sqliteCodeVerifySchema(pParse);
|
||||
}
|
||||
}else if( setCheckpoint ){
|
||||
sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Checkpoint, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2254,7 +2263,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
db->cache_size = db->cache_size<0 ? -size : size;
|
||||
sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
@@ -2287,7 +2296,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
if( size<0 ) size = -size;
|
||||
if( db->cache_size<0 ) size = -size;
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
@@ -2349,8 +2358,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
|
||||
sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
||||
}
|
||||
}else
|
||||
|
||||
@@ -2377,8 +2386,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
db->safety_level = getSafetyLevel(zRight)+1;
|
||||
if( db->safety_level==1 ) size = -size;
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
|
||||
sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
||||
}
|
||||
}else
|
||||
|
||||
@@ -2535,21 +2544,23 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
|
||||
static VdbeOp checkDb[] = {
|
||||
{ OP_SetInsert, 0, 0, "2"},
|
||||
{ OP_Open, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 6, 0},
|
||||
{ OP_Column, 0, 3, 0}, /* 3 */
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_OpenRead, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 7, 0},
|
||||
{ OP_Column, 0, 3, 0}, /* 4 */
|
||||
{ OP_SetInsert, 0, 0, 0},
|
||||
{ OP_Next, 0, 3, 0},
|
||||
{ OP_IntegrityCk, 0, 0, 0}, /* 6 */
|
||||
{ OP_Next, 0, 4, 0},
|
||||
{ OP_IntegrityCk, 0, 0, 0}, /* 7 */
|
||||
{ OP_ColumnName, 0, 0, "integrity_check"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
{ OP_SetInsert, 1, 0, "2"},
|
||||
{ OP_OpenAux, 1, 2, 0},
|
||||
{ OP_Rewind, 1, 15, 0},
|
||||
{ OP_Column, 1, 3, 0}, /* 12 */
|
||||
{ OP_Integer, 1, 0, 0},
|
||||
{ OP_OpenRead, 1, 2, 0},
|
||||
{ OP_Rewind, 1, 17, 0},
|
||||
{ OP_Column, 1, 3, 0}, /* 14 */
|
||||
{ OP_SetInsert, 1, 0, 0},
|
||||
{ OP_Next, 1, 12, 0},
|
||||
{ OP_IntegrityCk, 1, 1, 0}, /* 15 */
|
||||
{ OP_Next, 1, 14, 0},
|
||||
{ OP_IntegrityCk, 1, 1, 0}, /* 17 */
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
|
||||
|
||||
19
src/delete.c
19
src/delete.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.45 2003/01/13 23:27:33 drh Exp $
|
||||
** $Id: delete.c,v 1.46 2003/03/19 03:14:01 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -83,7 +83,6 @@ void sqliteDeleteFrom(
|
||||
Index *pIdx; /* For looping over indices of the table */
|
||||
int base; /* Index of the first available table cursor */
|
||||
sqlite *db; /* Main database structure */
|
||||
int openOp; /* Opcode used to open a cursor to the table */
|
||||
|
||||
int row_triggers_exist = 0;
|
||||
int oldIdx = -1;
|
||||
@@ -173,8 +172,8 @@ void sqliteDeleteFrom(
|
||||
** entries in the table. */
|
||||
int endOfLoop = sqliteVdbeMakeLabel(v);
|
||||
int addr;
|
||||
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, base, sqliteVdbeCurrentAddr(v)+2);
|
||||
addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Next, base, addr);
|
||||
@@ -220,9 +219,8 @@ void sqliteDeleteFrom(
|
||||
if( row_triggers_exist ){
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
|
||||
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
|
||||
|
||||
@@ -251,10 +249,11 @@ void sqliteDeleteFrom(
|
||||
** cursors are opened only once on the outside the loop.
|
||||
*/
|
||||
pParse->nTab = base + 1;
|
||||
openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqliteVdbeAddOp(v, openOp, pParse->nTab++, pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
|
||||
}
|
||||
|
||||
/* This is the beginning of the delete loop when there are no
|
||||
|
||||
19
src/insert.c
19
src/insert.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.72 2003/01/29 18:46:52 drh Exp $
|
||||
** $Id: insert.c,v 1.73 2003/03/19 03:14:01 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -100,7 +100,6 @@ void sqliteInsert(
|
||||
int base; /* First available cursor */
|
||||
int iCont, iBreak; /* Beginning and end of the loop over srcTab */
|
||||
sqlite *db; /* The main database structure */
|
||||
int openOp; /* Opcode used to open cursors */
|
||||
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||
int endOfLoop; /* Label for the end of the insertion loop */
|
||||
int useTempTable; /* Store SELECT results in intermediate table */
|
||||
@@ -198,7 +197,7 @@ void sqliteInsert(
|
||||
** should be written into a temporary table. Set to FALSE if each
|
||||
** row of the SELECT can be written directly into the result table.
|
||||
*/
|
||||
opCode = pTab->isTemp ? OP_OpenTemp : OP_Open;
|
||||
opCode = pTab->isTemp ? OP_OpenTemp : OP_OpenRead;
|
||||
useTempTable = row_triggers_exist || sqliteVdbeFindOp(v,opCode,pTab->tnum);
|
||||
|
||||
if( useTempTable ){
|
||||
@@ -329,11 +328,12 @@ void sqliteInsert(
|
||||
/* Open tables and indices if there are no row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
base = pParse->nTab;
|
||||
openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
sqliteVdbeAddOp(v, openOp, idx+base, pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
pParse->nTab += idx;
|
||||
@@ -390,11 +390,12 @@ void sqliteInsert(
|
||||
/* Open the tables and indices for the INSERT */
|
||||
if( !pTab->pSelect ){
|
||||
base = pParse->nTab;
|
||||
openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
sqliteVdbeAddOp(v, openOp, idx+base, pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
pParse->nTab += idx;
|
||||
|
||||
66
src/main.c
66
src/main.c
@@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.114 2003/02/16 22:21:32 drh Exp $
|
||||
** $Id: main.c,v 1.115 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@@ -249,8 +249,8 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
|
||||
/* Create a cursor to hold the database open
|
||||
*/
|
||||
if( db->pBe==0 ) return SQLITE_OK;
|
||||
rc = sqliteBtreeCursor(db->pBe, 2, 0, &curMain);
|
||||
if( db->aDb[0].pBt==0 ) return SQLITE_OK;
|
||||
rc = sqliteBtreeCursor(db->aDb[0].pBt, 2, 0, &curMain);
|
||||
if( rc ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
||||
sqliteResetInternalSchema(db);
|
||||
@@ -259,23 +259,22 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
|
||||
/* Get the database meta information
|
||||
*/
|
||||
rc = sqliteBtreeGetMeta(db->pBe, meta);
|
||||
rc = sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
|
||||
if( rc ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
|
||||
sqliteResetInternalSchema(db);
|
||||
sqliteBtreeCloseCursor(curMain);
|
||||
return rc;
|
||||
}
|
||||
db->schema_cookie = meta[1];
|
||||
db->next_cookie = db->schema_cookie;
|
||||
db->next_cookie = db->aDb[0].schema_cookie = meta[1];
|
||||
db->file_format = meta[2];
|
||||
size = meta[3];
|
||||
if( size==0 ){ size = MAX_PAGES; }
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->pBe, size);
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, size);
|
||||
db->safety_level = meta[4];
|
||||
if( db->safety_level==0 ) db->safety_level = 2;
|
||||
sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
|
||||
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
||||
|
||||
/*
|
||||
** file_format==1 Version 2.1.0.
|
||||
@@ -297,7 +296,6 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
*/
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.pBe = db->pBe;
|
||||
sParse.xCallback = sqliteInitCallback;
|
||||
sParse.pArg = (void*)&initData;
|
||||
sParse.initFlag = 1;
|
||||
@@ -308,7 +306,7 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
if( sqlite_malloc_failed ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", 0);
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
sqliteBtreeRollback(db->pBe);
|
||||
sqliteBtreeRollback(db->aDb[0].pBt);
|
||||
sqliteResetInternalSchema(db);
|
||||
}
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
@@ -363,9 +361,11 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
||||
db->onError = OE_Default;
|
||||
db->priorNewRowid = 0;
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
db->nDb = 2;
|
||||
db->aDb = db->aDbStatic;
|
||||
|
||||
/* Open the backend database driver */
|
||||
rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->pBe);
|
||||
rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
switch( rc ){
|
||||
default: {
|
||||
@@ -376,6 +376,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
return 0;
|
||||
}
|
||||
db->aDb[0].zName = "main";
|
||||
|
||||
/* Attempt to read the schema */
|
||||
sqliteRegisterBuiltinFunctions(db);
|
||||
@@ -412,9 +413,9 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
||||
&initData,
|
||||
&zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteBtreeGetMeta(db->pBe, meta);
|
||||
sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
|
||||
meta[2] = 4;
|
||||
sqliteBtreeUpdateMeta(db->pBe, meta);
|
||||
sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
|
||||
sqlite_exec(db, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -457,17 +458,22 @@ int sqlite_changes(sqlite *db){
|
||||
*/
|
||||
void sqlite_close(sqlite *db){
|
||||
HashElem *i;
|
||||
int j;
|
||||
db->want_to_close = 1;
|
||||
if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){
|
||||
/* printf("DID NOT CLOSE\n"); fflush(stdout); */
|
||||
return;
|
||||
}
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
sqliteBtreeClose(db->pBe);
|
||||
sqliteResetInternalSchema(db);
|
||||
if( db->pBeTemp ){
|
||||
sqliteBtreeClose(db->pBeTemp);
|
||||
for(j=0; j<db->nDb; j++){
|
||||
if( db->aDb[j].pBt ){
|
||||
sqliteBtreeClose(db->aDb[j].pBt);
|
||||
}
|
||||
}
|
||||
if( db->aDb!=db->aDbStatic ){
|
||||
sqliteFree(db->aDb);
|
||||
}
|
||||
sqliteResetInternalSchema(db);
|
||||
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
|
||||
FuncDef *pFunc, *pNext;
|
||||
for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
|
||||
@@ -592,6 +598,20 @@ int sqlite_complete(const char *zSql){
|
||||
return seenText && isComplete && requireEnd==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Rollback all database files.
|
||||
*/
|
||||
void sqliteRollbackAll(sqlite *db){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
sqliteBtreeRollback(db->aDb[i].pBt);
|
||||
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()
|
||||
@@ -632,7 +652,6 @@ static int sqliteMain(
|
||||
if( db->pVdbe==0 ){ db->nChange = 0; }
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.pBe = db->pBe;
|
||||
sParse.xCallback = xCallback;
|
||||
sParse.pArg = pArg;
|
||||
sParse.useCallback = ppVm==0;
|
||||
@@ -643,10 +662,9 @@ static int sqliteMain(
|
||||
if( sqlite_malloc_failed ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", 0);
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
sqliteBtreeRollback(db->pBe);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
sqliteRollbackAll(db);
|
||||
sqliteResetInternalSchema(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
}
|
||||
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
|
||||
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
|
||||
@@ -965,10 +983,10 @@ int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg){
|
||||
if( zName && zName[0]==0 ) zName = 0;
|
||||
if( sqliteSafetyOn(db) ) goto openaux_misuse;
|
||||
sqliteResetInternalSchema(db);
|
||||
if( db->pBeTemp!=0 ){
|
||||
sqliteBtreeClose(db->pBeTemp);
|
||||
if( db->aDb[1].pBt!=0 ){
|
||||
sqliteBtreeClose(db->aDb[1].pBt);
|
||||
}
|
||||
rc = sqliteBtreeOpen(zName, 0, MAX_PAGES, &db->pBeTemp);
|
||||
rc = sqliteBtreeOpen(zName, 0, MAX_PAGES, &db->aDb[1].pBt);
|
||||
if( rc ){
|
||||
if( zName==0 ) zName = "a temporary file";
|
||||
sqliteSetString(pzErrMsg, "unable to open ", zName,
|
||||
|
||||
24
src/os.c
24
src/os.c
@@ -268,6 +268,30 @@ int sqliteOsFileExists(const char *zFilename){
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Change the name of an existing file.
|
||||
*/
|
||||
int sqliteOsRename(const char *zOldName, const char *zNewName){
|
||||
#if OS_UNIX
|
||||
if( link(zOldName, zNewName) ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
unlink(zOldName);
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
#if OS_WIN
|
||||
if( !MoveFile(zOldName, zNewName) ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
#if OS_MAC
|
||||
/**** FIX ME ***/
|
||||
return SQLITE_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Attempt to open a file for both reading and writing. If that
|
||||
** fails, try opening it read-only. If the file does not exist,
|
||||
|
||||
1
src/os.h
1
src/os.h
@@ -147,6 +147,7 @@
|
||||
|
||||
int sqliteOsDelete(const char*);
|
||||
int sqliteOsFileExists(const char*);
|
||||
int sqliteOsFileRename(const char*, const char*);
|
||||
int sqliteOsOpenReadWrite(const char*, OsFile*, int*);
|
||||
int sqliteOsOpenExclusive(const char*, OsFile*, int);
|
||||
int sqliteOsOpenReadOnly(const char*, OsFile*);
|
||||
|
||||
21
src/pager.c
21
src/pager.c
@@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.78 2003/02/16 19:13:37 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.79 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
#include "os.h" /* Must be first to enable large file support */
|
||||
#include "sqliteInt.h"
|
||||
@@ -1722,6 +1722,25 @@ int sqlitepager_iswriteable(void *pData){
|
||||
return pPg->dirty;
|
||||
}
|
||||
|
||||
/*
|
||||
** Replace the content of a single page with the information in the third
|
||||
** argument.
|
||||
*/
|
||||
int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void *pData){
|
||||
void *pPage;
|
||||
int rc;
|
||||
|
||||
rc = sqlitepager_get(pPager, pgno, &pPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlitepager_write(pPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(pPage, pData, SQLITE_PAGE_SIZE);
|
||||
}
|
||||
sqlitepager_unref(pPage);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** A call to this routine tells the pager that it is not necessary to
|
||||
** write the information on page "pgno" back to the disk, even though
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.20 2003/02/12 14:09:44 drh Exp $
|
||||
** @(#) $Id: pager.h,v 1.21 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -59,6 +59,7 @@ int sqlitepager_unref(void*);
|
||||
Pgno sqlitepager_pagenumber(void*);
|
||||
int sqlitepager_write(void*);
|
||||
int sqlitepager_iswriteable(void*);
|
||||
int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void*);
|
||||
int sqlitepager_pagecount(Pager*);
|
||||
int sqlitepager_begin(void*);
|
||||
int sqlitepager_commit(Pager*);
|
||||
|
||||
@@ -687,7 +687,6 @@ static void mout(void *arg, char *zNewText, int nNewChar){
|
||||
char *sqliteMPrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
struct sgMprintf sMprintf;
|
||||
char *zNew;
|
||||
char zBuf[200];
|
||||
|
||||
sMprintf.nChar = 0;
|
||||
|
||||
13
src/select.c
13
src/select.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.126 2003/02/02 12:41:26 drh Exp $
|
||||
** $Id: select.c,v 1.127 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -1768,7 +1768,6 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
Index *pIdx;
|
||||
int base;
|
||||
Vdbe *v;
|
||||
int openOp;
|
||||
int seekOp;
|
||||
int cont;
|
||||
ExprList eList;
|
||||
@@ -1828,17 +1827,17 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
** or last entry in the main table.
|
||||
*/
|
||||
if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
sqliteCodeVerifySchema(pParse);
|
||||
}
|
||||
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
|
||||
base = p->base;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
if( pIdx==0 ){
|
||||
sqliteVdbeAddOp(v, seekOp, base, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, openOp, base+1, pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, seekOp, base+1, 0);
|
||||
sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.162 2003/02/16 22:21:32 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.163 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "sqlite.h"
|
||||
@@ -187,6 +187,21 @@ typedef struct Trigger Trigger;
|
||||
typedef struct TriggerStep TriggerStep;
|
||||
typedef struct TriggerStack TriggerStack;
|
||||
typedef struct FKey FKey;
|
||||
typedef struct Db Db;
|
||||
|
||||
/*
|
||||
** Each database file to be accessed by the system is an instance
|
||||
** of the following structure. There are normally two of these structures
|
||||
** in the sqlite.aDb[] array. aDb[0] is the main database file and
|
||||
** aDb[1] is the database file used to hold temporary tables. But
|
||||
** additional databases may be attached to the engine.
|
||||
*/
|
||||
struct Db {
|
||||
char *zName; /* Name of this database */
|
||||
Btree *pBt; /* The B*Tree structure for this database file */
|
||||
int schema_cookie; /* Database schema version number for this file */
|
||||
u8 inTrans; /* True if a transaction is underway for this backend */
|
||||
};
|
||||
|
||||
/*
|
||||
** Each database is an instance of the following structure.
|
||||
@@ -204,14 +219,14 @@ typedef struct FKey FKey;
|
||||
** text datatypes.
|
||||
*/
|
||||
struct sqlite {
|
||||
Btree *pBe; /* The B*Tree backend */
|
||||
Btree *pBeTemp; /* Backend for session temporary tables */
|
||||
int nDb; /* Number of backends currently in use */
|
||||
Db *aDb; /* All backends */
|
||||
Db aDbStatic[2]; /* Static space for the 2 default backends */
|
||||
int flags; /* Miscellanous flags. See below */
|
||||
u8 file_format; /* What file format version is this database? */
|
||||
u8 safety_level; /* How aggressive at synching data to disk */
|
||||
u8 want_to_close; /* Close after all VDBEs are deallocated */
|
||||
int schema_cookie; /* Magic number that changes with the schema */
|
||||
int next_cookie; /* Value of schema_cookie after commit */
|
||||
int next_cookie; /* Next value of aDb[0].schema_cookie */
|
||||
int cache_size; /* Number of pages to use in the cache */
|
||||
int nTable; /* Number of tables in the database */
|
||||
void *pBusyArg; /* 1st Argument to the busy callback */
|
||||
@@ -348,7 +363,7 @@ struct Table {
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
Select *pSelect; /* NULL for tables. Points to definition if a view. */
|
||||
u8 readOnly; /* True if this table should not be written by the user */
|
||||
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
|
||||
u8 isTemp; /* Index into sqlite.aDb[] of the backend for this table */
|
||||
u8 isTransient; /* True if automatically deleted when VDBE finishes */
|
||||
u8 hasPrimKey; /* True if there exists a primary key */
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
@@ -731,7 +746,6 @@ struct AggExpr {
|
||||
*/
|
||||
struct Parse {
|
||||
sqlite *db; /* The main database structure */
|
||||
Btree *pBe; /* The database backend */
|
||||
int rc; /* Return code from execution */
|
||||
sqlite_callback xCallback; /* The callback function */
|
||||
void *pArg; /* First argument to the callback function */
|
||||
@@ -1003,6 +1017,8 @@ int sqliteExprAnalyzeAggregates(Parse*, Expr*);
|
||||
Vdbe *sqliteGetVdbe(Parse*);
|
||||
int sqliteRandomByte(void);
|
||||
int sqliteRandomInteger(void);
|
||||
void sqliteRollbackAll(sqlite*);
|
||||
void sqliteCodeVerifySchema(Parse*);
|
||||
void sqliteBeginTransaction(Parse*, int);
|
||||
void sqliteCommitTransaction(Parse*);
|
||||
void sqliteRollbackTransaction(Parse*);
|
||||
|
||||
13
src/update.c
13
src/update.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.53 2003/01/13 23:27:33 drh Exp $
|
||||
** $Id: update.c,v 1.54 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -42,7 +42,6 @@ void sqliteUpdate(
|
||||
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
|
||||
** an expression for the i-th column of the table.
|
||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||
int openOp; /* Opcode used to open tables */
|
||||
int chngRecno; /* True if the record number is being changed */
|
||||
Expr *pRecnoExpr; /* Expression defining the new record number */
|
||||
int openAll; /* True if all indices need to be opened */
|
||||
@@ -232,7 +231,8 @@ void sqliteUpdate(
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqliteVdbeAddOp(v, (pTab->isTemp?OP_OpenAux:OP_Open), base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
|
||||
sqliteVdbeAddOp(v, OP_Integer, 13, 0);
|
||||
@@ -277,8 +277,8 @@ void sqliteUpdate(
|
||||
** action, then we need to open all indices because we might need
|
||||
** to be deleting some records.
|
||||
*/
|
||||
openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
|
||||
if( onError==OE_Replace ){
|
||||
openAll = 1;
|
||||
}else{
|
||||
@@ -292,7 +292,8 @@ void sqliteUpdate(
|
||||
}
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] ){
|
||||
sqliteVdbeAddOp(v, openOp, base+i+1, pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, pIdx->tnum);
|
||||
assert( pParse->nTab>base+i+1 );
|
||||
}
|
||||
}
|
||||
|
||||
230
src/vdbe.c
230
src/vdbe.c
@@ -36,7 +36,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.207 2003/03/07 19:50:07 drh Exp $
|
||||
** $Id: vdbe.c,v 1.208 2003/03/19 03:14:02 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -243,7 +243,6 @@ struct Keylist {
|
||||
struct Vdbe {
|
||||
sqlite *db; /* The whole database */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
Btree *pBt; /* Opaque context structure used by DB backend */
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
@@ -315,7 +314,6 @@ Vdbe *sqliteVdbeCreate(sqlite *db){
|
||||
Vdbe *p;
|
||||
p = sqliteMalloc( sizeof(Vdbe) );
|
||||
if( p==0 ) return 0;
|
||||
p->pBt = db->pBe;
|
||||
p->db = db;
|
||||
if( db->pVdbe ){
|
||||
db->pVdbe->pPrev = p;
|
||||
@@ -1212,6 +1210,7 @@ static void Cleanup(Vdbe *p){
|
||||
*/
|
||||
void sqliteVdbeDelete(Vdbe *p){
|
||||
int i;
|
||||
sqlite *db = p->db;
|
||||
if( p==0 ) return;
|
||||
Cleanup(p);
|
||||
if( p->pPrev ){
|
||||
@@ -1233,6 +1232,13 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
sqliteFree(p->aOp[i].p3);
|
||||
}
|
||||
}
|
||||
for(i=2; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt && db->aDb[i].zName==0 ){
|
||||
sqliteBtreeClose(db->aDb[i].pBt);
|
||||
db->aDb[i].pBt = 0;
|
||||
db->aDb[i].inTrans = 0;
|
||||
}
|
||||
}
|
||||
sqliteFree(p->aOp);
|
||||
sqliteFree(p->aLabel);
|
||||
sqliteFree(p->aStack);
|
||||
@@ -1584,7 +1590,6 @@ int sqliteVdbeExec(
|
||||
int pc; /* The program counter */
|
||||
Op *pOp; /* Current operation */
|
||||
int rc = SQLITE_OK; /* Value to return */
|
||||
Btree *pBt = p->pBt; /* The backend driver */
|
||||
sqlite *db = p->db; /* The database */
|
||||
char **zStack = p->zStack; /* Text stack */
|
||||
Stack *aStack = p->aStack; /* Additional stack information */
|
||||
@@ -1894,6 +1899,7 @@ case OP_Push: {
|
||||
** to all column names is passed as the 4th parameter to the callback.
|
||||
*/
|
||||
case OP_ColumnName: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nOp );
|
||||
p->azColName[pOp->p1] = pOp->p3;
|
||||
p->nCallback = 0;
|
||||
break;
|
||||
@@ -3154,17 +3160,21 @@ case OP_IncrKey: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Checkpoint * * *
|
||||
/* Opcode: Checkpoint P1 * *
|
||||
**
|
||||
** Begin a checkpoint. A checkpoint is the beginning of a operation that
|
||||
** is part of a larger transaction but which might need to be rolled back
|
||||
** itself without effecting the containing transaction. A checkpoint will
|
||||
** be automatically committed or rollback when the VDBE halts.
|
||||
**
|
||||
** The checkpoint is begun on the database file with index P1. The main
|
||||
** database file has an index of 0 and the file used for temporary tables
|
||||
** has an index of 1.
|
||||
*/
|
||||
case OP_Checkpoint: {
|
||||
rc = sqliteBtreeBeginCkpt(pBt);
|
||||
if( rc==SQLITE_OK && db->pBeTemp ){
|
||||
rc = sqliteBtreeBeginCkpt(db->pBeTemp);
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<db->nDb && db->aDb[i].pBt ){
|
||||
rc = sqliteBtreeBeginCkpt(db->aDb[i].pBt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3175,10 +3185,9 @@ case OP_Checkpoint: {
|
||||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
** transaction might also be rolled back if an error is encountered.
|
||||
**
|
||||
** If P1 is true, then the transaction is started on the temporary
|
||||
** tables of the database only. The main database file is not write
|
||||
** locked and other processes can continue to read the main database
|
||||
** file.
|
||||
** P1 is the index of the database file on which the transaction is
|
||||
** started. Index 0 is the main database file and index 1 is the
|
||||
** file used for temporary tables.
|
||||
**
|
||||
** A write lock is obtained on the database file when a transaction is
|
||||
** started. No other process can read or write the file while the
|
||||
@@ -3188,15 +3197,9 @@ case OP_Checkpoint: {
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
int busy = 1;
|
||||
if( db->pBeTemp && !p->inTempTrans ){
|
||||
rc = sqliteBtreeBeginTrans(db->pBeTemp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
p->inTempTrans = 1;
|
||||
}
|
||||
while( pOp->p1==0 && busy ){
|
||||
rc = sqliteBtreeBeginTrans(pBt);
|
||||
int i = pOp->p1;
|
||||
while( i>=0 && i<db->nDb && db->aDb[i].pBt!=0 && busy ){
|
||||
rc = sqliteBtreeBeginTrans(db->aDb[i].pBt);
|
||||
switch( rc ){
|
||||
case SQLITE_BUSY: {
|
||||
if( db->xBusyCallback==0 ){
|
||||
@@ -3224,6 +3227,7 @@ case OP_Transaction: {
|
||||
}
|
||||
}
|
||||
}
|
||||
db->aDb[i].inTrans = 1;
|
||||
p->undoTransOnError = 1;
|
||||
break;
|
||||
}
|
||||
@@ -3237,53 +3241,48 @@ case OP_Transaction: {
|
||||
** A read lock continues to be held if there are still cursors open.
|
||||
*/
|
||||
case OP_Commit: {
|
||||
if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
|
||||
rc = p->inTempTrans ? SQLITE_OK : sqliteBtreeCommit(pBt);
|
||||
int i;
|
||||
assert( rc==SQLITE_OK );
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
if( db->aDb[i].inTrans ){
|
||||
rc = sqliteBtreeCommit(db->aDb[i].pBt);
|
||||
db->aDb[i].inTrans = 0;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteCommitInternalChanges(db);
|
||||
}else{
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteBtreeRollback(pBt);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
sqliteRollbackAll(db);
|
||||
}
|
||||
p->inTempTrans = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Rollback * * *
|
||||
/* Opcode: Rollback P1 * *
|
||||
**
|
||||
** Cause all modifications to the database that have been made since the
|
||||
** last Transaction to be undone. The database is restored to its state
|
||||
** before the Transaction opcode was executed. No additional modifications
|
||||
** are allowed until another transaction is started.
|
||||
**
|
||||
** P1 is the index of the database file that is committed. An index of 0
|
||||
** is used for the main database and an index of 1 is used for the file used
|
||||
** to hold temporary tables.
|
||||
**
|
||||
** This instruction automatically closes all cursors and releases both
|
||||
** the read and write locks on the database.
|
||||
** the read and write locks on the indicated database.
|
||||
*/
|
||||
case OP_Rollback: {
|
||||
if( db->pBeTemp ){
|
||||
sqliteBtreeRollback(db->pBeTemp);
|
||||
}
|
||||
rc = sqliteBtreeRollback(pBt);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
sqliteRollbackAll(db);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ReadCookie * P2 *
|
||||
/* Opcode: ReadCookie P1 P2 *
|
||||
**
|
||||
** When P2==0,
|
||||
** read the schema cookie from the database file and push it onto the
|
||||
** stack. The schema cookie is an integer that is used like a version
|
||||
** number for the database schema. Everytime the schema changes, the
|
||||
** cookie changes to a new random value. This opcode is used during
|
||||
** initialization to read the initial cookie value so that subsequent
|
||||
** database accesses can verify that the cookie has not changed.
|
||||
**
|
||||
** If P2>0, then read global database parameter number P2. There is
|
||||
** a small fixed number of global database parameters. P2==1 is the
|
||||
** database version number. P2==2 is the recommended pager cache size.
|
||||
** Other parameters are currently unused.
|
||||
** Read cookie number P2 from database P1 and push it onto the stack.
|
||||
** P2==0 is the schema version. P2==1 is the database format.
|
||||
** P2==2 is the recommended pager cache size, and so forth. P1==0 is
|
||||
** the main database file and P1==1 is the database file used to store
|
||||
** temporary tables.
|
||||
**
|
||||
** There must be a read-lock on the database (either a transaction
|
||||
** must be started or there must be an open cursor) before
|
||||
@@ -3293,36 +3292,35 @@ case OP_ReadCookie: {
|
||||
int i = ++p->tos;
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( db->aDb[pOp->p1].pBt!=0 );
|
||||
rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
aStack[i].i = aMeta[1+pOp->p2];
|
||||
aStack[i].flags = STK_Int;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetCookie * P2 *
|
||||
/* Opcode: SetCookie P1 P2 *
|
||||
**
|
||||
** When P2==0,
|
||||
** this operation changes the value of the schema cookie on the database.
|
||||
** The new value is top of the stack.
|
||||
** When P2>0, the value of global database parameter
|
||||
** number P2 is changed. See ReadCookie for more information about
|
||||
** global database parametes.
|
||||
**
|
||||
** The schema cookie changes its value whenever the database schema changes.
|
||||
** That way, other processes can recognize when the schema has changed
|
||||
** and reread it.
|
||||
** Write the top of the stack into cookie number P2 of database P1.
|
||||
** P2==0 is the schema version. P2==1 is the database format.
|
||||
** P2==2 is the recommended pager cache size, and so forth. P1==0 is
|
||||
** the main database file and P1==1 is the database file used to store
|
||||
** temporary tables.
|
||||
**
|
||||
** A transaction must be started before executing this opcode.
|
||||
*/
|
||||
case OP_SetCookie: {
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( db->aDb[pOp->p1].pBt!=0 );
|
||||
VERIFY( if( p->tos<0 ) goto not_enough_stack; )
|
||||
Integerify(p, p->tos)
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
if( rc==SQLITE_OK ){
|
||||
aMeta[1+pOp->p2] = aStack[p->tos].i;
|
||||
rc = sqliteBtreeUpdateMeta(pBt, aMeta);
|
||||
rc = sqliteBtreeUpdateMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
@@ -3330,10 +3328,11 @@ case OP_SetCookie: {
|
||||
|
||||
/* Opcode: VerifyCookie P1 P2 *
|
||||
**
|
||||
** Check the value of global database parameter number P2 and make
|
||||
** sure it is equal to P1. P2==0 is the schema cookie. P1==1 is
|
||||
** the database version. If the values do not match, abort with
|
||||
** an SQLITE_SCHEMA error.
|
||||
** Check the value of global database parameter number 0 (the
|
||||
** schema version) and make sure it is equal to P2.
|
||||
** P1 is the database number which is 0 for the main database file
|
||||
** and 1 for the file holding temporary tables and some higher number
|
||||
** for auxiliary databases.
|
||||
**
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
@@ -3345,23 +3344,27 @@ case OP_SetCookie: {
|
||||
*/
|
||||
case OP_VerifyCookie: {
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( db->aDb[pOp->p1].zName!=0 );
|
||||
rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
if( rc==SQLITE_OK && aMeta[1]!=pOp->p2 ){
|
||||
sqliteSetString(&p->zErrMsg, "database schema has changed", 0);
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Open P1 P2 P3
|
||||
/* Opcode: OpenRead P1 P2 P3
|
||||
**
|
||||
** Open a read-only cursor for the database table whose root page is
|
||||
** P2 in the main database file. Give the new cursor an identifier
|
||||
** of P1. The P1 values need not be contiguous but all P1 values
|
||||
** should be small integers. It is an error for P1 to be negative.
|
||||
** P2 in a database file. The database file is determined by an
|
||||
** integer from the top of the stack. 0 means the main database and
|
||||
** 1 means the database used for temporary tables. Give the new
|
||||
** cursor an identifier of P1. The P1 values need not be contiguous
|
||||
** but all P1 values should be small integers. It is an error for
|
||||
** P1 to be negative.
|
||||
**
|
||||
** If P2==0 then take the root page number from the top of the stack.
|
||||
** If P2==0 then take the root page number from the next of the stack.
|
||||
**
|
||||
** There will be a read lock on the database whenever there is an
|
||||
** open cursor. If the database was unlocked prior to this instruction
|
||||
@@ -3377,52 +3380,39 @@ case OP_VerifyCookie: {
|
||||
** omitted. But the code generator usually inserts the index or
|
||||
** table name into P3 to make the code easier to read.
|
||||
**
|
||||
** See also OpenAux and OpenWrite.
|
||||
*/
|
||||
/* Opcode: OpenAux P1 P2 P3
|
||||
**
|
||||
** Open a read-only cursor in the auxiliary table set. This opcode
|
||||
** works exactly like OP_Open except that it opens the cursor on the
|
||||
** auxiliary table set (the file used to store tables created using
|
||||
** CREATE TEMPORARY TABLE) instead of in the main database file.
|
||||
** See OP_Open for additional information.
|
||||
** See also OpenWrite.
|
||||
*/
|
||||
/* Opcode: OpenWrite P1 P2 P3
|
||||
**
|
||||
** Open a read/write cursor named P1 on the table or index whose root
|
||||
** page is P2. If P2==0 then take the root page number from the stack.
|
||||
**
|
||||
** This instruction works just like Open except that it opens the cursor
|
||||
** This instruction works just like OpenRead except that it opens the cursor
|
||||
** in read/write mode. For a given table, there can be one or more read-only
|
||||
** cursors or a single read/write cursor but not both.
|
||||
**
|
||||
** See also OpWrAux.
|
||||
** See also OpenRead.
|
||||
*/
|
||||
/* Opcode: OpenWrAux P1 P2 P3
|
||||
**
|
||||
** Open a read/write cursor in the auxiliary table set. This opcode works
|
||||
** just like OpenWrite except that the auxiliary table set (the file used
|
||||
** to store tables created using CREATE TEMPORARY TABLE) is used in place
|
||||
** of the main database file.
|
||||
*/
|
||||
case OP_OpenAux:
|
||||
case OP_OpenWrAux:
|
||||
case OP_OpenWrite:
|
||||
case OP_Open: {
|
||||
case OP_OpenRead:
|
||||
case OP_OpenWrite: {
|
||||
int busy = 0;
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
int p2 = pOp->p2;
|
||||
int wrFlag;
|
||||
Btree *pX;
|
||||
switch( pOp->opcode ){
|
||||
case OP_Open: wrFlag = 0; pX = pBt; break;
|
||||
case OP_OpenWrite: wrFlag = 1; pX = pBt; break;
|
||||
case OP_OpenAux: wrFlag = 0; pX = db->pBeTemp; break;
|
||||
case OP_OpenWrAux: wrFlag = 1; pX = db->pBeTemp; break;
|
||||
}
|
||||
int iDb;
|
||||
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; );
|
||||
Integerify(p, tos);
|
||||
iDb = p->aStack[tos].i;
|
||||
tos--;
|
||||
VERIFY( if( iDb<0 || iDb>=db->nDb ) goto bad_instruction; );
|
||||
VERIFY( if( db->aDb[iDb].pBt==0 ) goto bad_instruction; );
|
||||
pX = db->aDb[iDb].pBt;
|
||||
wrFlag = pOp->opcode==OP_OpenWrite;
|
||||
if( p2<=0 ){
|
||||
if( tos<0 ) goto not_enough_stack;
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; );
|
||||
Integerify(p, tos);
|
||||
p2 = p->aStack[tos].i;
|
||||
POPSTACK;
|
||||
@@ -3464,6 +3454,7 @@ case OP_Open: {
|
||||
if( p2<=0 ){
|
||||
POPSTACK;
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4448,7 +4439,7 @@ case OP_IdxGE: {
|
||||
** See also: Clear
|
||||
*/
|
||||
case OP_Destroy: {
|
||||
sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
|
||||
sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4465,7 +4456,7 @@ case OP_Destroy: {
|
||||
** See also: Destroy
|
||||
*/
|
||||
case OP_Clear: {
|
||||
sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
|
||||
sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4499,10 +4490,12 @@ case OP_CreateTable: {
|
||||
int i = ++p->tos;
|
||||
int pgno;
|
||||
assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
|
||||
assert( pOp->p2>=0 && pOp->p2<db->nDb );
|
||||
assert( db->aDb[pOp->p2].pBt!=0 );
|
||||
if( pOp->opcode==OP_CreateTable ){
|
||||
rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
rc = sqliteBtreeCreateTable(db->aDb[pOp->p2].pBt, &pgno);
|
||||
}else{
|
||||
rc = sqliteBtreeCreateIndex(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
rc = sqliteBtreeCreateIndex(db->aDb[pOp->p2].pBt, &pgno);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
aStack[i].i = pgno;
|
||||
@@ -4546,7 +4539,7 @@ case OP_IntegrityCk: {
|
||||
toInt((char*)sqliteHashKey(i), &aRoot[j]);
|
||||
}
|
||||
aRoot[j] = 0;
|
||||
z = sqliteBtreeIntegrityCheck(pOp->p2 ? db->pBeTemp : pBt, aRoot, nRoot);
|
||||
z = sqliteBtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
|
||||
if( z==0 || z[0]==0 ){
|
||||
if( z ) sqliteFree(z);
|
||||
zStack[tos] = "ok";
|
||||
@@ -5671,8 +5664,7 @@ bad_instruction:
|
||||
*/
|
||||
int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
||||
sqlite *db = p->db;
|
||||
Btree *pBt = p->pBt;
|
||||
int rc;
|
||||
int i, rc;
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
|
||||
@@ -5691,23 +5683,24 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
||||
switch( p->errorAction ){
|
||||
case OE_Abort: {
|
||||
if( !p->undoTransOnError ){
|
||||
sqliteBtreeRollbackCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
sqliteBtreeRollbackCkpt(db->aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Fall through to ROLLBACK */
|
||||
}
|
||||
case OE_Rollback: {
|
||||
sqliteBtreeRollback(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteRollbackAll(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( p->undoTransOnError ){
|
||||
sqliteBtreeCommit(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp);
|
||||
sqliteRollbackAll(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
}
|
||||
@@ -5716,8 +5709,11 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
||||
}
|
||||
sqliteRollbackInternalChanges(db);
|
||||
}
|
||||
sqliteBtreeCommitCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
sqliteBtreeCommitCkpt(db->aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
assert( p->tos<p->pc || sqlite_malloc_failed==1 );
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
|
||||
14
src/where.c
14
src/where.c
@@ -13,7 +13,7 @@
|
||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||
** to generate VDBE code to evaluate expressions.
|
||||
**
|
||||
** $Id: where.c,v 1.72 2003/01/31 17:21:50 drh Exp $
|
||||
** $Id: where.c,v 1.73 2003/03/19 03:14:03 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -636,21 +636,21 @@ WhereInfo *sqliteWhereBegin(
|
||||
/* Open all tables in the pTabList and all indices used by those tables.
|
||||
*/
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
int openOp;
|
||||
Table *pTab;
|
||||
|
||||
pTab = pTabList->a[i].pTab;
|
||||
if( pTab->isTransient || pTab->pSelect ) continue;
|
||||
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
|
||||
sqliteVdbeAddOp(v, openOp, base+i, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, base+i, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
if( i==0 && !pParse->schemaVerified &&
|
||||
(pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
sqliteCodeVerifySchema(pParse);
|
||||
}
|
||||
if( pWInfo->a[i].pIdx!=0 ){
|
||||
sqliteVdbeAddOp(v, openOp, pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead,
|
||||
pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user