aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2007-08-23 02:47:53 +0000
committerdrh <drh@noemail.net>2007-08-23 02:47:53 +0000
commit4a50aac5645b7dffed2c27e552675fa4be3a9368 (patch)
tree8a197bbd8fca21cf558ae84e510efd8168fe72c2 /src
parented138fb3bc8e55a6ae93669899dce79e5e26c65a (diff)
downloadsqlite-4a50aac5645b7dffed2c27e552675fa4be3a9368.tar.gz
sqlite-4a50aac5645b7dffed2c27e552675fa4be3a9368.zip
Improvements to memory leak detection. The --backtrace=NNN option is now
recognized by tester.tcl. Memory leak summaries are automatically written to the file ./memleak.txt and each leak is tagged with the test in which it occurred. The quick.test script runs on Linux with no errors and no leaks. (CVS 4273) FossilOrigin-Name: 21f6b31097692171c6493e6ca6de6acbd62dc595
Diffstat (limited to 'src')
-rw-r--r--src/btree.c6
-rw-r--r--src/func.c5
-rw-r--r--src/loadext.c1
-rw-r--r--src/mem2.c58
-rw-r--r--src/os_unix.c6
-rw-r--r--src/sqlite.h.in19
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/test1.c14
-rw-r--r--src/test6.c11
-rw-r--r--src/test8.c4
-rw-r--r--src/test_malloc.c56
-rw-r--r--src/vdbeaux.c6
-rw-r--r--src/vtab.c6
13 files changed, 147 insertions, 49 deletions
diff --git a/src/btree.c b/src/btree.c
index f92e32cc5..bb740a74f 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.409 2007/08/22 11:41:18 drh Exp $
+** $Id: btree.c,v 1.410 2007/08/23 02:47:53 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@@ -1136,12 +1136,16 @@ int sqlite3BtreeOpen(
*/
if( (flags & BTREE_PRIVATE)==0
&& isMemdb==0
+ && (pSqlite==0 || (pSqlite->flags &SQLITE_Vtab)==0)
&& zFilename && zFilename[0]
&& sqlite3SharedCacheEnabled
){
char *zFullPathname = (char *)sqlite3_malloc(pVfs->mxPathname);
sqlite3_mutex *mutexShared;
p->sharable = 1;
+ if( pSqlite ){
+ pSqlite->flags |= SQLITE_SharedCache;
+ }
if( !zFullPathname ){
sqlite3_free(p);
return SQLITE_NOMEM;
diff --git a/src/func.c b/src/func.c
index 224f88f08..7b981df30 100644
--- a/src/func.c
+++ b/src/func.c
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.168 2007/08/21 19:33:56 drh Exp $
+** $Id: func.c,v 1.169 2007/08/23 02:47:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -807,14 +807,17 @@ static void replaceFunc(
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
zOut[j++] = zStr[i];
}else{
+ u8 *zOld;
nOut += nRep - nPattern;
if( nOut>=SQLITE_MAX_LENGTH ){
sqlite3_result_error_toobig(context);
sqlite3_free(zOut);
return;
}
+ zOld = zOut;
zOut = sqlite3_realloc(zOut, (int)nOut);
if( zOut==0 ){
+ sqlite3_free(zOld);
return;
}
memcpy(&zOut[j], zRep, nRep);
diff --git a/src/loadext.c b/src/loadext.c
index a4c57c2c6..7d2340cf7 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -454,6 +454,7 @@ int sqlite3AutoLoadExtensions(sqlite3 *db){
"automatic extension loading failed: %s", zErrmsg);
go = 0;
rc = SQLITE_ERROR;
+ sqlite3_free(zErrmsg);
}
}
return rc;
diff --git a/src/mem2.c b/src/mem2.c
index d9653ee81..4b3c4f58f 100644
--- a/src/mem2.c
+++ b/src/mem2.c
@@ -12,7 +12,7 @@
** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite.
**
-** $Id: mem2.c,v 1.7 2007/08/22 22:04:37 drh Exp $
+** $Id: mem2.c,v 1.8 2007/08/23 02:47:53 drh Exp $
*/
/*
@@ -59,9 +59,9 @@
/*
** Each memory allocation looks like this:
**
-** ----------------------------------------------------------------
-** | backtrace pointers | MemBlockHdr | allocation | EndGuard |
-** ----------------------------------------------------------------
+** ------------------------------------------------------------------------
+** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard |
+** ------------------------------------------------------------------------
**
** The application code sees only a pointer to the allocation. We have
** to back up from the allocation pointer to find the MemBlockHdr. The
@@ -72,8 +72,9 @@
struct MemBlockHdr {
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
unsigned int iSize; /* Size of this allocation */
- unsigned short nBacktrace; /* Number of backtraces on this alloc */
- unsigned short nBacktraceSlots; /* Available backtrace slots */
+ unsigned char nBacktrace; /* Number of backtraces on this alloc */
+ unsigned char nBacktraceSlots; /* Available backtrace slots */
+ unsigned short nTitle; /* Bytes of title; includes '\0' */
unsigned int iForeGuard; /* Guard word for sanity */
};
@@ -125,6 +126,12 @@ static struct {
int nBacktrace;
/*
+ ** Title text to insert in front of each block
+ */
+ int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */
+ char zTitle[100]; /* The title text */
+
+ /*
** These values are used to simulate malloc failures. When
** iFail is 1, simulate a malloc failures and reset the value
** to iReset.
@@ -252,6 +259,7 @@ static void sqlite3MemsysFailed(void){
void *sqlite3_malloc(int nByte){
struct MemBlockHdr *pHdr;
void **pBt;
+ char *z;
unsigned int *pInt;
void *p;
unsigned int totalSize;
@@ -269,7 +277,7 @@ void *sqlite3_malloc(int nByte){
}
nByte = (nByte+3)&~3;
totalSize = nByte + sizeof(*pHdr) + sizeof(unsigned int) +
- mem.nBacktrace*sizeof(void*);
+ mem.nBacktrace*sizeof(void*) + mem.nTitle;
if( mem.iFail>0 ){
if( mem.iFail==1 ){
p = 0;
@@ -290,7 +298,8 @@ void *sqlite3_malloc(int nByte){
}
}
if( p ){
- pBt = p;
+ z = p;
+ pBt = (void**)&z[mem.nTitle];
pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
pHdr->pNext = 0;
pHdr->pPrev = mem.pLast;
@@ -302,6 +311,7 @@ void *sqlite3_malloc(int nByte){
mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
pHdr->nBacktraceSlots = mem.nBacktrace;
+ pHdr->nTitle = mem.nTitle;
if( mem.nBacktrace ){
void *aAddr[40];
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
@@ -309,6 +319,9 @@ void *sqlite3_malloc(int nByte){
}else{
pHdr->nBacktrace = 0;
}
+ if( mem.nTitle ){
+ memcpy(z, mem.zTitle, mem.nTitle);
+ }
pHdr->iSize = nByte;
pInt = (unsigned int *)&pHdr[1];
pInt[nByte/sizeof(unsigned int)] = REARGUARD;
@@ -329,6 +342,7 @@ void *sqlite3_malloc(int nByte){
void sqlite3_free(void *pPrior){
struct MemBlockHdr *pHdr;
void **pBt;
+ char *z;
if( pPrior==0 ){
return;
}
@@ -352,9 +366,11 @@ void sqlite3_free(void *pPrior){
assert( mem.pLast==pHdr );
mem.pLast = pHdr->pPrev;
}
- memset(pBt, 0x2b, sizeof(void*)*pHdr->nBacktrace + sizeof(*pHdr) +
- pHdr->iSize + sizeof(unsigned int));
- free(pBt);
+ z = (char*)pBt;
+ z -= pHdr->nTitle;
+ memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
+ pHdr->iSize + sizeof(unsigned int) + pHdr->nTitle);
+ free(z);
sqlite3_mutex_leave(mem.mutex);
}
@@ -403,6 +419,22 @@ void sqlite3_memdebug_backtrace(int depth){
}
/*
+** Set the title string for subsequent allocations.
+*/
+void sqlite3_memdebug_settitle(const char *zTitle){
+ int n = strlen(zTitle) + 1;
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
+ }
+ sqlite3_mutex_enter(mem.mutex);
+ if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
+ memcpy(mem.zTitle, zTitle, n);
+ mem.zTitle[n] = 0;
+ mem.nTitle = (n+3)&~3;
+ sqlite3_mutex_leave(mem.mutex);
+}
+
+/*
** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
@@ -417,7 +449,9 @@ void sqlite3_memdebug_dump(const char *zFilename){
return;
}
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
- fprintf(out, "**** %d bytes at %p ****\n", pHdr->iSize, &pHdr[1]);
+ char *z = (char*)pHdr;
+ z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
+ fprintf(out, "**** %d bytes at %p from %s ****\n", pHdr->iSize,&pHdr[1],z);
if( pHdr->nBacktrace ){
fflush(out);
pBt = (void**)pHdr;
diff --git a/src/os_unix.c b/src/os_unix.c
index 75cf36e8d..eb7a66b64 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -2657,6 +2657,10 @@ static int unixRandomness(void *pNotUsed, int nBuf, char *zBuf){
/*
** Sleep for a little while. Return the amount of time slept.
** The argument is the number of microseconds we want to sleep.
+** The return value is the number of microseconds of sleep actually
+** requested from the underlying operating system, a number which
+** might be greater than or equal to the argument, but not less
+** than the argument.
*/
static int unixSleep(void *pNotUsed, int microseconds){
#if defined(HAVE_USLEEP) && HAVE_USLEEP
@@ -2665,7 +2669,7 @@ static int unixSleep(void *pNotUsed, int microseconds){
#else
int seconds = (microseconds+999999)/1000000;
sleep(seconds);
- return seconds;
+ return seconds*1000000;
#endif
}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 6465245ca..b6b56686e 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
-** @(#) $Id: sqlite.h.in,v 1.237 2007/08/22 20:18:22 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.238 2007/08/23 02:47:53 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -1389,8 +1389,11 @@ int sqlite3_open_v2(
** (overwriting the previous values). Note that calls to [sqlite3_errcode()],
** [sqlite3_errmsg()], and [sqlite3_errmsg16()] themselves do not affect the
** results of future invocations. Calls to API routines that do not return
-** an error code (examples: [sqlite3_data_count()] or [sqlite3_mprintf()]) do
-** not change the error code returned by this routine.
+** an error code (example: [sqlite3_data_count()]) do not
+** change the error code returned by this routine. Interfaces that are
+** not associated with a specific database connection (examples:
+** [sqlite3_mprintf()] or [sqlite3_enable_shared_cache()] do not change
+** the return code.
**
** Assuming no other intervening sqlite3_* API calls are made, the error
** code returned by this function is associated with the same error as
@@ -1708,6 +1711,10 @@ int sqlite3_column_count(sqlite3_stmt *pStmt);
** [sqlite3_stmt | prepared statement] is destroyed by [sqlite3_finalize()]
** or until the next call sqlite3_column_name() or sqlite3_column_name16()
** on the same column.
+**
+** If sqlite3_malloc() fails during the processing of either routine
+** (for example during a conversion from UTF-8 to UTF-16) then a
+** NULL pointer is returned.
*/
const char *sqlite3_column_name(sqlite3_stmt*, int N);
const void *sqlite3_column_name16(sqlite3_stmt*, int N);
@@ -2040,6 +2047,12 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** and blobs is freed automatically. Do <b>not</b> pass the pointers returned
** [sqlite3_column_blob()], [sqlite_column_text()], etc. into
** [sqlite3_free()].
+**
+** If a memory allocation error occurs during the evaluation of any
+** of these routines, a default value is returned. The default value
+** is either the integer 0, the floating point number 0.0, or a NULL
+** pointer. Subsequent calls to [sqlite3_errcode()] will return
+** [SQLITE_NOMEM].
*/
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 4b6e01dec..29da21f5a 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.597 2007/08/22 11:41:18 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.598 2007/08/23 02:47:53 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -493,6 +493,8 @@ struct sqlite3 {
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
+#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */
+#define SQLITE_Vtab 0x00100000 /* There exists a virtual table */
/*
** Possible values for the sqlite.magic field.
diff --git a/src/test1.c b/src/test1.c
index 11ffb1e23..198744c2b 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.270 2007/08/22 20:18:22 drh Exp $
+** $Id: test1.c,v 1.271 2007/08/23 02:47:53 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -186,18 +186,6 @@ static int getStmtPointer(
}
/*
-** Decode a pointer to an sqlite3_stmt object.
-*/
-static int getFilePointer(
- Tcl_Interp *interp,
- const char *zArg,
- sqlite3_file **ppFile
-){
- *ppFile = (sqlite3_file*)sqlite3TextToPtr(zArg);
- return TCL_OK;
-}
-
-/*
** Generate a text representation of a pointer that can be understood
** by the getDbPointer and getVmPointer routines above.
**
diff --git a/src/test6.c b/src/test6.c
index 0abf2353a..93befb881 100644
--- a/src/test6.c
+++ b/src/test6.c
@@ -320,8 +320,6 @@ static int cfRead(
sqlite_int64 iOfst
){
CrashFile *pCrash = (CrashFile *)pFile;
- sqlite3_int64 iSize;
- WriteBuffer *pWrite;
/* Check the file-size to see if this is a short-read */
if( pCrash->iSize<(iOfst+iAmt) ){
@@ -346,9 +344,9 @@ static int cfWrite(
pCrash->iSize = iAmt+iOfst;
}
while( pCrash->iSize>pCrash->nData ){
- char *zNew;
+ u8 *zNew;
int nNew = (pCrash->nData*2) + 4096;
- zNew = (char *)sqlite3_realloc(pCrash->zData, nNew);
+ zNew = sqlite3_realloc(pCrash->zData, nNew);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -480,7 +478,7 @@ static int cfOpen(
sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
int rc;
CrashFile *pWrapper = (CrashFile *)pFile;
- sqlite3_file *pReal = &pWrapper[1];
+ sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1];
memset(pWrapper, 0, sizeof(CrashFile));
rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags);
@@ -495,7 +493,7 @@ static int cfOpen(
}
if( rc==SQLITE_OK ){
pWrapper->nData = (4096 + pWrapper->iSize);
- pWrapper->zData = (char *)sqlite3_malloc(pWrapper->nData);
+ pWrapper->zData = sqlite3_malloc(pWrapper->nData);
if( pWrapper->zData ){
memset(pWrapper->zData, 0, pWrapper->nData);
rc = sqlite3OsRead(pReal, pWrapper->zData, pWrapper->iSize, 0);
@@ -570,7 +568,6 @@ static int crashParamsObjCmd(
int iDelay;
const char *zCrashFile;
int nCrashFile;
- static struct crashAppData appData;
static sqlite3_vfs crashVfs = {
1, /* iVersion */
diff --git a/src/test8.c b/src/test8.c
index 28a49a75f..8e7d50d54 100644
--- a/src/test8.c
+++ b/src/test8.c
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test8.c,v 1.52 2007/08/21 10:44:16 drh Exp $
+** $Id: test8.c,v 1.53 2007/08/23 02:47:53 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -852,7 +852,7 @@ int echoUpdate(
"%s %Q=?%d", zSep, pVtab->aCol[i-2], i), 1);
zSep = ",";
}
- string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 0);
+ string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 1);
}
/* If apData[0] is an integer and nData==1 then do a DELETE */
diff --git a/src/test_malloc.c b/src/test_malloc.c
index 478c6c5f8..395288229 100644
--- a/src/test_malloc.c
+++ b/src/test_malloc.c
@@ -13,7 +13,7 @@
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
-** $Id: test_malloc.c,v 1.3 2007/08/22 22:04:37 drh Exp $
+** $Id: test_malloc.c,v 1.4 2007/08/23 02:47:53 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -27,7 +27,16 @@
static void pointerToText(void *p, char *z){
static const char zHex[] = "0123456789abcdef";
int i, k;
- sqlite3_uint64 n = (sqlite3_uint64)p;
+ unsigned int u;
+ sqlite3_uint64 n;
+ if( sizeof(n)==sizeof(p) ){
+ memcpy(&n, &p, sizeof(p));
+ }else if( sizeof(u)==sizeof(p) ){
+ memcpy(&u, &p, sizeof(u));
+ n = u;
+ }else{
+ assert( 0 );
+ }
for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
z[k] = zHex[n&0xf];
n >>= 4;
@@ -46,6 +55,7 @@ static int hexToInt(int h){
static int textToPointer(const char *z, void **pp){
sqlite3_uint64 n = 0;
int i;
+ unsigned int u;
for(i=0; i<sizeof(void*)*2 && z[0]; i++){
int v;
v = hexToInt(*z++);
@@ -53,7 +63,14 @@ static int textToPointer(const char *z, void **pp){
n = n*16 + v;
}
if( *z!=0 ) return TCL_ERROR;
- *pp = (void*)n;
+ if( sizeof(n)==sizeof(*pp) ){
+ memcpy(pp, &n, sizeof(n));
+ }else if( sizeof(u)==sizeof(*pp) ){
+ u = (unsigned int)n;
+ memcpy(pp, &u, sizeof(u));
+ }else{
+ assert( 0 );
+ }
return TCL_OK;
}
@@ -290,6 +307,38 @@ static int test_memdebug_pending(
/*
+** Usage: sqlite3_memdebug_settitle TITLE
+**
+** Set a title string stored with each allocation. The TITLE is
+** typically the name of the test that was running when the
+** allocation occurred. The TITLE is stored with the allocation
+** and can be used to figure out which tests are leaking memory.
+**
+** Each title overwrite the previous.
+*/
+static int test_memdebug_settitle(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ const char *zTitle;
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
+ return TCL_ERROR;
+ }
+ zTitle = Tcl_GetString(objv[1]);
+#ifdef SQLITE_MEMDEBUG
+ {
+ extern int sqlite3_memdebug_settitle(const char*);
+ sqlite3_memdebug_settitle(zTitle);
+ }
+#endif
+ return TCL_OK;
+}
+
+
+/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_malloc_Init(Tcl_Interp *interp){
@@ -306,6 +355,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_memdebug_dump", test_memdebug_dump },
{ "sqlite3_memdebug_fail", test_memdebug_fail },
{ "sqlite3_memdebug_pending", test_memdebug_pending },
+ { "sqlite3_memdebug_settitle", test_memdebug_settitle },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 85edcba11..ff93ac529 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1007,6 +1007,8 @@ static void Cleanup(Vdbe *p){
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
Mem *pColName;
int n;
+ sqlite3 *db = p->db;
+
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3_free(p->aColName);
n = nResColumn*COLNAME_N;
@@ -1014,7 +1016,9 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
p->aColName = pColName = (Mem*)sqlite3DbMallocZero(p->db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
while( n-- > 0 ){
- (pColName++)->flags = MEM_Null;
+ pColName->flags = MEM_Null;
+ pColName->db = db;
+ pColName++;
}
}
diff --git a/src/vtab.c b/src/vtab.c
index ac54516fd..09793aef7 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
-** $Id: vtab.c,v 1.52 2007/08/22 02:56:44 drh Exp $
+** $Id: vtab.c,v 1.53 2007/08/23 02:47:53 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
@@ -167,12 +167,10 @@ void sqlite3VtabBeginParse(
Table *pTable; /* The new virtual table */
sqlite3 *db; /* Database connection */
-#if 0 /* FIX ME */
- if( sqlite3ThreadDataReadOnly()->useSharedData ){
+ if( pParse->db->flags & SQLITE_SharedCache ){
sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
return;
}
-#endif
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable;