aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2022-04-28 12:52:49 +0000
committerdrh <>2022-04-28 12:52:49 +0000
commit09121b0523fd6f2e7795b65222aeace231382ac8 (patch)
tree80b3f69280a822a56187ffdecca7ef8f29e6ad79 /src
parent7980fadceff1593fe703bb5d0b48ab1772ef81ae (diff)
parent22b541b55a12a137b533132396cbdf2e71e2f7d3 (diff)
downloadsqlite-09121b0523fd6f2e7795b65222aeace231382ac8.tar.gz
sqlite-09121b0523fd6f2e7795b65222aeace231382ac8.zip
Merge trunk enhancements into the right-join branch.
FossilOrigin-Name: 3fd9706bba4a71cb5c7ce1341c3be0a7727941445820a073e7b2f0f32512e8ef
Diffstat (limited to 'src')
-rw-r--r--src/analyze.c8
-rw-r--r--src/build.c15
-rw-r--r--src/expr.c36
-rw-r--r--src/select.c22
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/where.c6
6 files changed, 65 insertions, 24 deletions
diff --git a/src/analyze.c b/src/analyze.c
index e8699653f..39009899a 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -847,9 +847,14 @@ static void statGet(
** * "WHERE a=? AND b=?" matches 2 rows.
**
** If D is the count of distinct values and K is the total number of
- ** rows, then each estimate is computed as:
+ ** rows, then each estimate is usually computed as:
**
** I = (K+D-1)/D
+ **
+ ** In other words, I is K/D rounded up to the next whole integer.
+ ** However, if I is between 1.0 and 1.1 (in other words if I is
+ ** close to 1.0 but just a little larger) then do not round up but
+ ** instead keep the I value at 1.0.
*/
sqlite3_str sStat; /* Text of the constructed "stat" line */
int i; /* Loop counter */
@@ -860,6 +865,7 @@ static void statGet(
for(i=0; i<p->nKeyCol; i++){
u64 nDistinct = p->current.anDLt[i] + 1;
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
+ if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
sqlite3_str_appendf(&sStat, " %llu", iVal);
assert( p->current.anEq[i] );
}
diff --git a/src/build.c b/src/build.c
index 8ae263fc3..fbd633209 100644
--- a/src/build.c
+++ b/src/build.c
@@ -172,9 +172,7 @@ void sqlite3FinishCoding(Parse *pParse){
int i;
int reg;
- if( NEVER(pReturning->nRetCol==0) ){
- assert( CORRUPT_DB );
- }else{
+ if( pReturning->nRetCol ){
sqlite3VdbeAddOp0(v, OP_FkCheck);
addrRewind =
sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
@@ -270,9 +268,7 @@ void sqlite3FinishCoding(Parse *pParse){
if( pParse->bReturning ){
Returning *pRet = pParse->u1.pReturning;
- if( NEVER(pRet->nRetCol==0) ){
- assert( CORRUPT_DB );
- }else{
+ if( pRet->nRetCol ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
}
@@ -3059,7 +3055,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
- int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
#ifndef SQLITE_OMIT_VIRTUALTABLE
int rc;
@@ -3117,8 +3112,9 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0);
if( pSel ){
u8 eParseMode = pParse->eParseMode;
+ int nTab = pParse->nTab;
+ int nSelect = pParse->nSelect;
pParse->eParseMode = PARSE_MODE_NORMAL;
- n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
DisableLookaside;
@@ -3130,7 +3126,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
#endif
- pParse->nTab = n;
+ pParse->nTab = nTab;
+ pParse->nSelect = nSelect;
if( pSelTab==0 ){
pTable->nCol = 0;
nErr++;
diff --git a/src/expr.c b/src/expr.c
index f532bba2e..2bc5eae20 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2297,6 +2297,42 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
return exprIsConst(p, 3, iCur);
}
+/*
+** Check pExpr to see if it is an invariant constraint on data source pSrc.
+** This is an optimization. False negatives will perhaps cause slower
+** queries, but false positives will yield incorrect answers. So when in
+** doubt, return 0.
+**
+** To be an invariant constraint, the following must be true:
+**
+** (1) pExpr cannot refer to any table other than pSrc->iCursor.
+**
+** (2) pExpr cannot use subqueries or non-deterministic functions.
+**
+** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
+** (Is there some way to relax this constraint?)
+**
+** (4) If pSrc is the right operand of a LEFT JOIN, then...
+** (4a) pExpr must come from an ON clause..
+ (4b) and specifically the ON clause associated with the LEFT JOIN.
+**
+** (5) If pSrc is not the right operand of a LEFT JOIN or the left
+** operand of a RIGHT JOIN, then pExpr must be from the WHERE
+** clause, not an ON clause.
+*/
+int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
+ if( pSrc->fg.jointype & JT_LTORJ ){
+ return 0; /* rule (3) */
+ }
+ if( pSrc->fg.jointype & JT_LEFT ){
+ if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (4a) */
+ if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */
+ }else{
+ if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (5) */
+ }
+ return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
+}
+
/*
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
diff --git a/src/select.c b/src/select.c
index df4ad4395..3c59b5d5f 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4329,6 +4329,7 @@ static int flattenSubquery(
if( pSrc->nSrc>1 ){
if( pParse->nSelect>500 ) return 0;
+ if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0;
aCsrMap = sqlite3DbMallocZero(db, ((i64)pParse->nTab+1)*sizeof(int));
if( aCsrMap ) aCsrMap[0] = pParse->nTab;
}
@@ -4957,13 +4958,13 @@ static int pushDownWhereTerms(
Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
- int iCursor, /* Cursor number of the subquery */
- int isLeftJoin /* True if pSubq is the right term of a LEFT JOIN */
+ SrcItem *pSrc /* The subquery term of the outer FROM clause */
){
Expr *pNew;
int nChng = 0;
if( pWhere==0 ) return 0;
if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pPrior ){
@@ -4993,10 +4994,11 @@ static int pushDownWhereTerms(
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight,
- iCursor, isLeftJoin);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
pWhere = pWhere->pLeft;
}
+
+#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
if( isLeftJoin
&& (ExprHasProperty(pWhere,EP_FromJoin)==0
|| pWhere->w.iJoin!=iCursor)
@@ -5008,7 +5010,9 @@ static int pushDownWhereTerms(
){
return 0; /* restriction (5) */
}
- if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
+#endif
+
+ if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
nChng++;
pSubq->selFlags |= SF_PushDown;
while( pSubq ){
@@ -5016,8 +5020,8 @@ static int pushDownWhereTerms(
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
unsetJoinExpr(pNew, -1);
x.pParse = pParse;
- x.iTable = iCursor;
- x.iNewTable = iCursor;
+ x.iTable = pSrc->iCursor;
+ x.iNewTable = pSrc->iCursor;
x.isOuterJoin = 0;
x.pEList = pSubq->pEList;
pNew = substExpr(&x, pNew);
@@ -6870,9 +6874,7 @@ int sqlite3Select(
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
- && (pItem->fg.jointype & JT_RIGHT)==0
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
- (pItem->fg.jointype & JT_OUTER)!=0)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
){
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x100 ){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index d9f5bc42e..eb8ad2abe 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1780,6 +1780,7 @@ struct sqlite3 {
#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */
#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
+#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -4753,6 +4754,7 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int);
+int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
int sqlite3ExprContainsSubquery(Expr*);
#endif
diff --git a/src/where.c b/src/where.c
index d6c023941..2750d9358 100644
--- a/src/where.c
+++ b/src/where.c
@@ -832,9 +832,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && ((pSrc->fg.jointype&(JT_LEFT|JT_LTORJ))==0
- || ExprHasProperty(pExpr,EP_FromJoin))
- && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor)
+ && sqlite3ExprIsTableConstraint(pExpr, pSrc)
){
pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -1073,7 +1071,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
Expr *pExpr = pTerm->pExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstant(pExpr, iCur)
+ && sqlite3ExprIsTableConstraint(pExpr, pItem)
){
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}