aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/os_unix.c6
-rw-r--r--src/os_win.c2
-rw-r--r--src/pager.c38
-rw-r--r--src/sqlite.h.in23
-rw-r--r--src/test_vfs.c263
-rw-r--r--src/vdbe.c11
-rw-r--r--src/vdbeblob.c4
7 files changed, 287 insertions, 60 deletions
diff --git a/src/os_unix.c b/src/os_unix.c
index e949c20cd..77aafccce 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -4604,6 +4604,12 @@ static int unixAccess(
assert(!"Invalid flags argument");
}
*pResOut = (access(zPath, amode)==0);
+ if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
+ struct stat buf;
+ if( 0==stat(zPath, &buf) && buf.st_size==0 ){
+ *pResOut = 0;
+ }
+ }
return SQLITE_OK;
}
diff --git a/src/os_win.c b/src/os_win.c
index ec62e394c..24d0e7ca3 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -1151,7 +1151,7 @@ static int winSectorSize(sqlite3_file *id){
*/
static int winDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(id);
- return 0;
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}
/****************************************************************************
diff --git a/src/pager.c b/src/pager.c
index c875dd9df..a5377d4c3 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -1219,12 +1219,24 @@ static int pagerUseWal(Pager *pPager){
static void pager_unlock(Pager *pPager){
if( !pPager->exclusiveMode ){
int rc = SQLITE_OK; /* Return code */
+ int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
/* Always close the journal file when dropping the database lock.
** Otherwise, another connection with journal_mode=delete might
** delete the file out from under us.
*/
- sqlite3OsClose(pPager->jfd);
+ assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+ if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)
+ || 1!=(pPager->journalMode & 5)
+ ){
+ sqlite3OsClose(pPager->jfd);
+ }
+
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
releaseAllSavepoints(pPager);
@@ -3115,6 +3127,7 @@ int sqlite3PagerClose(Pager *pPager){
enable_simulated_io_errors();
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
IOTRACE(("CLOSE %p\n", pPager))
+ sqlite3OsClose(pPager->jfd);
sqlite3OsClose(pPager->fd);
sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
@@ -3908,17 +3921,22 @@ int sqlite3PagerOpen(
*/
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
- int rc; /* Return code */
- int exists; /* True if a journal file is present */
+ int rc = SQLITE_OK; /* Return code */
+ int exists = 1; /* True if a journal file is present */
+ int jrnlOpen = !!isOpen(pPager->jfd);
assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
- assert( !isOpen(pPager->jfd) );
assert( pPager->state <= PAGER_SHARED );
+ assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
+ SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+ ));
*pExists = 0;
- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( !jrnlOpen ){
+ rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ }
if( rc==SQLITE_OK && exists ){
int locked; /* True if some process holds a RESERVED lock */
@@ -3956,15 +3974,19 @@ static int hasHotJournal(Pager *pPager, int *pExists){
** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
- int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ if( !jrnlOpen ){
+ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ }
if( rc==SQLITE_OK ){
u8 first = 0;
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
- sqlite3OsClose(pPager->jfd);
+ if( !jrnlOpen ){
+ sqlite3OsClose(pPager->jfd);
+ }
*pExists = (first!=0);
}else if( rc==SQLITE_CANTOPEN ){
/* If we cannot open the rollback journal file in order to see if
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 28778f7fc..f91f25b3f 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -497,17 +497,18 @@ int sqlite3_exec(
** information is written to disk in the same order as calls
** to xWrite().
*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_ATOMIC 0x00000001
+#define SQLITE_IOCAP_ATOMIC512 0x00000002
+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
/*
** CAPI3REF: File Locking Levels
diff --git a/src/test_vfs.c b/src/test_vfs.c
index e94bef7d2..46f3a0630 100644
--- a/src/test_vfs.c
+++ b/src/test_vfs.c
@@ -58,6 +58,13 @@ struct Testvfs {
int iIoerrCnt;
int ioerr;
int nIoerrFail;
+
+ int iFullCnt;
+ int fullerr;
+ int nFullFail;
+
+ int iDevchar;
+ int iSectorsize;
};
/*
@@ -77,7 +84,10 @@ struct Testvfs {
#define TESTVFS_OPEN_MASK 0x00000100
#define TESTVFS_SYNC_MASK 0x00000200
#define TESTVFS_DELETE_MASK 0x00000400
-#define TESTVFS_ALL_MASK 0x000007FF
+#define TESTVFS_CLOSE_MASK 0x00000800
+#define TESTVFS_WRITE_MASK 0x00001000
+#define TESTVFS_TRUNCATE_MASK 0x00002000
+#define TESTVFS_ALL_MASK 0x00003FFF
#define TESTVFS_MAX_PAGES 256
@@ -187,6 +197,30 @@ static int tvfsResultCode(Testvfs *p, int *pRc){
return 0;
}
+static int tvfsInjectIoerr(Testvfs *p){
+ int ret = 0;
+ if( p->ioerr ){
+ p->iIoerrCnt--;
+ if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
+ ret = 1;
+ p->nIoerrFail++;
+ }
+ }
+ return ret;
+}
+
+static int tvfsInjectFullerr(Testvfs *p){
+ int ret = 0;
+ if( p->fullerr ){
+ p->iFullCnt--;
+ if( p->iFullCnt<=0 ){
+ ret = 1;
+ p->nFullFail++;
+ }
+ }
+ return ret;
+}
+
static void tvfsExecTcl(
Testvfs *p,
@@ -245,15 +279,23 @@ static void tvfsExecTcl(
** Close an tvfs-file.
*/
static int tvfsClose(sqlite3_file *pFile){
- TestvfsFile *p = (TestvfsFile *)pFile;
- if( p->pShmId ){
- Tcl_DecrRefCount(p->pShmId);
- p->pShmId = 0;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+
+ if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){
+ tvfsExecTcl(p, "xClose",
+ Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
+ );
+ }
+
+ if( pFd->pShmId ){
+ Tcl_DecrRefCount(pFd->pShmId);
+ pFd->pShmId = 0;
}
if( pFile->pMethods ){
ckfree((char *)pFile->pMethods);
}
- return sqlite3OsClose(p->pReal);
+ return sqlite3OsClose(pFd->pReal);
}
/*
@@ -278,16 +320,44 @@ static int tvfsWrite(
int iAmt,
sqlite_int64 iOfst
){
- TestvfsFile *p = (TestvfsFile *)pFile;
- return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
+ int rc = SQLITE_OK;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+
+ if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){
+ tvfsExecTcl(p, "xWrite",
+ Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
+ );
+ tvfsResultCode(p, &rc);
+ }
+
+ if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst);
+ }
+ return rc;
}
/*
** Truncate an tvfs-file.
*/
static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
- TestvfsFile *p = (TestvfsFile *)pFile;
- return sqlite3OsTruncate(p->pReal, size);
+ int rc = SQLITE_OK;
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+
+ if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){
+ tvfsExecTcl(p, "xTruncate",
+ Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
+ );
+ tvfsResultCode(p, &rc);
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsTruncate(pFd->pReal, size);
+ }
+ return rc;
}
/*
@@ -325,6 +395,8 @@ static int tvfsSync(sqlite3_file *pFile, int flags){
tvfsResultCode(p, &rc);
}
+ if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
+
if( rc==SQLITE_OK ){
rc = sqlite3OsSync(pFd->pReal, flags);
}
@@ -376,16 +448,24 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
** Return the sector-size in bytes for an tvfs-file.
*/
static int tvfsSectorSize(sqlite3_file *pFile){
- TestvfsFile *p = (TestvfsFile *)pFile;
- return sqlite3OsSectorSize(p->pReal);
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+ if( p->iSectorsize>=0 ){
+ return p->iSectorsize;
+ }
+ return sqlite3OsSectorSize(pFd->pReal);
}
/*
** Return the device characteristic flags supported by an tvfs-file.
*/
static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
- TestvfsFile *p = (TestvfsFile *)pFile;
- return sqlite3OsDeviceCharacteristics(p->pReal);
+ TestvfsFile *pFd = (TestvfsFile *)pFile;
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+ if( p->iDevchar>=0 ){
+ return p->iDevchar;
+ }
+ return sqlite3OsDeviceCharacteristics(pFd->pReal);
}
/*
@@ -555,18 +635,6 @@ static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
}
-static int tvfsInjectIoerr(Testvfs *p){
- int ret = 0;
- if( p->ioerr ){
- p->iIoerrCnt--;
- if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
- ret = 1;
- p->nIoerrFail++;
- }
- }
- return ret;
-}
-
static int tvfsShmOpen(
sqlite3_file *pFileDes
){
@@ -782,25 +850,38 @@ static int testvfs_obj_cmd(
){
Testvfs *p = (Testvfs *)cd;
- static const char *CMD_strs[] = {
- "shm", "delete", "filter", "ioerr", "script", 0
- };
enum DB_enum {
- CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT
+ CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT,
+ CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR
+ };
+ struct TestvfsSubcmd {
+ char *zName;
+ enum DB_enum eCmd;
+ } aSubcmd[] = {
+ { "shm", CMD_SHM },
+ { "delete", CMD_DELETE },
+ { "filter", CMD_FILTER },
+ { "ioerr", CMD_IOERR },
+ { "fullerr", CMD_FULLERR },
+ { "script", CMD_SCRIPT },
+ { "devchar", CMD_DEVCHAR },
+ { "sectorsize", CMD_SECTORSIZE },
+ { 0, 0 }
};
-
int i;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
return TCL_ERROR;
}
- if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){
+ if( Tcl_GetIndexFromObjStruct(
+ interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i)
+ ){
return TCL_ERROR;
}
Tcl_ResetResult(interp);
- switch( (enum DB_enum)i ){
+ switch( aSubcmd[i].eCmd ){
case CMD_SHM: {
Tcl_Obj *pObj;
int i;
@@ -857,7 +938,10 @@ static int testvfs_obj_cmd(
{ "xShmMap", TESTVFS_SHMMAP_MASK },
{ "xSync", TESTVFS_SYNC_MASK },
{ "xDelete", TESTVFS_DELETE_MASK },
+ { "xWrite", TESTVFS_WRITE_MASK },
+ { "xTruncate", TESTVFS_TRUNCATE_MASK },
{ "xOpen", TESTVFS_OPEN_MASK },
+ { "xClose", TESTVFS_CLOSE_MASK },
};
Tcl_Obj **apElem = 0;
int nElem = 0;
@@ -916,6 +1000,34 @@ static int testvfs_obj_cmd(
}
/*
+ ** TESTVFS fullerr ?IFAIL?
+ **
+ ** Where IFAIL is an integer.
+ */
+ case CMD_FULLERR: {
+ int iRet = p->nFullFail;
+
+ p->nFullFail = 0;
+ p->fullerr = 0;
+ p->iFullCnt = 0;
+
+ if( objc==3 ){
+ int iCnt;
+ if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) ){
+ return TCL_ERROR;
+ }
+ p->fullerr = (iCnt>0);
+ p->iFullCnt = iCnt;
+ }else if( objc!=2 ){
+ Tcl_AppendResult(interp, "Bad args", 0);
+ return TCL_ERROR;
+ }
+
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
+ break;
+ }
+
+ /*
** TESTVFS ioerr ?IFAIL PERSIST?
**
** Where IFAIL is an integer and PERSIST is boolean.
@@ -948,6 +1060,89 @@ static int testvfs_obj_cmd(
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
break;
}
+
+ case CMD_DEVCHAR: {
+ struct DeviceFlag {
+ char *zName;
+ int iValue;
+ } aFlag[] = {
+ { "default", -1 },
+ { "atomic", SQLITE_IOCAP_ATOMIC },
+ { "atomic512", SQLITE_IOCAP_ATOMIC512 },
+ { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
+ { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
+ { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
+ { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
+ { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
+ { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
+ { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
+ { "sequential", SQLITE_IOCAP_SEQUENTIAL },
+ { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
+ { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN },
+ { 0, 0 }
+ };
+ Tcl_Obj *pRet;
+ int iFlag;
+
+ if( objc>3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
+ return TCL_ERROR;
+ }
+ if( objc==3 ){
+ int j;
+ int iNew = 0;
+ Tcl_Obj **flags = 0;
+ int nFlags = 0;
+
+ if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){
+ return TCL_ERROR;
+ }
+
+ for(j=0; j<nFlags; j++){
+ int idx = 0;
+ if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag,
+ sizeof(aFlag[0]), "flag", 0, &idx)
+ ){
+ return TCL_ERROR;
+ }
+ if( aFlag[idx].iValue<0 && nFlags>1 ){
+ Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0);
+ return TCL_ERROR;
+ }
+ iNew |= aFlag[idx].iValue;
+ }
+
+ p->iDevchar = iNew;
+ }
+
+ pRet = Tcl_NewObj();
+ for(iFlag=0; iFlag<sizeof(aFlag)/sizeof(aFlag[0]); iFlag++){
+ if( p->iDevchar & aFlag[iFlag].iValue ){
+ Tcl_ListObjAppendElement(
+ interp, pRet, Tcl_NewStringObj(aFlag[iFlag].zName, -1)
+ );
+ }
+ }
+ Tcl_SetObjResult(interp, pRet);
+
+ break;
+ }
+
+ case CMD_SECTORSIZE: {
+ if( objc>3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?VALUE?");
+ return TCL_ERROR;
+ }
+ if( objc==3 ){
+ int iNew = 0;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iNew) ){
+ return TCL_ERROR;
+ }
+ p->iSectorsize = iNew;
+ }
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(p->iSectorsize));
+ break;
+ }
}
return TCL_OK;
@@ -1067,6 +1262,8 @@ static int testvfs_cmd(
nByte = sizeof(Testvfs) + strlen(zVfs)+1;
p = (Testvfs *)ckalloc(nByte);
memset(p, 0, nByte);
+ p->iDevchar = -1;
+ p->iSectorsize = -1;
/* Create the new object command before querying SQLite for a default VFS
** to use for 'real' IO operations. This is because creating the new VFS
diff --git a/src/vdbe.c b/src/vdbe.c
index 6803beafd..aec5712bf 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -5248,8 +5248,6 @@ case OP_JournalMode: { /* out2-prerelease */
rc = sqlite3PagerCloseWal(pPager);
if( rc==SQLITE_OK ){
sqlite3PagerSetJournalMode(pPager, eNew);
- }else if( rc==SQLITE_BUSY && pOp->p5==0 ){
- goto abort_due_to_error;
}
}
@@ -5259,16 +5257,15 @@ case OP_JournalMode: { /* out2-prerelease */
assert( sqlite3BtreeIsInTrans(pBt)==0 );
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
- if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error;
- }
- if( rc==SQLITE_BUSY ){
- eNew = eOld;
- rc = SQLITE_OK;
}
}
}
#endif /* ifndef SQLITE_OMIT_WAL */
+ if( rc ){
+ if( rc==SQLITE_BUSY && pOp->p5!=0 ) rc = SQLITE_OK;
+ eNew = eOld;
+ }
eNew = sqlite3PagerSetJournalMode(pPager, eNew);
pOut = &aMem[pOp->p2];
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 829b6de6d..b2b9f0ed0 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -191,10 +191,14 @@ int sqlite3_blob_open(
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ sqlite3VdbeChangeToNoop(v, 2, 1);
+#else
sqlite3VdbeChangeP1(v, 2, iDb);
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
sqlite3VdbeChangeP3(v, 2, flags);
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
+#endif
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */