aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c11
-rw-r--r--src/expr.c21
-rw-r--r--src/parse.y1
-rw-r--r--src/select.c57
-rw-r--r--src/shell.c143
-rw-r--r--src/sqliteInt.h11
-rw-r--r--src/test_rtree.c1
-rw-r--r--src/tokenize.c2
-rw-r--r--src/vdbe.c2
-rw-r--r--src/vdbeaux.c118
-rw-r--r--src/where.c40
11 files changed, 202 insertions, 205 deletions
diff --git a/src/build.c b/src/build.c
index 06ecf6570..f5ea5be4b 100644
--- a/src/build.c
+++ b/src/build.c
@@ -3805,25 +3805,20 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
int i;
int nCol = pIdx->nColumn;
- int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
- sqlite3 *db = pParse->db;
- KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(db, nBytes);
+ KeyInfo *pKey;
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol);
if( pKey ){
- pKey->db = pParse->db;
- pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]);
- assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) );
for(i=0; i<nCol; i++){
char *zColl = pIdx->azColl[i];
assert( zColl );
pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl);
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
- pKey->nField = (u16)nCol;
}
if( pParse->nErr ){
- sqlite3DbFree(db, pKey);
+ sqlite3DbFree(pParse->db, pKey);
pKey = 0;
}
return pKey;
diff --git a/src/expr.c b/src/expr.c
index e7ac855f7..3857d5d84 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1692,10 +1692,9 @@ int sqlite3CodeSubselect(
switch( pExpr->op ){
case TK_IN: {
char affinity; /* Affinity of the LHS of the IN */
- KeyInfo keyInfo; /* Keyinfo for the generated table */
- static u8 sortOrder = 0; /* Fake aSortOrder for keyInfo */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
+ KeyInfo *pKeyInfo = 0; /* Key information */
if( rMayHaveNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
@@ -1719,9 +1718,7 @@ int sqlite3CodeSubselect(
pExpr->iTable = pParse->nTab++;
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
- memset(&keyInfo, 0, sizeof(keyInfo));
- keyInfo.nField = 1;
- keyInfo.aSortOrder = &sortOrder;
+ pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
@@ -1738,11 +1735,12 @@ int sqlite3CodeSubselect(
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
pExpr->x.pSelect->iLimit = 0;
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
+ sqlite3DbFree(pParse->db, pKeyInfo);
return 0;
}
pEList = pExpr->x.pSelect->pEList;
- if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){
- keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
+ if( pKeyInfo && ALWAYS(pEList!=0 && pEList->nExpr>0) ){
+ pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}
}else if( ALWAYS(pExpr->x.pList!=0) ){
@@ -1761,8 +1759,9 @@ int sqlite3CodeSubselect(
if( !affinity ){
affinity = SQLITE_AFF_NONE;
}
- keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- keyInfo.aSortOrder = &sortOrder;
+ if( pKeyInfo ){
+ pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
+ }
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
@@ -1801,8 +1800,8 @@ int sqlite3CodeSubselect(
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
- if( !isRowid ){
- sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
+ if( pKeyInfo ){
+ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO_HANDOFF);
}
break;
}
diff --git a/src/parse.y b/src/parse.y
index 139040339..e9c8a1563 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -417,6 +417,7 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
if( Z ){
Z->op = (u8)Y;
Z->pPrior = X;
+ if( Y!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, X);
}
diff --git a/src/select.c b/src/select.c
index 014feca8f..83fcf7ed4 100644
--- a/src/select.c
+++ b/src/select.c
@@ -803,6 +803,25 @@ static void selectInnerLoop(
}
/*
+** Allocate a KeyInfo object sufficient for an index of N columns.
+**
+** Actually, always allocate one extra column for the rowid at the end
+** of the index. So the KeyInfo returned will have space sufficient for
+** N+1 columns.
+*/
+KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N){
+ KeyInfo *p = sqlite3DbMallocZero(db,
+ sizeof(KeyInfo) + (N+1)*(sizeof(CollSeq*)+1));
+ if( p ){
+ p->aSortOrder = (u8*)&p->aColl[N+1];
+ p->nField = (u16)N;
+ p->enc = ENC(db);
+ p->db = db;
+ }
+ return p;
+}
+
+/*
** Given an expression list, generate a KeyInfo structure that records
** the collating sequence for each expression in that expression list.
**
@@ -818,25 +837,19 @@ static void selectInnerLoop(
** P4_KEYINFO_HANDOFF is the usual way of dealing with this.
*/
static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
- sqlite3 *db = pParse->db;
int nExpr;
KeyInfo *pInfo;
struct ExprList_item *pItem;
+ sqlite3 *db = pParse->db;
int i;
nExpr = pList->nExpr;
- pInfo = sqlite3DbMallocZero(db, sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
+ pInfo = sqlite3KeyInfoAlloc(db, nExpr);
if( pInfo ){
- pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
- pInfo->nField = (u16)nExpr;
- pInfo->enc = ENC(db);
- pInfo->db = db;
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
CollSeq *pColl;
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
- if( !pColl ){
- pColl = db->pDfltColl;
- }
+ if( !pColl ) pColl = db->pDfltColl;
pInfo->aColl[i] = pColl;
pInfo->aSortOrder[i] = pItem->sortOrder;
}
@@ -1942,23 +1955,17 @@ static int multiSelect(
assert( p->pRightmost==p );
nCol = p->pEList->nExpr;
- pKeyInfo = sqlite3DbMallocZero(db,
- sizeof(*pKeyInfo)+nCol*(sizeof(CollSeq*) + 1));
+ pKeyInfo = sqlite3KeyInfoAlloc(db, nCol);
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
}
-
- pKeyInfo->enc = ENC(db);
- pKeyInfo->nField = (u16)nCol;
-
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
*apColl = multiSelectCollSeq(pParse, p, i);
if( 0==*apColl ){
*apColl = db->pDfltColl;
}
}
- pKeyInfo->aSortOrder = (u8*)apColl;
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
for(i=0; i<2; i++){
@@ -2327,12 +2334,8 @@ static int multiSelectOrderBy(
assert( pItem->iOrderByCol>0 && pItem->iOrderByCol<=p->pEList->nExpr );
aPermute[i] = pItem->iOrderByCol - 1;
}
- pKeyMerge =
- sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq*)+1));
+ pKeyMerge = sqlite3KeyInfoAlloc(db, nOrderBy);
if( pKeyMerge ){
- pKeyMerge->aSortOrder = (u8*)&pKeyMerge->aColl[nOrderBy];
- pKeyMerge->nField = (u16)nOrderBy;
- pKeyMerge->enc = ENC(db);
for(i=0; i<nOrderBy; i++){
CollSeq *pColl;
Expr *pTerm = pOrderBy->a[i].pExpr;
@@ -2369,12 +2372,8 @@ static int multiSelectOrderBy(
regPrev = pParse->nMem+1;
pParse->nMem += nExpr+1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
- pKeyDup = sqlite3DbMallocZero(db,
- sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
+ pKeyDup = sqlite3KeyInfoAlloc(db, nExpr);
if( pKeyDup ){
- pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr];
- pKeyDup->nField = (u16)nExpr;
- pKeyDup->enc = ENC(db);
for(i=0; i<nExpr; i++){
pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
pKeyDup->aSortOrder[i] = 0;
@@ -3640,10 +3639,12 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
memset(&w, 0, sizeof(w));
- w.xSelectCallback = convertCompoundSelectToSubquery;
w.xExprCallback = exprWalkNoop;
w.pParse = pParse;
- sqlite3WalkSelect(&w, pSelect);
+ if( pParse->hasCompound ){
+ w.xSelectCallback = convertCompoundSelectToSubquery;
+ sqlite3WalkSelect(&w, pSelect);
+ }
w.xSelectCallback = selectExpander;
sqlite3WalkSelect(&w, pSelect);
}
diff --git a/src/shell.c b/src/shell.c
index 7b8a8ad7f..4a59c667a 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -53,7 +53,6 @@
# include <readline/history.h>
#endif
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
-# define readline(p) local_getline(p,stdin,0)
# define add_history(X)
# define read_history(X)
# define write_history(X)
@@ -337,23 +336,13 @@ static void shellstaticFunc(
** to the text. NULL is returned at end of file, or if malloc()
** fails.
**
-** The interface is like "readline" but no command-line editing
-** is done.
+** If zLine is not NULL then it is a malloced buffer returned from
+** a previous call to this routine that may be reused.
*/
-static char *local_getline(char *zPrompt, FILE *in, int csvFlag){
- char *zLine;
- int nLine;
- int n;
- int inQuote = 0;
+static char *local_getline(char *zLine, FILE *in){
+ int nLine = zLine==0 ? 0 : 100;
+ int n = 0;
- if( zPrompt && *zPrompt ){
- printf("%s",zPrompt);
- fflush(stdout);
- }
- nLine = 100;
- zLine = malloc( nLine );
- if( zLine==0 ) return 0;
- n = 0;
while( 1 ){
if( n+100>nLine ){
nLine = nLine*2 + 100;
@@ -368,42 +357,48 @@ static char *local_getline(char *zPrompt, FILE *in, int csvFlag){
zLine[n] = 0;
break;
}
- while( zLine[n] ){
- if( zLine[n]=='"' ) inQuote = !inQuote;
- n++;
- }
- if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){
+ while( zLine[n] ) n++;
+ if( n>0 && zLine[n-1]=='\n' ){
n--;
if( n>0 && zLine[n-1]=='\r' ) n--;
zLine[n] = 0;
break;
}
}
- zLine = realloc( zLine, n+1 );
return zLine;
}
/*
** Retrieve a single line of input text.
**
-** zPrior is a string of prior text retrieved. If not the empty
-** string, then issue a continuation prompt.
+** If in==0 then read from standard input and prompt before each line.
+** If isContinuation is true, then a continuation prompt is appropriate.
+** If isContinuation is zero, then the main prompt should be used.
+**
+** If zPrior is not NULL then it is a buffer from a prior call to this
+** routine that can be reused.
+**
+** The result is stored in space obtained from malloc() and must either
+** be freed by the caller or else passed back into this routine via the
+** zPrior argument for reuse.
*/
-static char *one_input_line(const char *zPrior, FILE *in){
+static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
if( in!=0 ){
- return local_getline(0, in, 0);
- }
- if( zPrior && zPrior[0] ){
- zPrompt = continuePrompt;
+ zResult = local_getline(zPrior, in);
}else{
- zPrompt = mainPrompt;
- }
- zResult = readline(zPrompt);
+ zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if defined(HAVE_READLINE) && HAVE_READLINE==1
- if( zResult && *zResult ) add_history(zResult);
+ free(zPrior);
+ zResult = readline(zPrompt);
+ if( zResult && *zResult ) add_history(zResult);
+#else
+ printf("%s", zPrompt);
+ fflush(stdout);
+ zResult = local_getline(zPrior, stdin);
#endif
+ }
return zResult;
}
@@ -1995,6 +1990,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
+ int needCommit; /* True to COMMIT or ROLLBACK at end */
int nSep; /* Number of bytes in p->separator[] */
char *zSql; /* An SQL statement */
CSVReader sCsv; /* Reader context */
@@ -2096,6 +2092,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
xCloser(sCsv.in);
return 1;
}
+ needCommit = sqlite3_get_autocommit(db);
+ if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
do{
int startLine = sCsv.nLine;
for(i=0; i<nCol; i++){
@@ -2132,7 +2130,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
xCloser(sCsv.in);
sqlite3_free(sCsv.z);
sqlite3_finalize(pStmt);
- sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+ if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
@@ -2781,7 +2779,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
** Return TRUE if a semicolon occurs anywhere in the first N characters
** of string z[].
*/
-static int _contains_semicolon(const char *z, int N){
+static int line_contains_semicolon(const char *z, int N){
int i;
for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
return 0;
@@ -2816,7 +2814,7 @@ static int _all_whitespace(const char *z){
** than a semi-colon. The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
-static int _is_command_terminator(const char *zLine){
+static int line_is_command_terminator(const char *zLine){
while( IsSpace(zLine[0]) ){ zLine++; };
if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
return 1; /* Oracle */
@@ -2832,7 +2830,7 @@ static int _is_command_terminator(const char *zLine){
** Return true if zSql is a complete SQL statement. Return false if it
** ends in the middle of a string literal or C-style comment.
*/
-static int _is_complete(char *zSql, int nSql){
+static int line_is_complete(char *zSql, int nSql){
int rc;
if( zSql==0 ) return 1;
zSql[nSql] = ';';
@@ -2852,20 +2850,21 @@ static int _is_complete(char *zSql, int nSql){
** Return the number of errors.
*/
static int process_input(struct callback_data *p, FILE *in){
- char *zLine = 0;
- char *zSql = 0;
- int nSql = 0;
- int nSqlPrior = 0;
- char *zErrMsg;
- int rc;
- int errCnt = 0;
- int lineno = 0;
- int startline = 0;
+ char *zLine = 0; /* A single input line */
+ char *zSql = 0; /* Accumulated SQL text */
+ int nLine; /* Length of current line */
+ int nSql = 0; /* Bytes of zSql[] used */
+ int nAlloc = 0; /* Allocated zSql[] space */
+ int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
+ char *zErrMsg; /* Error message returned */
+ int rc; /* Error code */
+ int errCnt = 0; /* Number of errors seen */
+ int lineno = 0; /* Current line number */
+ int startline = 0; /* Line number for start of current input */
while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
fflush(p->out);
- free(zLine);
- zLine = one_input_line(zSql, in);
+ zLine = one_input_line(in, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
if( stdin_is_interactive ) printf("\n");
@@ -2876,7 +2875,7 @@ static int process_input(struct callback_data *p, FILE *in){
seenInterrupt = 0;
}
lineno++;
- if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
+ if( nSql==0 && _all_whitespace(zLine) ) continue;
if( zLine && zLine[0]=='.' && nSql==0 ){
if( p->echoOn ) printf("%s\n", zLine);
rc = do_meta_command(zLine, p);
@@ -2887,35 +2886,31 @@ static int process_input(struct callback_data *p, FILE *in){
}
continue;
}
- if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){
+ if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
memcpy(zLine,";",2);
}
+ nLine = strlen30(zLine);
+ if( nSql+nLine+2>=nAlloc ){
+ nAlloc = nSql+nLine+100;
+ zSql = realloc(zSql, nAlloc);
+ if( zSql==0 ){
+ fprintf(stderr, "Error: out of memory\n");
+ exit(1);
+ }
+ }
nSqlPrior = nSql;
- if( zSql==0 ){
+ if( nSql==0 ){
int i;
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
- if( zLine[i]!=0 ){
- nSql = strlen30(zLine);
- zSql = malloc( nSql+3 );
- if( zSql==0 ){
- fprintf(stderr, "Error: out of memory\n");
- exit(1);
- }
- memcpy(zSql, zLine, nSql+1);
- startline = lineno;
- }
+ memcpy(zSql, zLine+i, nLine+1-i);
+ startline = lineno;
+ nSql = nLine-i;
}else{
- int len = strlen30(zLine);
- zSql = realloc( zSql, nSql + len + 4 );
- if( zSql==0 ){
- fprintf(stderr,"Error: out of memory\n");
- exit(1);
- }
zSql[nSql++] = '\n';
- memcpy(&zSql[nSql], zLine, len+1);
- nSql += len;
+ memcpy(zSql+nSql, zLine, nLine+1);
+ nSql += nLine;
}
- if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
+ if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
&& sqlite3_complete(zSql) ){
p->cnt = 0;
open_db(p);
@@ -2939,16 +2934,12 @@ static int process_input(struct callback_data *p, FILE *in){
}
errCnt++;
}
- free(zSql);
- zSql = 0;
nSql = 0;
- }else if( zSql && _all_whitespace(zSql) ){
- free(zSql);
- zSql = 0;
+ }else if( nSql && _all_whitespace(zSql) ){
nSql = 0;
}
}
- if( zSql ){
+ if( nSql ){
if( !_all_whitespace(zSql) ){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index d6b4dd492..b16295904 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1472,12 +1472,16 @@ struct FKey {
** An instance of the following structure is passed as the first
** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys.
+**
+** Note that aSortOrder[] and aColl[] have nField+1 slots. There
+** are nField slots for the columns of an index then one extra slot
+** for the rowid at the end.
*/
struct KeyInfo {
sqlite3 *db; /* The database connection */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
- u16 nField; /* Number of entries in aColl[] */
- u8 *aSortOrder; /* Sort order for each column. May be NULL */
+ u16 nField; /* Maximum index for aColl[] and aSortOrder[] */
+ u8 *aSortOrder; /* Sort order for each column. */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
};
@@ -2082,6 +2086,7 @@ struct Select {
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
#define SF_Materialize 0x0100 /* Force materialization of views */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
+#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
/*
@@ -2203,6 +2208,7 @@ struct Parse {
u8 iColCache; /* Next entry in aColCache[] to replace */
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
+ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
int aTempReg[8]; /* Holding area for temporary registers */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
@@ -3098,6 +3104,7 @@ void sqlite3MinimumFileFormat(Parse*, int, int);
void sqlite3SchemaClear(void *);
Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
+KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int);
KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **),
diff --git a/src/test_rtree.c b/src/test_rtree.c
index f54ae9b06..e1966c243 100644
--- a/src/test_rtree.c
+++ b/src/test_rtree.c
@@ -14,6 +14,7 @@
*/
#include <sqlite3.h>
+#include <tcl.h>
/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"
diff --git a/src/tokenize.c b/src/tokenize.c
index aef1d300f..d26157f7d 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -123,7 +123,6 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
case '-': {
if( z[1]=='-' ){
- /* IMP: R-50417-27976 -- syntax diagram for comments */
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
return i;
@@ -156,7 +155,6 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_SLASH;
return 1;
}
- /* IMP: R-50417-27976 -- syntax diagram for comments */
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++;
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
diff --git a/src/vdbe.c b/src/vdbe.c
index 2c9edf897..efbd182f2 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -565,7 +565,7 @@ int sqlite3VdbeExec(
int iCompare = 0; /* Result of last OP_Compare operation */
unsigned nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
+ unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 3235e1428..8f7f0a9c4 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -408,40 +408,60 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode;
- pOp->opflags = sqlite3OpcodeProperty[opcode];
- if( opcode==OP_Function || opcode==OP_AggStep ){
- if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
- }else if( opcode==OP_Transaction ){
- if( pOp->p2!=0 ) p->readOnly = 0;
- p->bIsReader = 1;
- }else if( opcode==OP_AutoCommit || opcode==OP_Savepoint ){
- p->bIsReader = 1;
- }else if( opcode==OP_Vacuum
- || opcode==OP_JournalMode
+ /* NOTE: Be sure to update mkopcodeh.awk when adding or removing
+ ** cases from this switch! */
+ switch( opcode ){
+ case OP_Function:
+ case OP_AggStep: {
+ if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
+ break;
+ }
+ case OP_Transaction: {
+ if( pOp->p2!=0 ) p->readOnly = 0;
+ /* fall thru */
+ }
+ case OP_AutoCommit:
+ case OP_Savepoint: {
+ p->bIsReader = 1;
+ break;
+ }
#ifndef SQLITE_OMIT_WAL
- || opcode==OP_Checkpoint
+ case OP_Checkpoint:
#endif
- ){
- p->readOnly = 0;
- p->bIsReader = 1;
+ case OP_Vacuum:
+ case OP_JournalMode: {
+ p->readOnly = 0;
+ p->bIsReader = 1;
+ break;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
- }else if( opcode==OP_VUpdate ){
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
- }else if( opcode==OP_VFilter ){
- int n;
- assert( p->nOp - i >= 3 );
- assert( pOp[-1].opcode==OP_Integer );
- n = pOp[-1].p1;
- if( n>nMaxArgs ) nMaxArgs = n;
+ case OP_VUpdate: {
+ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
+ break;
+ }
+ case OP_VFilter: {
+ int n;
+ assert( p->nOp - i >= 3 );
+ assert( pOp[-1].opcode==OP_Integer );
+ n = pOp[-1].p1;
+ if( n>nMaxArgs ) nMaxArgs = n;
+ break;
+ }
#endif
- }else if( opcode==OP_Next || opcode==OP_SorterNext ){
- pOp->p4.xAdvance = sqlite3BtreeNext;
- pOp->p4type = P4_ADVANCE;
- }else if( opcode==OP_Prev ){
- pOp->p4.xAdvance = sqlite3BtreePrevious;
- pOp->p4type = P4_ADVANCE;
+ case OP_Next:
+ case OP_SorterNext: {
+ pOp->p4.xAdvance = sqlite3BtreeNext;
+ pOp->p4type = P4_ADVANCE;
+ break;
+ }
+ case OP_Prev: {
+ pOp->p4.xAdvance = sqlite3BtreePrevious;
+ pOp->p4type = P4_ADVANCE;
+ break;
+ }
}
+ pOp->opflags = sqlite3OpcodeProperty[opcode];
if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
assert( -1-pOp->p2<p->nLabel );
pOp->p2 = aLabel[-1-pOp->p2];
@@ -730,20 +750,13 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
}else if( n==P4_KEYINFO ){
- KeyInfo *pKeyInfo;
- int nField, nByte;
-
- nField = ((KeyInfo*)zP4)->nField;
- nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
- pKeyInfo = sqlite3DbMallocRaw(0, nByte);
- pOp->p4.pKeyInfo = pKeyInfo;
- if( pKeyInfo ){
- u8 *aSortOrder;
- memcpy((char*)pKeyInfo, zP4, nByte - nField);
- aSortOrder = pKeyInfo->aSortOrder;
- assert( aSortOrder!=0 );
- pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
- memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
+ KeyInfo *pOrig, *pNew;
+
+ pOrig = (KeyInfo*)zP4;
+ pOp->p4.pKeyInfo = pNew = sqlite3KeyInfoAlloc(db, pOrig->nField);
+ if( pNew ){
+ memcpy(pNew->aColl, pOrig->aColl, pOrig->nField*sizeof(pNew->aColl[0]));
+ memcpy(pNew->aSortOrder, pOrig->aSortOrder, pOrig->nField);
pOp->p4type = P4_KEYINFO;
}else{
p->db->mallocFailed = 1;
@@ -2995,7 +3008,6 @@ int sqlite3VdbeRecordCompare(
u32 idx1; /* Offset into aKey[] of next header element */
u32 szHdr1; /* Number of bytes in header */
int i = 0;
- int nField;
int rc = 0;
const unsigned char *aKey1 = (const unsigned char *)pKey1;
KeyInfo *pKeyInfo;
@@ -3018,14 +3030,25 @@ int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
- nField = pKeyInfo->nField;
+ assert( pKeyInfo->nField+1>=pPKey2->nField );
assert( pKeyInfo->aSortOrder!=0 );
while( idx1<szHdr1 && i<pPKey2->nField ){
u32 serial_type1;
/* Read the serial types for the next element in each key. */
idx1 += getVarint32( aKey1+idx1, serial_type1 );
- if( d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 ) break;
+
+ /* Verify that there is enough key space remaining to avoid
+ ** a buffer overread. The "d1+serial_type1+2" subexpression will
+ ** always be greater than or equal to the amount of required key space.
+ ** Use that approximation to avoid the more expensive call to
+ ** sqlite3VdbeSerialTypeLen() in the common case.
+ */
+ if( d1+serial_type1+2>(u32)nKey1
+ && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1
+ ){
+ break;
+ }
/* Extract the values to be compared.
*/
@@ -3033,13 +3056,12 @@ int sqlite3VdbeRecordCompare(
/* Do the comparison
*/
- rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
- i<nField ? pKeyInfo->aColl[i] : 0);
+ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]);
if( rc!=0 ){
assert( mem1.zMalloc==0 ); /* See comment below */
/* Invert the result if we are using DESC sort order. */
- if( i<nField && pKeyInfo->aSortOrder[i] ){
+ if( pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
diff --git a/src/where.c b/src/where.c
index 02193785b..2bf3aaecb 100644
--- a/src/where.c
+++ b/src/where.c
@@ -658,7 +658,7 @@ static void whereClauseClear(WhereClause *pWC){
static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
WhereTerm *pTerm;
int idx;
- testcase( wtFlags & TERM_VIRTUAL ); /* EV: R-00211-15100 */
+ testcase( wtFlags & TERM_VIRTUAL );
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
sqlite3 *db = pWC->pWInfo->pParse->db;
@@ -803,13 +803,6 @@ static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){
** Return TRUE if the given operator is one of the operators that is
** allowed for an indexable WHERE clause term. The allowed operators are
** "=", "<", ">", "<=", ">=", "IN", and "IS NULL"
-**
-** IMPLEMENTATION-OF: R-59926-26393 To be usable by an index a term must be
-** of one of the following forms: column = expression column > expression
-** column >= expression column < expression column <= expression
-** expression = column expression > column expression >= column
-** expression < column expression <= column column IN
-** (expression-list) column IN (subquery) column IS NULL
*/
static int allowedOp(int op){
assert( TK_GT>TK_EQ && TK_GT<TK_GE );
@@ -1483,8 +1476,6 @@ static void exprAnalyzeOrTerm(
/* At this point, okToChngToIN is true if original pTerm satisfies
** case 1. In that case, construct a new virtual term that is
** pTerm converted into an IN operator.
- **
- ** EV: R-00211-15100
*/
if( okToChngToIN ){
Expr *pDup; /* A transient duplicate expression */
@@ -1726,9 +1717,7 @@ static void exprAnalyze(
** inequality. To avoid this, make sure to also run the full
** LIKE on all candidate expressions by clearing the isComplete flag
*/
- if( c=='A'-1 ) isComplete = 0; /* EV: R-64339-08207 */
-
-
+ if( c=='A'-1 ) isComplete = 0;
c = sqlite3UpperToLower[c];
}
*pC = c + 1;
@@ -2818,9 +2807,6 @@ static int whereInScanEst(
** in the ON clause. The term is disabled in (3) because it is not part
** of a LEFT OUTER JOIN. In (1), the term is not disabled.
**
-** IMPLEMENTATION-OF: R-24597-58655 No tests are done for terms that are
-** completely satisfied by indices.
-**
** Disabling a term causes that term to not be tested in the inner loop
** of the join. Disabling is an optimization. When terms are satisfied
** by indices, we disable them to prevent redundant tests in the inner
@@ -3050,7 +3036,7 @@ static int codeAllEqualityTerms(
/* The following true for indices with redundant columns.
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
- testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
@@ -3361,7 +3347,7 @@ static Bitmask codeOneLoopStart(
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
assert( omitTable==0 );
- testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -3409,7 +3395,7 @@ static Bitmask codeOneLoopStart(
assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
assert( (pStart->wtFlags & TERM_VNULL)==0 );
- testcase( pStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
+ testcase( pStart->wtFlags & TERM_VIRTUAL );
pX = pStart->pExpr;
assert( pX!=0 );
testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
@@ -3428,7 +3414,7 @@ static Bitmask codeOneLoopStart(
assert( pX!=0 );
assert( (pEnd->wtFlags & TERM_VNULL)==0 );
testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
- testcase( pEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
+ testcase( pEnd->wtFlags & TERM_VIRTUAL );
memEndValue = ++pParse->nMem;
sqlite3ExprCode(pParse, pX->pRight, memEndValue);
if( pX->op==TK_LT || pX->op==TK_GT ){
@@ -3594,7 +3580,7 @@ static Bitmask codeOneLoopStart(
}
}
nConstraint++;
- testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
+ testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
}else if( isMinQuery ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
nConstraint++;
@@ -3636,7 +3622,7 @@ static Bitmask codeOneLoopStart(
}
codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
nConstraint++;
- testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
+ testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
}
sqlite3DbFree(db, zStartAff);
sqlite3DbFree(db, zEndAff);
@@ -3923,14 +3909,10 @@ static Bitmask codeOneLoopStart(
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
- **
- ** IMPLEMENTATION-OF: R-49525-50935 Terms that cannot be satisfied through
- ** the use of indices become tests that are evaluated against each row of
- ** the relevant input tables.
*/
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE;
- testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & newNotReady)!=0 ){
@@ -3990,7 +3972,7 @@ static Bitmask codeOneLoopStart(
VdbeComment((v, "record LEFT JOIN hit"));
sqlite3ExprCacheClear(pParse);
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
- testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & newNotReady)!=0 ){
@@ -5763,7 +5745,7 @@ WhereInfo *sqlite3WhereBegin(
initMaskSet(pMaskSet);
whereClauseInit(&pWInfo->sWC, pWInfo);
sqlite3ExprCodeConstants(pParse, pWhere);
- whereSplit(&pWInfo->sWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
+ whereSplit(&pWInfo->sWC, pWhere, TK_AND);
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
/* Special case: a WHERE clause that is constant. Evaluate the