aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2015-06-17 18:18:51 +0000
committerdrh <drh@noemail.net>2015-06-17 18:18:51 +0000
commit5600329bc033aa5837969918d3397e455ee93d51 (patch)
tree258ab0590848adbbf5e278c2d3e26b803d5dede2 /src
parent60c97e6aa88b96277a4f8e6ba7d9ebd83f956cc3 (diff)
parentbbe031f9f1260fd97622cfd47dbdf5377daee6b2 (diff)
downloadsqlite-5600329bc033aa5837969918d3397e455ee93d51.tar.gz
sqlite-5600329bc033aa5837969918d3397e455ee93d51.zip
Merge all recent enhancements and fixes from trunk.
FossilOrigin-Name: 199bfb67fdf642cca6cd5d460fa4dc602b94837a
Diffstat (limited to 'src')
-rw-r--r--src/btree.c39
-rw-r--r--src/build.c3
-rw-r--r--src/expr.c19
-rw-r--r--src/func.c23
-rw-r--r--src/loadext.c5
-rw-r--r--src/main.c6
-rw-r--r--src/mutex.c11
-rw-r--r--src/pcache1.c96
-rw-r--r--src/shell.c24
-rw-r--r--src/sqlite.h.in2
-rw-r--r--src/sqlite3ext.h3
-rw-r--r--src/sqliteInt.h8
-rw-r--r--src/tokenize.c4
-rw-r--r--src/vdbe.c20
-rw-r--r--src/vdbe.h1
-rw-r--r--src/vdbeInt.h3
-rw-r--r--src/vdbeaux.c32
-rw-r--r--src/vdbemem.c43
-rw-r--r--src/where.c19
19 files changed, 241 insertions, 120 deletions
diff --git a/src/btree.c b/src/btree.c
index 53e0ebbfc..eab5b9842 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -1441,7 +1441,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
/* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none
- ** iPtr: The address of a pointer iFreeBlk
+ ** iPtr: The address of a pointer to iFreeBlk
**
** Check to see if iFreeBlk should be coalesced onto the end of iStart.
*/
@@ -1449,6 +1449,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
+ if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
}
@@ -3984,13 +3985,6 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
**
** BtCursor.info is a cache of the information in the current cell.
** Using this cache reduces the number of calls to btreeParseCell().
-**
-** 2007-06-25: There is a bug in some versions of MSVC that cause the
-** compiler to crash when getCellInfo() is implemented as a macro.
-** But there is a measureable speed advantage to using the macro on gcc
-** (when less compiler optimizations like -Os or -O0 are used and the
-** compiler is not doing aggressive inlining.) So we use a real function
-** for MSVC and a macro for everything else. Ticket #2457.
*/
#ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){
@@ -4003,28 +3997,15 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#else
#define assertCellInfo(x)
#endif
-#ifdef _MSC_VER
- /* Use a real function in MSVC to work around bugs in that compiler. */
- static void getCellInfo(BtCursor *pCur){
- if( pCur->info.nSize==0 ){
- int iPage = pCur->iPage;
- btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
- pCur->curFlags |= BTCF_ValidNKey;
- }else{
- assertCellInfo(pCur);
- }
- }
-#else /* if not _MSC_VER */
- /* Use a macro in all other compilers so that the function is inlined */
-#define getCellInfo(pCur) \
- if( pCur->info.nSize==0 ){ \
- int iPage = pCur->iPage; \
- btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
- pCur->curFlags |= BTCF_ValidNKey; \
- }else{ \
- assertCellInfo(pCur); \
+static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
+ if( pCur->info.nSize==0 ){
+ int iPage = pCur->iPage;
+ pCur->curFlags |= BTCF_ValidNKey;
+ btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
+ }else{
+ assertCellInfo(pCur);
}
-#endif /* _MSC_VER */
+}
#ifndef NDEBUG /* The next routine used only within assert() statements */
/*
diff --git a/src/build.c b/src/build.c
index 8c62fd18d..293680536 100644
--- a/src/build.c
+++ b/src/build.c
@@ -976,7 +976,7 @@ void sqlite3StartTable(
int j1;
int fileFormat;
int reg1, reg2, reg3;
- sqlite3BeginWriteOperation(pParse, 0, iDb);
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtual ){
@@ -1924,6 +1924,7 @@ void sqlite3EndTable(
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
assert(pParse->nTab==1);
+ sqlite3MayAbort(pParse);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
pParse->nTab = 2;
diff --git a/src/expr.c b/src/expr.c
index 06993e737..ddf939d3f 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2208,17 +2208,6 @@ static void sqlite3ExprCodeIN(
}
#endif /* SQLITE_OMIT_SUBQUERY */
-/*
-** Duplicate an 8-byte value
-*/
-static char *dup8bytes(Vdbe *v, const char *in){
- char *out = sqlite3DbMallocRaw(sqlite3VdbeDb(v), 8);
- if( out ){
- memcpy(out, in, 8);
- }
- return out;
-}
-
#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Generate an instruction that will put the floating point
@@ -2231,12 +2220,10 @@ static char *dup8bytes(Vdbe *v, const char *in){
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
if( ALWAYS(z!=0) ){
double value;
- char *zV;
sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
if( negateFlag ) value = -value;
- zV = dup8bytes(v, (char*)&value);
- sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
+ sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL);
}
}
#endif
@@ -2262,10 +2249,8 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
if( c==0 || (c==2 && negFlag) ){
- char *zV;
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
- zV = dup8bytes(v, (char*)&value);
- sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
+ sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
diff --git a/src/func.c b/src/func.c
index 62abf13d4..d0565357d 100644
--- a/src/func.c
+++ b/src/func.c
@@ -575,17 +575,15 @@ struct compareInfo {
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
-** character is exactly one byte in size. Also, all characters are
-** able to participate in upper-case-to-lower-case mappings in EBCDIC
-** whereas only characters less than 0x80 do in ASCII.
+** character is exactly one byte in size. Also, provde the Utf8Read()
+** macro for fast reading of the next character in the common case where
+** the next character is ASCII.
*/
#if defined(SQLITE_EBCDIC)
# define sqlite3Utf8Read(A) (*((*A)++))
-# define GlobUpperToLower(A) A = sqlite3UpperToLower[A]
-# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
+# define Utf8Read(A) (*(A++))
#else
-# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; }
-# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
+# define Utf8Read(A) (A[0]<0x80?*(A++):sqlite3Utf8Read(&A))
#endif
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
@@ -627,7 +625,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
** Ec Where E is the "esc" character and c is any other
** character, including '%', '_', and esc, match exactly c.
**
-** The comments through this routine usually assume glob matching.
+** The comments within this routine usually assume glob matching.
**
** This routine is usually quick, but can be N**2 in the worst case.
*/
@@ -651,13 +649,12 @@ static int patternCompare(
*/
matchOther = esc ? esc : pInfo->matchSet;
- while( (c = sqlite3Utf8Read(&zPattern))!=0 ){
+ while( (c = Utf8Read(zPattern))!=0 ){
if( c==matchAll ){ /* Match "*" */
/* Skip over multiple "*" characters in the pattern. If there
** are also "?" characters, skip those as well, but consume a
** single character of the input string for each "?" skipped */
- while( (c=sqlite3Utf8Read(&zPattern)) == matchAll
- || c == matchOne ){
+ while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
return 0;
}
@@ -702,7 +699,7 @@ static int patternCompare(
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
}else{
- while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
+ while( (c2 = Utf8Read(zString))!=0 ){
if( c2!=c ) continue;
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
@@ -748,7 +745,7 @@ static int patternCompare(
continue;
}
}
- c2 = sqlite3Utf8Read(&zString);
+ c2 = Utf8Read(zString);
if( c==c2 ) continue;
if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
continue;
diff --git a/src/loadext.c b/src/loadext.c
index 5a2b9d297..dcdbb2812 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -402,7 +402,10 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_reset_auto_extension,
sqlite3_result_blob64,
sqlite3_result_text64,
- sqlite3_strglob
+ sqlite3_strglob,
+ /* Version 3.8.11 and later */
+ (sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
+ sqlite3_value_free
};
/*
diff --git a/src/main.c b/src/main.c
index e0de69e75..20e09cf1f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2103,9 +2103,11 @@ int sqlite3TempInMemory(const sqlite3 *db){
return ( db->temp_store!=1 );
#endif
#if SQLITE_TEMP_STORE==3
+ UNUSED_PARAMETER(db);
return 1;
#endif
#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3
+ UNUSED_PARAMETER(db);
return 0;
#endif
}
@@ -3377,7 +3379,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
*/
int sqlite3_test_control(int op, ...){
int rc = 0;
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_OMIT_BUILTIN_TEST
+ UNUSED_PARAMETER(op);
+#else
va_list ap;
va_start(ap, op);
switch( op ){
diff --git a/src/mutex.c b/src/mutex.c
index 2b4503628..64efd3b05 100644
--- a/src/mutex.c
+++ b/src/mutex.c
@@ -45,9 +45,14 @@ int sqlite3MutexInit(void){
}else{
pFrom = sqlite3NoopMutex();
}
- memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
- memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
- sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
+ pTo->xMutexInit = pFrom->xMutexInit;
+ pTo->xMutexEnd = pFrom->xMutexEnd;
+ pTo->xMutexFree = pFrom->xMutexFree;
+ pTo->xMutexEnter = pFrom->xMutexEnter;
+ pTo->xMutexTry = pFrom->xMutexTry;
+ pTo->xMutexLeave = pFrom->xMutexLeave;
+ pTo->xMutexHeld = pFrom->xMutexHeld;
+ pTo->xMutexNotheld = pFrom->xMutexNotheld;
pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
rc = sqlite3GlobalConfig.mutex.xMutexInit();
diff --git a/src/pcache1.c b/src/pcache1.c
index a8755a314..c394ff178 100644
--- a/src/pcache1.c
+++ b/src/pcache1.c
@@ -148,8 +148,15 @@ static SQLITE_WSD struct PCacheGlobal {
/*
** Macros to enter and leave the PCache LRU mutex.
*/
-#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
-#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
+#if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
+# define pcache1EnterMutex(X) assert((X)->mutex==0)
+# define pcache1LeaveMutex(X) assert((X)->mutex==0)
+# define PCACHE1_MIGHT_USE_GROUP_MUTEX 0
+#else
+# define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
+# define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
+# define PCACHE1_MIGHT_USE_GROUP_MUTEX 1
+#endif
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
@@ -425,31 +432,30 @@ static void pcache1ResizeHash(PCache1 *p){
**
** The PGroup mutex must be held when this function is called.
*/
-static void pcache1PinPage(PgHdr1 *pPage){
+static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
PCache1 *pCache;
- PGroup *pGroup;
assert( pPage!=0 );
assert( pPage->isPinned==0 );
pCache = pPage->pCache;
- pGroup = pCache->pGroup;
- assert( pPage->pLruNext || pPage==pGroup->pLruTail );
- assert( pPage->pLruPrev || pPage==pGroup->pLruHead );
- assert( sqlite3_mutex_held(pGroup->mutex) );
+ assert( pPage->pLruNext || pPage==pCache->pGroup->pLruTail );
+ assert( pPage->pLruPrev || pPage==pCache->pGroup->pLruHead );
+ assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
if( pPage->pLruPrev ){
pPage->pLruPrev->pLruNext = pPage->pLruNext;
}else{
- pGroup->pLruHead = pPage->pLruNext;
+ pCache->pGroup->pLruHead = pPage->pLruNext;
}
if( pPage->pLruNext ){
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
}else{
- pGroup->pLruTail = pPage->pLruPrev;
+ pCache->pGroup->pLruTail = pPage->pLruPrev;
}
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
pPage->isPinned = 1;
pCache->nRecyclable--;
+ return pPage;
}
@@ -530,10 +536,12 @@ static int pcache1Init(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
assert( pcache1.isInit==0 );
memset(&pcache1, 0, sizeof(pcache1));
+#if SQLITE_THREADSAFE
if( sqlite3GlobalConfig.bCoreMutex ){
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
}
+#endif
pcache1.grp.mxPinned = 10;
pcache1.isInit = 1;
return SQLITE_OK;
@@ -729,9 +737,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** attempt to allocate a new one.
*/
if( !pPage ){
- if( createFlag==1 ) sqlite3BeginBenignMalloc();
+ if( createFlag==1 ){ sqlite3BeginBenignMalloc(); }
pPage = pcache1AllocPage(pCache);
- if( createFlag==1 ) sqlite3EndBenignMalloc();
+ if( createFlag==1 ){ sqlite3EndBenignMalloc(); }
}
if( pPage ){
@@ -805,8 +813,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** proceed to step 5.
**
** 5. Otherwise, allocate and return a new page buffer.
+**
+** There are two versions of this routine. pcache1FetchWithMutex() is
+** the general case. pcache1FetchNoMutex() is a faster implementation for
+** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper
+** invokes the appropriate routine.
*/
-static sqlite3_pcache_page *pcache1Fetch(
+static PgHdr1 *pcache1FetchNoMutex(
sqlite3_pcache *p,
unsigned int iKey,
int createFlag
@@ -814,28 +827,63 @@ static sqlite3_pcache_page *pcache1Fetch(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0;
- assert( offsetof(PgHdr1,page)==0 );
- assert( pCache->bPurgeable || createFlag!=1 );
- assert( pCache->bPurgeable || pCache->nMin==0 );
- assert( pCache->bPurgeable==0 || pCache->nMin==10 );
- assert( pCache->nMin==0 || pCache->bPurgeable );
- assert( pCache->nHash>0 );
- pcache1EnterMutex(pCache->pGroup);
-
/* Step 1: Search the hash table for an existing entry. */
pPage = pCache->apHash[iKey % pCache->nHash];
while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
/* Step 2: Abort if no existing page is found and createFlag is 0 */
if( pPage ){
- if( !pPage->isPinned ) pcache1PinPage(pPage);
+ if( !pPage->isPinned ){
+ return pcache1PinPage(pPage);
+ }else{
+ return pPage;
+ }
}else if( createFlag ){
/* Steps 3, 4, and 5 implemented by this subroutine */
- pPage = pcache1FetchStage2(pCache, iKey, createFlag);
+ return pcache1FetchStage2(pCache, iKey, createFlag);
+ }else{
+ return 0;
}
+}
+#if PCACHE1_MIGHT_USE_GROUP_MUTEX
+static PgHdr1 *pcache1FetchWithMutex(
+ sqlite3_pcache *p,
+ unsigned int iKey,
+ int createFlag
+){
+ PCache1 *pCache = (PCache1 *)p;
+ PgHdr1 *pPage;
+
+ pcache1EnterMutex(pCache->pGroup);
+ pPage = pcache1FetchNoMutex(p, iKey, createFlag);
assert( pPage==0 || pCache->iMaxKey>=iKey );
pcache1LeaveMutex(pCache->pGroup);
- return (sqlite3_pcache_page*)pPage;
+ return pPage;
+}
+#endif
+static sqlite3_pcache_page *pcache1Fetch(
+ sqlite3_pcache *p,
+ unsigned int iKey,
+ int createFlag
+){
+#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
+ PCache1 *pCache = (PCache1 *)p;
+#endif
+
+ assert( offsetof(PgHdr1,page)==0 );
+ assert( pCache->bPurgeable || createFlag!=1 );
+ assert( pCache->bPurgeable || pCache->nMin==0 );
+ assert( pCache->bPurgeable==0 || pCache->nMin==10 );
+ assert( pCache->nMin==0 || pCache->bPurgeable );
+ assert( pCache->nHash>0 );
+#if PCACHE1_MIGHT_USE_GROUP_MUTEX
+ if( pCache->pGroup->mutex ){
+ return (sqlite3_pcache_page*)pcache1FetchWithMutex(p, iKey, createFlag);
+ }else
+#endif
+ {
+ return (sqlite3_pcache_page*)pcache1FetchNoMutex(p, iKey, createFlag);
+ }
}
diff --git a/src/shell.c b/src/shell.c
index c6317e99f..746e7229b 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1348,7 +1348,10 @@ static void display_scanstats(
sqlite3 *db, /* Database to query */
ShellState *pArg /* Pointer to ShellState */
){
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
+ UNUSED_PARAMETER(db);
+ UNUSED_PARAMETER(pArg);
+#else
int i, k, n, mx;
fprintf(pArg->out, "-------- scanstats --------\n");
mx = 0;
@@ -1910,6 +1913,7 @@ static void readfileFunc(
long nIn;
void *pBuf;
+ UNUSED_PARAMETER(argc);
zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return;
in = fopen(zName, "rb");
@@ -1942,6 +1946,7 @@ static void writefileFunc(
sqlite3_int64 rc;
const char *zFile;
+ UNUSED_PARAMETER(argc);
zFile = (const char*)sqlite3_value_text(argv[0]);
if( zFile==0 ) return;
out = fopen(zFile, "wb");
@@ -2666,7 +2671,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
- for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
+ for(i=0; i<ArraySize(aField); i++){
int ofst = aField[i].ofst;
unsigned int val = get4byteInt(aHdr + ofst);
fprintf(p->out, "%-20s %u", aField[i].zName, val);
@@ -2686,7 +2691,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
}else{
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
}
- for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
+ for(i=0; i<ArraySize(aQuery); i++){
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
int val = db_int(p, zSql);
sqlite3_free(zSql);
@@ -3317,7 +3322,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int i, n2;
open_db(p, 0);
if( nArg==1 ){
- for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
+ for(i=0; i<ArraySize(aLimit); i++){
printf("%20s %d\n", aLimit[i].zLimitName,
sqlite3_limit(p->db, aLimit[i].limitCode, -1));
}
@@ -3328,7 +3333,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
int iLimit = -1;
n2 = strlen30(azArg[1]);
- for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
+ for(i=0; i<ArraySize(aLimit); i++){
if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
if( iLimit<0 ){
iLimit = i;
@@ -3438,9 +3443,8 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zSavedFilename = p->zDbFilename;
char *zNewFilename = 0;
p->db = 0;
- if( nArg>=2 ){
- p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]);
- }
+ if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]);
+ p->zDbFilename = zNewFilename;
open_db(p, 1);
if( p->db!=0 ){
session_close_all(p);
@@ -4096,7 +4100,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* convert testctrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */
n2 = strlen30(azArg[1]);
- for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
+ for(i=0; i<ArraySize(aCtrl); i++){
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode;
@@ -5073,7 +5077,7 @@ int SQLITE_CDECL main(int argc, char **argv){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
}
- if( zHistory ) shell_read_history(zHistory);
+ if( zHistory ){ shell_read_history(zHistory); }
rc = process_input(&data, 0);
if( zHistory ){
shell_stifle_history(100);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index a04030df8..963b55c27 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -23,7 +23,7 @@
**
** The official C-language API documentation for SQLite is derived
** from comments in this file. This file is the authoritative source
-** on how SQLite interfaces are suppose to operate.
+** on how SQLite interfaces are supposed to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 5c4488c3b..b56cc4e54 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -267,7 +267,8 @@ struct sqlite3_api_routines {
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
- sqlite3_value (*value_dup)(const sqlite3_value*);
+ /* Version 3.8.11 and later */
+ sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
};
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index a0608abbe..bcfc1ea3e 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3078,7 +3078,9 @@ int sqlite3CantopenError(int);
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
#endif
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3IsIdChar(u8);
+#endif
/*
** Internal function prototypes
@@ -3106,7 +3108,9 @@ void sqlite3ScratchFree(void*);
void *sqlite3PageMalloc(int);
void sqlite3PageFree(void*);
void sqlite3MemSetDefault(void);
+#ifndef SQLITE_OMIT_BUILTIN_TEST
void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
+#endif
int sqlite3HeapNearlyFull(void);
/*
@@ -3250,7 +3254,9 @@ int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*);
u32 sqlite3BitvecSize(Bitvec*);
+#ifndef SQLITE_OMIT_BUILTIN_TEST
int sqlite3BitvecBuiltinTest(int,int*);
+#endif
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
void sqlite3RowSetClear(RowSet*);
@@ -3355,8 +3361,10 @@ void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
Vdbe *sqlite3GetVdbe(Parse*);
+#ifndef SQLITE_OMIT_BUILTIN_TEST
void sqlite3PrngSaveState(void);
void sqlite3PrngRestoreState(void);
+#endif
void sqlite3RollbackAll(sqlite3*,int);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
diff --git a/src/tokenize.c b/src/tokenize.c
index b5934d247..3d08f75a2 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -102,7 +102,11 @@ const char sqlite3IsEbcdicIdChar[] = {
};
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
+
+/* Make the IdChar function accessible from ctime.c */
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3IsIdChar(u8 c){ return IdChar(c); }
+#endif
/*
diff --git a/src/vdbe.c b/src/vdbe.c
index cba5c380e..ef639145c 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3521,6 +3521,26 @@ case OP_Close: {
break;
}
+#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
+/* Opcode: ColumnsUsed P1 * * P4 *
+**
+** This opcode (which only exists if SQLite was compiled with
+** SQLITE_ENABLE_COLUMN_USED_MASK) identifies which columns of the
+** table or index for cursor P1 are used. P4 is a 64-bit integer
+** (P4_INT64) in which the first 63 bits are one for each of the
+** first 63 columns of the table or index that are actually used
+** by the cursor. The high-order bit is set if any column after
+** the 64th is used.
+*/
+case OP_ColumnsUsed: {
+ VdbeCursor *pC;
+ pC = p->apCsr[pOp->p1];
+ assert( pC->pCursor );
+ pC->maskUsed = *(u64*)pOp->p4.pI64;
+ break;
+}
+#endif
+
/* Opcode: SeekGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
diff --git a/src/vdbe.h b/src/vdbe.h
index ffce30377..f6a8b6107 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -171,6 +171,7 @@ int sqlite3VdbeAddOp1(Vdbe*,int,int);
int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
+int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 06ffd95b5..6fe6f6dc4 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -83,6 +83,9 @@ struct VdbeCursor {
i64 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
+#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
+ u64 maskUsed; /* Mask of columns used by this cursor */
+#endif
/* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheStatus matches
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 28018ed46..38ca6475c 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -235,6 +235,23 @@ int sqlite3VdbeAddOp4(
}
/*
+** Add an opcode that includes the p4 value with a P4_INT64 type.
+*/
+int sqlite3VdbeAddOp4Dup8(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ const u8 *zP4, /* The P4 operand */
+ int p4type /* P4 operand type */
+){
+ char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8);
+ if( p4copy ) memcpy(p4copy, zP4, 8);
+ return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
+}
+
+/*
** Add an OP_ParseSchema opcode. This routine is broken out from
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
** as having been used.
@@ -398,6 +415,7 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_VUpdate
** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
+** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does
@@ -409,6 +427,8 @@ static Op *opIterNext(VdbeOpIter *p){
int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasAbort = 0;
int hasFkCounter = 0;
+ int hasCreateTable = 0;
+ int hasInitCoroutine = 0;
Op *pOp;
VdbeOpIter sIter;
memset(&sIter, 0, sizeof(sIter));
@@ -423,6 +443,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
hasAbort = 1;
break;
}
+ if( opcode==OP_CreateTable ) hasCreateTable = 1;
+ if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
hasFkCounter = 1;
@@ -436,7 +458,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** through all opcodes and hasAbort may be set incorrectly. Return
** true for this case to prevent the assert() in the callers frame
** from failing. */
- return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
+ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter
+ || (hasCreateTable && hasInitCoroutine) );
}
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
@@ -1219,12 +1242,11 @@ void sqlite3VdbeEnter(Vdbe *p){
/*
** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
*/
-void sqlite3VdbeLeave(Vdbe *p){
+static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){
int i;
sqlite3 *db;
Db *aDb;
int nDb;
- if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db;
aDb = db->aDb;
nDb = db->nDb;
@@ -1234,6 +1256,10 @@ void sqlite3VdbeLeave(Vdbe *p){
}
}
}
+void sqlite3VdbeLeave(Vdbe *p){
+ if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
+ vdbeLeave(p);
+}
#endif
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 95378954f..c91ced11a 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -942,6 +942,32 @@ int sqlite3VdbeMemSetStr(
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
+static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
+ BtCursor *pCur, /* Cursor pointing at record to retrieve. */
+ u32 offset, /* Offset from the start of data to return bytes from. */
+ u32 amt, /* Number of bytes to return. */
+ int key, /* If true, retrieve from the btree key, not data. */
+ Mem *pMem /* OUT: Return data in this Mem structure. */
+){
+ int rc;
+ pMem->flags = MEM_Null;
+ if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
+ if( key ){
+ rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
+ }else{
+ rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
+ }
+ if( rc==SQLITE_OK ){
+ pMem->z[amt] = 0;
+ pMem->z[amt+1] = 0;
+ pMem->flags = MEM_Blob|MEM_Term;
+ pMem->n = (int)amt;
+ }else{
+ sqlite3VdbeMemRelease(pMem);
+ }
+ }
+ return rc;
+}
int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
u32 offset, /* Offset from the start of data to return bytes from. */
@@ -971,22 +997,7 @@ int sqlite3VdbeMemFromBtree(
pMem->flags = MEM_Blob|MEM_Ephem;
pMem->n = (int)amt;
}else{
- pMem->flags = MEM_Null;
- if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
- if( key ){
- rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
- }else{
- rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
- }
- if( rc==SQLITE_OK ){
- pMem->z[amt] = 0;
- pMem->z[amt+1] = 0;
- pMem->flags = MEM_Blob|MEM_Term;
- pMem->n = (int)amt;
- }else{
- sqlite3VdbeMemRelease(pMem);
- }
- }
+ rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
}
return rc;
diff --git a/src/where.c b/src/where.c
index e32d176ea..5be830e7e 100644
--- a/src/where.c
+++ b/src/where.c
@@ -4213,6 +4213,10 @@ WhereInfo *sqlite3WhereBegin(
SQLITE_INT_TO_PTR(n), P4_INT32);
assert( n<=pTab->nCol );
}
+#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
+ sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0,
+ (const u8*)&pTabItem->colUsed, P4_INT64);
+#endif
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
@@ -4258,6 +4262,21 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
}
VdbeComment((v, "%s", pIx->zName));
+#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
+ {
+ u64 colUsed = 0;
+ int ii, jj;
+ for(ii=0; ii<pIx->nColumn; ii++){
+ jj = pIx->aiColumn[ii];
+ if( jj<0 ) continue;
+ if( jj>63 ) jj = 63;
+ if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue;
+ colUsed |= ((u64)1)<<(ii<63 ? ii : 63);
+ }
+ sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0,
+ (u8*)&colUsed, P4_INT64);
+ }
+#endif /* SQLITE_ENABLE_COLUMN_USED_MASK */
}
}
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);