aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c39
-rw-r--r--src/select.c12
-rw-r--r--src/sqliteInt.h4
3 files changed, 41 insertions, 14 deletions
diff --git a/src/expr.c b/src/expr.c
index 034088faf..70526aea6 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3440,7 +3440,6 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
** an incorrect 0 or 1 could lead to a malfunction.
*/
int sqlite3ExprCompare(Expr *pA, Expr *pB){
- int i;
if( pA==0||pB==0 ){
return pB==pA ? 0 : 2;
}
@@ -3453,18 +3452,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA->op!=pB->op ) return 2;
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
-
- if( pA->x.pList && pB->x.pList ){
- if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 2;
- for(i=0; i<pA->x.pList->nExpr; i++){
- Expr *pExprA = pA->x.pList->a[i].pExpr;
- Expr *pExprB = pB->x.pList->a[i].pExpr;
- if( sqlite3ExprCompare(pExprA, pExprB) ) return 2;
- }
- }else if( pA->x.pList || pB->x.pList ){
- return 2;
- }
-
+ if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
if( ExprHasProperty(pA, EP_IntValue) ){
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
@@ -3481,6 +3469,31 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
return 0;
}
+/*
+** Compare two ExprList objects. Return 0 if they are identical and
+** non-zero if they differ in any way.
+**
+** This routine might return non-zero for equivalent ExprLists. The
+** only consequence will be disabled optimizations. But this routine
+** must never return 0 if the two ExprList objects are different, or
+** a malfunction will result.
+**
+** Two NULL pointers are considered to be the same. But a NULL pointer
+** always differs from a non-NULL pointer.
+*/
+int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
+ int i;
+ if( pA==0 && pB==0 ) return 0;
+ if( pA==0 || pB==0 ) return 1;
+ if( pA->nExpr!=pB->nExpr ) return 1;
+ for(i=0; i<pA->nExpr; i++){
+ Expr *pExprA = pA->a[i].pExpr;
+ Expr *pExprB = pB->a[i].pExpr;
+ if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
+ if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
+ }
+ return 0;
+}
/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
diff --git a/src/select.c b/src/select.c
index 47e409ffc..9a016039a 100644
--- a/src/select.c
+++ b/src/select.c
@@ -3718,6 +3718,18 @@ int sqlite3Select(
isDistinct = 0;
}
+ /* If there is both a GROUP BY and an ORDER BY clause and they are
+ ** identical, then disable the ORDER BY clause since the GROUP BY
+ ** will cause elements to come out in the correct order. This is
+ ** an optimization - the correct answer should result regardless.
+ ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
+ ** to disable this optimization for testing purposes.
+ */
+ if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
+ && (db->flags & SQLITE_GroupByOrder)==0 ){
+ pOrderBy = 0;
+ }
+
/* If there is an ORDER BY clause, then this sorting
** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 6e6ec72ac..d4f8d23aa 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -925,7 +925,8 @@ struct sqlite3 {
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
-#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
+#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
+#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
/*
** Possible values for the sqlite.magic field.
@@ -2689,6 +2690,7 @@ void sqlite3Vacuum(Parse*);
int sqlite3RunVacuum(char**, sqlite3*);
char *sqlite3NameFromToken(sqlite3*, Token*);
int sqlite3ExprCompare(Expr*, Expr*);
+int sqlite3ExprListCompare(ExprList*, ExprList*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);