annotate sqlite/select.c @ 1565:88c0aabb4286 trunk

[svn] - remove static version
author nenolod
date Thu, 10 Aug 2006 20:41:43 -0700
parents b6b61becdf4e
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1434
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2 ** 2001 September 15
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
4 ** The author disclaims copyright to this source code. In place of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
5 ** a legal notice, here is a blessing:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
6 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
7 ** May you do good and not evil.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
8 ** May you find forgiveness for yourself and forgive others.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
9 ** May you share freely, never taking more than you give.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
10 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
11 *************************************************************************
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
12 ** This file contains C code routines that are called by the parser
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
13 ** to handle SELECT statements in SQLite.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
14 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
15 ** $Id: select.c,v 1.313 2006/04/26 17:39:34 drh Exp $
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
16 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
17 #include "sqliteInt.h"
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
18
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
19
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
20 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
21 ** Delete all the content of a Select structure but do not deallocate
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
22 ** the select structure itself.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
23 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
24 static void clearSelect(Select *p){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
25 sqlite3ExprListDelete(p->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
26 sqlite3SrcListDelete(p->pSrc);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
27 sqlite3ExprDelete(p->pWhere);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
28 sqlite3ExprListDelete(p->pGroupBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
29 sqlite3ExprDelete(p->pHaving);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
30 sqlite3ExprListDelete(p->pOrderBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
31 sqlite3SelectDelete(p->pPrior);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
32 sqlite3ExprDelete(p->pLimit);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
33 sqlite3ExprDelete(p->pOffset);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
34 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
35
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
36
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
37 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
38 ** Allocate a new Select structure and return a pointer to that
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
39 ** structure.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
40 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
41 Select *sqlite3SelectNew(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
42 ExprList *pEList, /* which columns to include in the result */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
43 SrcList *pSrc, /* the FROM clause -- which tables to scan */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
44 Expr *pWhere, /* the WHERE clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
45 ExprList *pGroupBy, /* the GROUP BY clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
46 Expr *pHaving, /* the HAVING clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
47 ExprList *pOrderBy, /* the ORDER BY clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
48 int isDistinct, /* true if the DISTINCT keyword is present */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
49 Expr *pLimit, /* LIMIT value. NULL means not used */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
50 Expr *pOffset /* OFFSET value. NULL means no offset */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
51 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
52 Select *pNew;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
53 Select standin;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
54 pNew = sqliteMalloc( sizeof(*pNew) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
55 assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
56 if( pNew==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
57 pNew = &standin;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
58 memset(pNew, 0, sizeof(*pNew));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
59 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
60 if( pEList==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
61 pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
62 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
63 pNew->pEList = pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
64 pNew->pSrc = pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
65 pNew->pWhere = pWhere;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
66 pNew->pGroupBy = pGroupBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
67 pNew->pHaving = pHaving;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
68 pNew->pOrderBy = pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
69 pNew->isDistinct = isDistinct;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
70 pNew->op = TK_SELECT;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
71 pNew->pLimit = pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
72 pNew->pOffset = pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
73 pNew->iLimit = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
74 pNew->iOffset = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
75 pNew->addrOpenVirt[0] = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
76 pNew->addrOpenVirt[1] = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
77 pNew->addrOpenVirt[2] = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
78 if( pNew==&standin) {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
79 clearSelect(pNew);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
80 pNew = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
81 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
82 return pNew;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
83 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
84
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
85 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
86 ** Delete the given Select structure and all of its substructures.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
87 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
88 void sqlite3SelectDelete(Select *p){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
89 if( p ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
90 clearSelect(p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
91 sqliteFree(p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
92 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
93 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
94
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
95 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
96 ** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
97 ** type of join. Return an integer constant that expresses that type
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
98 ** in terms of the following bit values:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
99 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
100 ** JT_INNER
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
101 ** JT_CROSS
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
102 ** JT_OUTER
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
103 ** JT_NATURAL
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
104 ** JT_LEFT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
105 ** JT_RIGHT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
106 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
107 ** A full outer join is the combination of JT_LEFT and JT_RIGHT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
108 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
109 ** If an illegal or unsupported join type is seen, then still return
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
110 ** a join type, but put an error in the pParse structure.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
111 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
112 int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
113 int jointype = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
114 Token *apAll[3];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
115 Token *p;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
116 static const struct {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
117 const char zKeyword[8];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
118 u8 nChar;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
119 u8 code;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
120 } keywords[] = {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
121 { "natural", 7, JT_NATURAL },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
122 { "left", 4, JT_LEFT|JT_OUTER },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
123 { "right", 5, JT_RIGHT|JT_OUTER },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
124 { "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
125 { "outer", 5, JT_OUTER },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
126 { "inner", 5, JT_INNER },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
127 { "cross", 5, JT_INNER|JT_CROSS },
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
128 };
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
129 int i, j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
130 apAll[0] = pA;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
131 apAll[1] = pB;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
132 apAll[2] = pC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
133 for(i=0; i<3 && apAll[i]; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
134 p = apAll[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
135 for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
136 if( p->n==keywords[j].nChar
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
137 && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
138 jointype |= keywords[j].code;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
139 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
140 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
141 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
142 if( j>=sizeof(keywords)/sizeof(keywords[0]) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
143 jointype |= JT_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
144 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
145 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
146 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
147 if(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
148 (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) ||
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
149 (jointype & JT_ERROR)!=0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
150 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
151 const char *zSp1 = " ";
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
152 const char *zSp2 = " ";
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
153 if( pB==0 ){ zSp1++; }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
154 if( pC==0 ){ zSp2++; }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
155 sqlite3ErrorMsg(pParse, "unknown or unsupported join type: "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
156 "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
157 jointype = JT_INNER;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
158 }else if( jointype & JT_RIGHT ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
159 sqlite3ErrorMsg(pParse,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
160 "RIGHT and FULL OUTER JOINs are not currently supported");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
161 jointype = JT_INNER;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
162 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
163 return jointype;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
164 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
165
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
166 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
167 ** Return the index of a column in a table. Return -1 if the column
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
168 ** is not contained in the table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
169 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
170 static int columnIndex(Table *pTab, const char *zCol){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
171 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
172 for(i=0; i<pTab->nCol; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
173 if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
174 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
175 return -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
176 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
177
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
178 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
179 ** Set the value of a token to a '\000'-terminated string.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
180 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
181 static void setToken(Token *p, const char *z){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
182 p->z = (u8*)z;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
183 p->n = z ? strlen(z) : 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
184 p->dyn = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
185 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
186
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
187 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
188 ** Create an expression node for an identifier with the name of zName
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
189 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
190 static Expr *createIdExpr(const char *zName){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
191 Token dummy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
192 setToken(&dummy, zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
193 return sqlite3Expr(TK_ID, 0, 0, &dummy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
194 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
195
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
196
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
197 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
198 ** Add a term to the WHERE expression in *ppExpr that requires the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
199 ** zCol column to be equal in the two tables pTab1 and pTab2.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
200 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
201 static void addWhereTerm(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
202 const char *zCol, /* Name of the column */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
203 const Table *pTab1, /* First table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
204 const char *zAlias1, /* Alias for first table. May be NULL */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
205 const Table *pTab2, /* Second table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
206 const char *zAlias2, /* Alias for second table. May be NULL */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
207 int iRightJoinTable, /* VDBE cursor for the right table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
208 Expr **ppExpr /* Add the equality term to this expression */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
209 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
210 Expr *pE1a, *pE1b, *pE1c;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
211 Expr *pE2a, *pE2b, *pE2c;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
212 Expr *pE;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
213
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
214 pE1a = createIdExpr(zCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
215 pE2a = createIdExpr(zCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
216 if( zAlias1==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
217 zAlias1 = pTab1->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
218 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
219 pE1b = createIdExpr(zAlias1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
220 if( zAlias2==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
221 zAlias2 = pTab2->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
222 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
223 pE2b = createIdExpr(zAlias2);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
224 pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
225 pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
226 pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
227 ExprSetProperty(pE, EP_FromJoin);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
228 pE->iRightJoinTable = iRightJoinTable;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
229 *ppExpr = sqlite3ExprAnd(*ppExpr, pE);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
230 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
231
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
232 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
233 ** Set the EP_FromJoin property on all terms of the given expression.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
234 ** And set the Expr.iRightJoinTable to iTable for every term in the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
235 ** expression.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
236 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
237 ** The EP_FromJoin property is used on terms of an expression to tell
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
238 ** the LEFT OUTER JOIN processing logic that this term is part of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
239 ** join restriction specified in the ON or USING clause and not a part
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
240 ** of the more general WHERE clause. These terms are moved over to the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
241 ** WHERE clause during join processing but we need to remember that they
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
242 ** originated in the ON or USING clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
243 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
244 ** The Expr.iRightJoinTable tells the WHERE clause processing that the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
245 ** expression depends on table iRightJoinTable even if that table is not
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
246 ** explicitly mentioned in the expression. That information is needed
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
247 ** for cases like this:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
248 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
249 ** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
250 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
251 ** The where clause needs to defer the handling of the t1.x=5
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
252 ** term until after the t2 loop of the join. In that way, a
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
253 ** NULL t2 row will be inserted whenever t1.x!=5. If we do not
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
254 ** defer the handling of t1.x=5, it will be processed immediately
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
255 ** after the t1 loop and rows with t1.x!=5 will never appear in
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
256 ** the output, which is incorrect.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
257 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
258 static void setJoinExpr(Expr *p, int iTable){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
259 while( p ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
260 ExprSetProperty(p, EP_FromJoin);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
261 p->iRightJoinTable = iTable;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
262 setJoinExpr(p->pLeft, iTable);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
263 p = p->pRight;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
264 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
265 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
266
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
267 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
268 ** This routine processes the join information for a SELECT statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
269 ** ON and USING clauses are converted into extra terms of the WHERE clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
270 ** NATURAL joins also create extra WHERE clause terms.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
271 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
272 ** The terms of a FROM clause are contained in the Select.pSrc structure.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
273 ** The left most table is the first entry in Select.pSrc. The right-most
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
274 ** table is the last entry. The join operator is held in the entry to
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
275 ** the left. Thus entry 0 contains the join operator for the join between
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
276 ** entries 0 and 1. Any ON or USING clauses associated with the join are
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
277 ** also attached to the left entry.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
278 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
279 ** This routine returns the number of errors encountered.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
280 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
281 static int sqliteProcessJoin(Parse *pParse, Select *p){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
282 SrcList *pSrc; /* All tables in the FROM clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
283 int i, j; /* Loop counters */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
284 struct SrcList_item *pLeft; /* Left table being joined */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
285 struct SrcList_item *pRight; /* Right table being joined */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
286
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
287 pSrc = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
288 pLeft = &pSrc->a[0];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
289 pRight = &pLeft[1];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
290 for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
291 Table *pLeftTab = pLeft->pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
292 Table *pRightTab = pRight->pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
293
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
294 if( pLeftTab==0 || pRightTab==0 ) continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
295
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
296 /* When the NATURAL keyword is present, add WHERE clause terms for
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
297 ** every column that the two tables have in common.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
298 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
299 if( pLeft->jointype & JT_NATURAL ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
300 if( pLeft->pOn || pLeft->pUsing ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
301 sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
302 "an ON or USING clause", 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
303 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
304 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
305 for(j=0; j<pLeftTab->nCol; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
306 char *zName = pLeftTab->aCol[j].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
307 if( columnIndex(pRightTab, zName)>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
308 addWhereTerm(zName, pLeftTab, pLeft->zAlias,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
309 pRightTab, pRight->zAlias,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
310 pRight->iCursor, &p->pWhere);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
311
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
312 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
313 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
314 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
315
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
316 /* Disallow both ON and USING clauses in the same join
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
317 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
318 if( pLeft->pOn && pLeft->pUsing ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
319 sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
320 "clauses in the same join");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
321 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
322 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
323
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
324 /* Add the ON clause to the end of the WHERE clause, connected by
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
325 ** an AND operator.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
326 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
327 if( pLeft->pOn ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
328 setJoinExpr(pLeft->pOn, pRight->iCursor);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
329 p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
330 pLeft->pOn = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
331 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
332
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
333 /* Create extra terms on the WHERE clause for each column named
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
334 ** in the USING clause. Example: If the two tables to be joined are
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
335 ** A and B and the USING clause names X, Y, and Z, then add this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
336 ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
337 ** Report an error if any column mentioned in the USING clause is
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
338 ** not contained in both tables to be joined.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
339 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
340 if( pLeft->pUsing ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
341 IdList *pList = pLeft->pUsing;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
342 for(j=0; j<pList->nId; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
343 char *zName = pList->a[j].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
344 if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
345 sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
346 "not present in both tables", zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
347 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
348 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
349 addWhereTerm(zName, pLeftTab, pLeft->zAlias,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
350 pRightTab, pRight->zAlias,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
351 pRight->iCursor, &p->pWhere);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
352 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
353 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
354 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
355 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
356 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
357
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
358 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
359 ** Insert code into "v" that will push the record on the top of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
360 ** stack into the sorter.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
361 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
362 static void pushOntoSorter(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
363 Parse *pParse, /* Parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
364 ExprList *pOrderBy, /* The ORDER BY clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
365 Select *pSelect /* The whole SELECT statement */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
366 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
367 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
368 sqlite3ExprCodeExprList(pParse, pOrderBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
369 sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
370 sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
371 sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
372 sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
373 if( pSelect->iLimit>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
374 int addr1, addr2;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
375 addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
376 sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
377 addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
378 sqlite3VdbeJumpHere(v, addr1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
379 sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
380 sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
381 sqlite3VdbeJumpHere(v, addr2);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
382 pSelect->iLimit = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
383 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
384 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
385
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
386 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
387 ** Add code to implement the OFFSET
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
388 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
389 static void codeOffset(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
390 Vdbe *v, /* Generate code into this VM */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
391 Select *p, /* The SELECT statement being coded */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
392 int iContinue, /* Jump here to skip the current record */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
393 int nPop /* Number of times to pop stack when jumping */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
394 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
395 if( p->iOffset>=0 && iContinue!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
396 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
397 sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
398 addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
399 if( nPop>0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
400 sqlite3VdbeAddOp(v, OP_Pop, nPop, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
401 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
402 sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
403 VdbeComment((v, "# skip OFFSET records"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
404 sqlite3VdbeJumpHere(v, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
405 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
406 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
407
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
408 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
409 ** Add code that will check to make sure the top N elements of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
410 ** stack are distinct. iTab is a sorting index that holds previously
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
411 ** seen combinations of the N values. A new entry is made in iTab
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
412 ** if the current N values are new.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
413 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
414 ** A jump to addrRepeat is made and the N+1 values are popped from the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
415 ** stack if the top N elements are not distinct.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
416 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
417 static void codeDistinct(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
418 Vdbe *v, /* Generate code into this VM */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
419 int iTab, /* A sorting index used to test for distinctness */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
420 int addrRepeat, /* Jump to here if not distinct */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
421 int N /* The top N elements of the stack must be distinct */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
422 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
423 sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
424 sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
425 sqlite3VdbeAddOp(v, OP_Pop, N+1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
426 sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
427 VdbeComment((v, "# skip indistinct records"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
428 sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
429 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
430
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
431
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
432 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
433 ** This routine generates the code for the inside of the inner loop
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
434 ** of a SELECT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
435 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
436 ** If srcTab and nColumn are both zero, then the pEList expressions
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
437 ** are evaluated in order to get the data for this row. If nColumn>0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
438 ** then data is pulled from srcTab and pEList is used only to get the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
439 ** datatypes for each column.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
440 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
441 static int selectInnerLoop(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
442 Parse *pParse, /* The parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
443 Select *p, /* The complete select statement being coded */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
444 ExprList *pEList, /* List of values being extracted */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
445 int srcTab, /* Pull data from this table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
446 int nColumn, /* Number of columns in the source table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
447 ExprList *pOrderBy, /* If not NULL, sort results using this key */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
448 int distinct, /* If >=0, make sure results are distinct */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
449 int eDest, /* How to dispose of the results */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
450 int iParm, /* An argument to the disposal method */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
451 int iContinue, /* Jump here to continue with next row */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
452 int iBreak, /* Jump here to break out of the inner loop */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
453 char *aff /* affinity string if eDest is SRT_Union */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
454 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
455 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
456 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
457 int hasDistinct; /* True if the DISTINCT keyword is present */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
458
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
459 if( v==0 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
460 assert( pEList!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
461
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
462 /* If there was a LIMIT clause on the SELECT statement, then do the check
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
463 ** to see if this row should be output.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
464 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
465 hasDistinct = distinct>=0 && pEList->nExpr>0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
466 if( pOrderBy==0 && !hasDistinct ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
467 codeOffset(v, p, iContinue, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
468 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
469
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
470 /* Pull the requested columns.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
471 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
472 if( nColumn>0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
473 for(i=0; i<nColumn; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
474 sqlite3VdbeAddOp(v, OP_Column, srcTab, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
475 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
476 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
477 nColumn = pEList->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
478 sqlite3ExprCodeExprList(pParse, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
479 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
480
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
481 /* If the DISTINCT keyword was present on the SELECT statement
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
482 ** and this row has been seen before, then do not make this row
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
483 ** part of the result.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
484 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
485 if( hasDistinct ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
486 assert( pEList!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
487 assert( pEList->nExpr==nColumn );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
488 codeDistinct(v, distinct, iContinue, nColumn);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
489 if( pOrderBy==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
490 codeOffset(v, p, iContinue, nColumn);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
491 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
492 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
493
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
494 switch( eDest ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
495 /* In this mode, write each query result to the key of the temporary
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
496 ** table iParm.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
497 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
498 #ifndef SQLITE_OMIT_COMPOUND_SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
499 case SRT_Union: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
500 sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
501 if( aff ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
502 sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
503 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
504 sqlite3VdbeAddOp(v, OP_IdxInsert, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
505 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
506 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
507
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
508 /* Construct a record from the query result, but instead of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
509 ** saving that record, use it as a key to delete elements from
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
510 ** the temporary table iParm.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
511 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
512 case SRT_Except: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
513 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
514 addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
515 sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
516 sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
517 sqlite3VdbeAddOp(v, OP_Delete, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
518 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
519 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
520 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
521
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
522 /* Store the result as data using a unique key.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
523 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
524 case SRT_Table:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
525 case SRT_VirtualTab: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
526 sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
527 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
528 pushOntoSorter(pParse, pOrderBy, p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
529 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
530 sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
531 sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
532 sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
533 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
534 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
535 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
536
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
537 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
538 /* If we are creating a set for an "expr IN (SELECT ...)" construct,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
539 ** then there should be a single item on the stack. Write this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
540 ** item into the set table with bogus data.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
541 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
542 case SRT_Set: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
543 int addr1 = sqlite3VdbeCurrentAddr(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
544 int addr2;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
545
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
546 assert( nColumn==1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
547 sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
548 sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
549 addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
550 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
551 /* At first glance you would think we could optimize out the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
552 ** ORDER BY in this case since the order of entries in the set
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
553 ** does not matter. But there might be a LIMIT clause, in which
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
554 ** case the order does matter */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
555 pushOntoSorter(pParse, pOrderBy, p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
556 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
557 char affinity = (iParm>>16)&0xFF;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
558 affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
559 sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
560 sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
561 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
562 sqlite3VdbeJumpHere(v, addr2);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
563 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
564 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
565
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
566 /* If any row exist in the result set, record that fact and abort.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
567 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
568 case SRT_Exists: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
569 sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
570 sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
571 /* The LIMIT clause will terminate the loop for us */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
572 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
573 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
574
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
575 /* If this is a scalar select that is part of an expression, then
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
576 ** store the results in the appropriate memory cell and break out
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
577 ** of the scan loop.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
578 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
579 case SRT_Mem: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
580 assert( nColumn==1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
581 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
582 pushOntoSorter(pParse, pOrderBy, p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
583 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
584 sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
585 /* The LIMIT clause will jump out of the loop for us */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
586 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
587 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
588 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
589 #endif /* #ifndef SQLITE_OMIT_SUBQUERY */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
590
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
591 /* Send the data to the callback function or to a subroutine. In the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
592 ** case of a subroutine, the subroutine itself is responsible for
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
593 ** popping the data from the stack.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
594 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
595 case SRT_Subroutine:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
596 case SRT_Callback: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
597 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
598 sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
599 pushOntoSorter(pParse, pOrderBy, p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
600 }else if( eDest==SRT_Subroutine ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
601 sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
602 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
603 sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
604 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
605 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
606 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
607
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
608 #if !defined(SQLITE_OMIT_TRIGGER)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
609 /* Discard the results. This is used for SELECT statements inside
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
610 ** the body of a TRIGGER. The purpose of such selects is to call
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
611 ** user-defined functions that have side effects. We do not care
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
612 ** about the actual results of the select.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
613 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
614 default: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
615 assert( eDest==SRT_Discard );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
616 sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
617 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
618 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
619 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
620 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
621
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
622 /* Jump to the end of the loop if the LIMIT is reached.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
623 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
624 if( p->iLimit>=0 && pOrderBy==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
625 sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
626 sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
627 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
628 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
629 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
630
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
631 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
632 ** Given an expression list, generate a KeyInfo structure that records
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
633 ** the collating sequence for each expression in that expression list.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
634 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
635 ** If the ExprList is an ORDER BY or GROUP BY clause then the resulting
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
636 ** KeyInfo structure is appropriate for initializing a virtual index to
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
637 ** implement that clause. If the ExprList is the result set of a SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
638 ** then the KeyInfo structure is appropriate for initializing a virtual
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
639 ** index to implement a DISTINCT test.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
640 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
641 ** Space to hold the KeyInfo structure is obtain from malloc. The calling
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
642 ** function is responsible for seeing that this structure is eventually
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
643 ** freed. Add the KeyInfo structure to the P3 field of an opcode using
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
644 ** P3_KEYINFO_HANDOFF is the usual way of dealing with this.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
645 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
646 static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
647 sqlite3 *db = pParse->db;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
648 int nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
649 KeyInfo *pInfo;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
650 struct ExprList_item *pItem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
651 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
652
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
653 nExpr = pList->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
654 pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
655 if( pInfo ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
656 pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
657 pInfo->nField = nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
658 pInfo->enc = ENC(db);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
659 for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
660 CollSeq *pColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
661 pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
662 if( !pColl ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
663 pColl = db->pDfltColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
664 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
665 pInfo->aColl[i] = pColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
666 pInfo->aSortOrder[i] = pItem->sortOrder;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
667 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
668 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
669 return pInfo;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
670 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
671
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
672
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
673 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
674 ** If the inner loop was generated using a non-null pOrderBy argument,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
675 ** then the results were placed in a sorter. After the loop is terminated
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
676 ** we need to run the sorter and output the results. The following
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
677 ** routine generates the code needed to do that.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
678 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
679 static void generateSortTail(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
680 Parse *pParse, /* Parsing context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
681 Select *p, /* The SELECT statement */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
682 Vdbe *v, /* Generate code into this VDBE */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
683 int nColumn, /* Number of columns of data */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
684 int eDest, /* Write the sorted results here */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
685 int iParm /* Optional parameter associated with eDest */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
686 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
687 int brk = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
688 int cont = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
689 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
690 int iTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
691 int pseudoTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
692 ExprList *pOrderBy = p->pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
693
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
694 iTab = pOrderBy->iECursor;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
695 if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
696 pseudoTab = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
697 sqlite3VdbeAddOp(v, OP_OpenPseudo, pseudoTab, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
698 sqlite3VdbeAddOp(v, OP_SetNumColumns, pseudoTab, nColumn);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
699 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
700 addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
701 codeOffset(v, p, cont, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
702 if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
703 sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
704 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
705 sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
706 switch( eDest ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
707 case SRT_Table:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
708 case SRT_VirtualTab: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
709 sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
710 sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
711 sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
712 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
713 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
714 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
715 case SRT_Set: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
716 assert( nColumn==1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
717 sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
718 sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
719 sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
720 sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
721 sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
722 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
723 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
724 case SRT_Mem: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
725 assert( nColumn==1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
726 sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
727 /* The LIMIT clause will terminate the loop for us */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
728 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
729 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
730 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
731 case SRT_Callback:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
732 case SRT_Subroutine: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
733 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
734 sqlite3VdbeAddOp(v, OP_Insert, pseudoTab, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
735 for(i=0; i<nColumn; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
736 sqlite3VdbeAddOp(v, OP_Column, pseudoTab, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
737 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
738 if( eDest==SRT_Callback ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
739 sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
740 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
741 sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
742 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
743 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
744 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
745 default: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
746 /* Do nothing */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
747 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
748 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
749 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
750
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
751 /* Jump to the end of the loop when the LIMIT is reached
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
752 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
753 if( p->iLimit>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
754 sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
755 sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
756 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
757
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
758 /* The bottom of the loop
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
759 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
760 sqlite3VdbeResolveLabel(v, cont);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
761 sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
762 sqlite3VdbeResolveLabel(v, brk);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
763 if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
764 sqlite3VdbeAddOp(v, OP_Close, pseudoTab, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
765 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
766
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
767 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
768
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
769 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
770 ** Return a pointer to a string containing the 'declaration type' of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
771 ** expression pExpr. The string may be treated as static by the caller.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
772 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
773 ** The declaration type is the exact datatype definition extracted from the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
774 ** original CREATE TABLE statement if the expression is a column. The
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
775 ** declaration type for a ROWID field is INTEGER. Exactly when an expression
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
776 ** is considered a column can be complex in the presence of subqueries. The
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
777 ** result-set expression in all of the following SELECT statements is
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
778 ** considered a column by this function.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
779 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
780 ** SELECT col FROM tbl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
781 ** SELECT (SELECT col FROM tbl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
782 ** SELECT (SELECT col FROM tbl);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
783 ** SELECT abc FROM (SELECT col AS abc FROM tbl);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
784 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
785 ** The declaration type for any expression other than a column is NULL.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
786 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
787 static const char *columnType(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
788 NameContext *pNC,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
789 Expr *pExpr,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
790 const char **pzOriginDb,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
791 const char **pzOriginTab,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
792 const char **pzOriginCol
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
793 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
794 char const *zType = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
795 char const *zOriginDb = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
796 char const *zOriginTab = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
797 char const *zOriginCol = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
798 int j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
799 if( pExpr==0 || pNC->pSrcList==0 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
800
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
801 /* The TK_AS operator can only occur in ORDER BY, GROUP BY, HAVING,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
802 ** and LIMIT clauses. But pExpr originates in the result set of a
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
803 ** SELECT. So pExpr can never contain an AS operator.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
804 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
805 assert( pExpr->op!=TK_AS );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
806
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
807 switch( pExpr->op ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
808 case TK_AGG_COLUMN:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
809 case TK_COLUMN: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
810 /* The expression is a column. Locate the table the column is being
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
811 ** extracted from in NameContext.pSrcList. This table may be real
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
812 ** database table or a subquery.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
813 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
814 Table *pTab = 0; /* Table structure column is extracted from */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
815 Select *pS = 0; /* Select the column is extracted from */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
816 int iCol = pExpr->iColumn; /* Index of column in pTab */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
817 while( pNC && !pTab ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
818 SrcList *pTabList = pNC->pSrcList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
819 for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
820 if( j<pTabList->nSrc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
821 pTab = pTabList->a[j].pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
822 pS = pTabList->a[j].pSelect;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
823 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
824 pNC = pNC->pNext;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
825 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
826 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
827
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
828 if( pTab==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
829 /* FIX ME:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
830 ** This can occurs if you have something like "SELECT new.x;" inside
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
831 ** a trigger. In other words, if you reference the special "new"
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
832 ** table in the result set of a select. We do not have a good way
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
833 ** to find the actual table type, so call it "TEXT". This is really
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
834 ** something of a bug, but I do not know how to fix it.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
835 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
836 ** This code does not produce the correct answer - it just prevents
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
837 ** a segfault. See ticket #1229.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
838 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
839 zType = "TEXT";
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
840 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
841 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
842
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
843 assert( pTab );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
844 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
845 if( pS ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
846 /* The "table" is actually a sub-select or a view in the FROM clause
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
847 ** of the SELECT statement. Return the declaration type and origin
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
848 ** data for the result-set column of the sub-select.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
849 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
850 if( iCol>=0 && iCol<pS->pEList->nExpr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
851 /* If iCol is less than zero, then the expression requests the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
852 ** rowid of the sub-select or view. This expression is legal (see
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
853 ** test case misc2.2.2) - it always evaluates to NULL.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
854 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
855 NameContext sNC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
856 Expr *p = pS->pEList->a[iCol].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
857 sNC.pSrcList = pS->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
858 sNC.pNext = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
859 sNC.pParse = pNC->pParse;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
860 zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
861 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
862 }else
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
863 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
864 if( pTab->pSchema ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
865 /* A real table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
866 assert( !pS );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
867 if( iCol<0 ) iCol = pTab->iPKey;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
868 assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
869 if( iCol<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
870 zType = "INTEGER";
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
871 zOriginCol = "rowid";
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
872 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
873 zType = pTab->aCol[iCol].zType;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
874 zOriginCol = pTab->aCol[iCol].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
875 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
876 zOriginTab = pTab->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
877 if( pNC->pParse ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
878 int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
879 zOriginDb = pNC->pParse->db->aDb[iDb].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
880 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
881 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
882 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
883 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
884 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
885 case TK_SELECT: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
886 /* The expression is a sub-select. Return the declaration type and
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
887 ** origin info for the single column in the result set of the SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
888 ** statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
889 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
890 NameContext sNC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
891 Select *pS = pExpr->pSelect;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
892 Expr *p = pS->pEList->a[0].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
893 sNC.pSrcList = pS->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
894 sNC.pNext = pNC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
895 sNC.pParse = pNC->pParse;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
896 zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
897 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
898 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
899 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
900 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
901
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
902 if( pzOriginDb ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
903 assert( pzOriginTab && pzOriginCol );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
904 *pzOriginDb = zOriginDb;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
905 *pzOriginTab = zOriginTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
906 *pzOriginCol = zOriginCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
907 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
908 return zType;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
909 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
910
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
911 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
912 ** Generate code that will tell the VDBE the declaration types of columns
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
913 ** in the result set.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
914 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
915 static void generateColumnTypes(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
916 Parse *pParse, /* Parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
917 SrcList *pTabList, /* List of tables */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
918 ExprList *pEList /* Expressions defining the result set */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
919 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
920 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
921 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
922 NameContext sNC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
923 sNC.pSrcList = pTabList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
924 sNC.pParse = pParse;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
925 for(i=0; i<pEList->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
926 Expr *p = pEList->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
927 const char *zOrigDb = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
928 const char *zOrigTab = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
929 const char *zOrigCol = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
930 const char *zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
931
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
932 /* The vdbe must make it's own copy of the column-type and other
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
933 ** column specific strings, in case the schema is reset before this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
934 ** virtual machine is deleted.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
935 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
936 sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, P3_TRANSIENT);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
937 sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, P3_TRANSIENT);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
938 sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, P3_TRANSIENT);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
939 sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, P3_TRANSIENT);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
940 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
941 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
942
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
943 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
944 ** Generate code that will tell the VDBE the names of columns
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
945 ** in the result set. This information is used to provide the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
946 ** azCol[] values in the callback.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
947 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
948 static void generateColumnNames(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
949 Parse *pParse, /* Parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
950 SrcList *pTabList, /* List of tables */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
951 ExprList *pEList /* Expressions defining the result set */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
952 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
953 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
954 int i, j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
955 sqlite3 *db = pParse->db;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
956 int fullNames, shortNames;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
957
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
958 #ifndef SQLITE_OMIT_EXPLAIN
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
959 /* If this is an EXPLAIN, skip this step */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
960 if( pParse->explain ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
961 return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
962 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
963 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
964
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
965 assert( v!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
966 if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
967 pParse->colNamesSet = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
968 fullNames = (db->flags & SQLITE_FullColNames)!=0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
969 shortNames = (db->flags & SQLITE_ShortColNames)!=0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
970 sqlite3VdbeSetNumCols(v, pEList->nExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
971 for(i=0; i<pEList->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
972 Expr *p;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
973 p = pEList->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
974 if( p==0 ) continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
975 if( pEList->a[i].zName ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
976 char *zName = pEList->a[i].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
977 sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, strlen(zName));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
978 continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
979 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
980 if( p->op==TK_COLUMN && pTabList ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
981 Table *pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
982 char *zCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
983 int iCol = p->iColumn;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
984 for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){}
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
985 assert( j<pTabList->nSrc );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
986 pTab = pTabList->a[j].pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
987 if( iCol<0 ) iCol = pTab->iPKey;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
988 assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
989 if( iCol<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
990 zCol = "rowid";
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
991 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
992 zCol = pTab->aCol[iCol].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
993 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
994 if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
995 sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
996 }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
997 char *zName = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
998 char *zTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
999
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1000 zTab = pTabList->a[j].zAlias;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1001 if( fullNames || zTab==0 ) zTab = pTab->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1002 sqlite3SetString(&zName, zTab, ".", zCol, (char*)0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1003 sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1004 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1005 sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1006 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1007 }else if( p->span.z && p->span.z[0] ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1008 sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1009 /* sqlite3VdbeCompressSpace(v, addr); */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1010 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1011 char zName[30];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1012 assert( p->op!=TK_COLUMN || pTabList==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1013 sprintf(zName, "column%d", i+1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1014 sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1015 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1016 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1017 generateColumnTypes(pParse, pTabList, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1018 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1019
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1020 #ifndef SQLITE_OMIT_COMPOUND_SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1021 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1022 ** Name of the connection operator, used for error messages.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1023 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1024 static const char *selectOpName(int id){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1025 char *z;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1026 switch( id ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1027 case TK_ALL: z = "UNION ALL"; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1028 case TK_INTERSECT: z = "INTERSECT"; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1029 case TK_EXCEPT: z = "EXCEPT"; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1030 default: z = "UNION"; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1031 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1032 return z;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1033 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1034 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1035
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1036 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1037 ** Forward declaration
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1038 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1039 static int prepSelectStmt(Parse*, Select*);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1040
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1041 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1042 ** Given a SELECT statement, generate a Table structure that describes
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1043 ** the result set of that SELECT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1044 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1045 Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1046 Table *pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1047 int i, j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1048 ExprList *pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1049 Column *aCol, *pCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1050
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1051 while( pSelect->pPrior ) pSelect = pSelect->pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1052 if( prepSelectStmt(pParse, pSelect) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1053 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1054 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1055 if( sqlite3SelectResolve(pParse, pSelect, 0) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1056 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1057 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1058 pTab = sqliteMalloc( sizeof(Table) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1059 if( pTab==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1060 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1061 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1062 pTab->nRef = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1063 pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1064 pEList = pSelect->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1065 pTab->nCol = pEList->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1066 assert( pTab->nCol>0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1067 pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1068 for(i=0, pCol=aCol; i<pTab->nCol; i++, pCol++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1069 Expr *p, *pR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1070 char *zType;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1071 char *zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1072 char *zBasename;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1073 CollSeq *pColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1074 int cnt;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1075 NameContext sNC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1076
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1077 /* Get an appropriate name for the column
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1078 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1079 p = pEList->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1080 assert( p->pRight==0 || p->pRight->token.z==0 || p->pRight->token.z[0]!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1081 if( (zName = pEList->a[i].zName)!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1082 /* If the column contains an "AS <name>" phrase, use <name> as the name */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1083 zName = sqliteStrDup(zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1084 }else if( p->op==TK_DOT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1085 && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1086 /* For columns of the from A.B use B as the name */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1087 zName = sqlite3MPrintf("%T", &pR->token);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1088 }else if( p->span.z && p->span.z[0] ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1089 /* Use the original text of the column expression as its name */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1090 zName = sqlite3MPrintf("%T", &p->span);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1091 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1092 /* If all else fails, make up a name */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1093 zName = sqlite3MPrintf("column%d", i+1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1094 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1095 sqlite3Dequote(zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1096 if( sqlite3MallocFailed() ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1097 sqliteFree(zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1098 sqlite3DeleteTable(0, pTab);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1099 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1100 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1101
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1102 /* Make sure the column name is unique. If the name is not unique,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1103 ** append a integer to the name so that it becomes unique.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1104 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1105 zBasename = zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1106 for(j=cnt=0; j<i; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1107 if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1108 zName = sqlite3MPrintf("%s:%d", zBasename, ++cnt);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1109 j = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1110 if( zName==0 ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1111 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1112 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1113 if( zBasename!=zName ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1114 sqliteFree(zBasename);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1115 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1116 pCol->zName = zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1117
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1118 /* Get the typename, type affinity, and collating sequence for the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1119 ** column.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1120 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1121 memset(&sNC, 0, sizeof(sNC));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1122 sNC.pSrcList = pSelect->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1123 zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1124 pCol->zType = zType;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1125 pCol->affinity = sqlite3ExprAffinity(p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1126 pColl = sqlite3ExprCollSeq(pParse, p);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1127 if( pColl ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1128 pCol->zColl = sqliteStrDup(pColl->zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1129 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1130 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1131 pTab->iPKey = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1132 return pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1133 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1134
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1135 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1136 ** Prepare a SELECT statement for processing by doing the following
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1137 ** things:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1138 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1139 ** (1) Make sure VDBE cursor numbers have been assigned to every
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1140 ** element of the FROM clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1141 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1142 ** (2) Fill in the pTabList->a[].pTab fields in the SrcList that
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1143 ** defines FROM clause. When views appear in the FROM clause,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1144 ** fill pTabList->a[].pSelect with a copy of the SELECT statement
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1145 ** that implements the view. A copy is made of the view's SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1146 ** statement so that we can freely modify or delete that statement
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1147 ** without worrying about messing up the presistent representation
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1148 ** of the view.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1149 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1150 ** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1151 ** on joins and the ON and USING clause of joins.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1152 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1153 ** (4) Scan the list of columns in the result set (pEList) looking
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1154 ** for instances of the "*" operator or the TABLE.* operator.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1155 ** If found, expand each "*" to be every column in every table
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1156 ** and TABLE.* to be every column in TABLE.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1157 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1158 ** Return 0 on success. If there are problems, leave an error message
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1159 ** in pParse and return non-zero.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1160 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1161 static int prepSelectStmt(Parse *pParse, Select *p){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1162 int i, j, k, rc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1163 SrcList *pTabList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1164 ExprList *pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1165 struct SrcList_item *pFrom;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1166
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1167 if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1168 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1169 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1170 pTabList = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1171 pEList = p->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1172
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1173 /* Make sure cursor numbers have been assigned to all entries in
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1174 ** the FROM clause of the SELECT statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1175 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1176 sqlite3SrcListAssignCursors(pParse, p->pSrc);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1177
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1178 /* Look up every table named in the FROM clause of the select. If
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1179 ** an entry of the FROM clause is a subquery instead of a table or view,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1180 ** then create a transient table structure to describe the subquery.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1181 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1182 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1183 Table *pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1184 if( pFrom->pTab!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1185 /* This statement has already been prepared. There is no need
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1186 ** to go further. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1187 assert( i==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1188 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1189 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1190 if( pFrom->zName==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1191 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1192 /* A sub-query in the FROM clause of a SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1193 assert( pFrom->pSelect!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1194 if( pFrom->zAlias==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1195 pFrom->zAlias =
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1196 sqlite3MPrintf("sqlite_subquery_%p_", (void*)pFrom->pSelect);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1197 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1198 assert( pFrom->pTab==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1199 pFrom->pTab = pTab =
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1200 sqlite3ResultSetOfSelect(pParse, pFrom->zAlias, pFrom->pSelect);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1201 if( pTab==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1202 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1203 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1204 /* The isTransient flag indicates that the Table structure has been
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1205 ** dynamically allocated and may be freed at any time. In other words,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1206 ** pTab is not pointing to a persistent table structure that defines
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1207 ** part of the schema. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1208 pTab->isTransient = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1209 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1210 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1211 /* An ordinary table or view name in the FROM clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1212 assert( pFrom->pTab==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1213 pFrom->pTab = pTab =
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1214 sqlite3LocateTable(pParse,pFrom->zName,pFrom->zDatabase);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1215 if( pTab==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1216 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1217 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1218 pTab->nRef++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1219 #ifndef SQLITE_OMIT_VIEW
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1220 if( pTab->pSelect ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1221 /* We reach here if the named table is a really a view */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1222 if( sqlite3ViewGetColumnNames(pParse, pTab) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1223 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1224 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1225 /* If pFrom->pSelect!=0 it means we are dealing with a
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1226 ** view within a view. The SELECT structure has already been
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1227 ** copied by the outer view so we can skip the copy step here
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1228 ** in the inner view.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1229 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1230 if( pFrom->pSelect==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1231 pFrom->pSelect = sqlite3SelectDup(pTab->pSelect);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1232 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1233 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1234 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1235 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1236 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1237
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1238 /* Process NATURAL keywords, and ON and USING clauses of joins.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1239 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1240 if( sqliteProcessJoin(pParse, p) ) return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1241
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1242 /* For every "*" that occurs in the column list, insert the names of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1243 ** all columns in all tables. And for every TABLE.* insert the names
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1244 ** of all columns in TABLE. The parser inserted a special expression
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1245 ** with the TK_ALL operator for each "*" that it found in the column list.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1246 ** The following code just has to locate the TK_ALL expressions and expand
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1247 ** each one to the list of all columns in all tables.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1248 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1249 ** The first loop just checks to see if there are any "*" operators
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1250 ** that need expanding.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1251 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1252 for(k=0; k<pEList->nExpr; k++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1253 Expr *pE = pEList->a[k].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1254 if( pE->op==TK_ALL ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1255 if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1256 && pE->pLeft && pE->pLeft->op==TK_ID ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1257 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1258 rc = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1259 if( k<pEList->nExpr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1260 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1261 ** If we get here it means the result set contains one or more "*"
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1262 ** operators that need to be expanded. Loop through each expression
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1263 ** in the result set and expand them one by one.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1264 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1265 struct ExprList_item *a = pEList->a;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1266 ExprList *pNew = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1267 int flags = pParse->db->flags;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1268 int longNames = (flags & SQLITE_FullColNames)!=0 &&
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1269 (flags & SQLITE_ShortColNames)==0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1270
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1271 for(k=0; k<pEList->nExpr; k++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1272 Expr *pE = a[k].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1273 if( pE->op!=TK_ALL &&
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1274 (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1275 /* This particular expression does not need to be expanded.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1276 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1277 pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1278 if( pNew ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1279 pNew->a[pNew->nExpr-1].zName = a[k].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1280 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1281 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1282 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1283 a[k].pExpr = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1284 a[k].zName = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1285 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1286 /* This expression is a "*" or a "TABLE.*" and needs to be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1287 ** expanded. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1288 int tableSeen = 0; /* Set to 1 when TABLE matches */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1289 char *zTName; /* text of name of TABLE */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1290 if( pE->op==TK_DOT && pE->pLeft ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1291 zTName = sqlite3NameFromToken(&pE->pLeft->token);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1292 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1293 zTName = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1294 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1295 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1296 Table *pTab = pFrom->pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1297 char *zTabName = pFrom->zAlias;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1298 if( zTabName==0 || zTabName[0]==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1299 zTabName = pTab->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1300 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1301 if( zTName && (zTabName==0 || zTabName[0]==0 ||
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1302 sqlite3StrICmp(zTName, zTabName)!=0) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1303 continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1304 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1305 tableSeen = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1306 for(j=0; j<pTab->nCol; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1307 Expr *pExpr, *pRight;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1308 char *zName = pTab->aCol[j].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1309
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1310 if( i>0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1311 struct SrcList_item *pLeft = &pTabList->a[i-1];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1312 if( (pLeft->jointype & JT_NATURAL)!=0 &&
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1313 columnIndex(pLeft->pTab, zName)>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1314 /* In a NATURAL join, omit the join columns from the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1315 ** table on the right */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1316 continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1317 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1318 if( sqlite3IdListIndex(pLeft->pUsing, zName)>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1319 /* In a join with a USING clause, omit columns in the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1320 ** using clause from the table on the right. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1321 continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1322 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1323 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1324 pRight = sqlite3Expr(TK_ID, 0, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1325 if( pRight==0 ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1326 setToken(&pRight->token, zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1327 if( zTabName && (longNames || pTabList->nSrc>1) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1328 Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1329 pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1330 if( pExpr==0 ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1331 setToken(&pLeft->token, zTabName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1332 setToken(&pExpr->span, sqlite3MPrintf("%s.%s", zTabName, zName));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1333 pExpr->span.dyn = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1334 pExpr->token.z = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1335 pExpr->token.n = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1336 pExpr->token.dyn = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1337 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1338 pExpr = pRight;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1339 pExpr->span = pExpr->token;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1340 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1341 if( longNames ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1342 pNew = sqlite3ExprListAppend(pNew, pExpr, &pExpr->span);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1343 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1344 pNew = sqlite3ExprListAppend(pNew, pExpr, &pRight->token);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1345 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1346 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1347 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1348 if( !tableSeen ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1349 if( zTName ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1350 sqlite3ErrorMsg(pParse, "no such table: %s", zTName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1351 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1352 sqlite3ErrorMsg(pParse, "no tables specified");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1353 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1354 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1355 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1356 sqliteFree(zTName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1357 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1358 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1359 sqlite3ExprListDelete(pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1360 p->pEList = pNew;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1361 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1362 return rc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1363 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1364
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1365 #ifndef SQLITE_OMIT_COMPOUND_SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1366 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1367 ** This routine associates entries in an ORDER BY expression list with
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1368 ** columns in a result. For each ORDER BY expression, the opcode of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1369 ** the top-level node is changed to TK_COLUMN and the iColumn value of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1370 ** the top-level node is filled in with column number and the iTable
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1371 ** value of the top-level node is filled with iTable parameter.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1372 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1373 ** If there are prior SELECT clauses, they are processed first. A match
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1374 ** in an earlier SELECT takes precedence over a later SELECT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1375 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1376 ** Any entry that does not match is flagged as an error. The number
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1377 ** of errors is returned.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1378 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1379 static int matchOrderbyToColumn(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1380 Parse *pParse, /* A place to leave error messages */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1381 Select *pSelect, /* Match to result columns of this SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1382 ExprList *pOrderBy, /* The ORDER BY values to match against columns */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1383 int iTable, /* Insert this value in iTable */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1384 int mustComplete /* If TRUE all ORDER BYs must match */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1385 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1386 int nErr = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1387 int i, j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1388 ExprList *pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1389
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1390 if( pSelect==0 || pOrderBy==0 ) return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1391 if( mustComplete ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1392 for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1393 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1394 if( prepSelectStmt(pParse, pSelect) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1395 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1396 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1397 if( pSelect->pPrior ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1398 if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1399 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1400 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1401 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1402 pEList = pSelect->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1403 for(i=0; i<pOrderBy->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1404 Expr *pE = pOrderBy->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1405 int iCol = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1406 if( pOrderBy->a[i].done ) continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1407 if( sqlite3ExprIsInteger(pE, &iCol) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1408 if( iCol<=0 || iCol>pEList->nExpr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1409 sqlite3ErrorMsg(pParse,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1410 "ORDER BY position %d should be between 1 and %d",
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1411 iCol, pEList->nExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1412 nErr++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1413 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1414 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1415 if( !mustComplete ) continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1416 iCol--;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1417 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1418 for(j=0; iCol<0 && j<pEList->nExpr; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1419 if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1420 char *zName, *zLabel;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1421 zName = pEList->a[j].zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1422 zLabel = sqlite3NameFromToken(&pE->token);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1423 assert( zLabel!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1424 if( sqlite3StrICmp(zName, zLabel)==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1425 iCol = j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1426 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1427 sqliteFree(zLabel);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1428 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1429 if( iCol<0 && sqlite3ExprCompare(pE, pEList->a[j].pExpr) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1430 iCol = j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1431 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1432 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1433 if( iCol>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1434 pE->op = TK_COLUMN;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1435 pE->iColumn = iCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1436 pE->iTable = iTable;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1437 pE->iAgg = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1438 pOrderBy->a[i].done = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1439 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1440 if( iCol<0 && mustComplete ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1441 sqlite3ErrorMsg(pParse,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1442 "ORDER BY term number %d does not match any result column", i+1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1443 nErr++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1444 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1445 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1446 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1447 return nErr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1448 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1449 #endif /* #ifndef SQLITE_OMIT_COMPOUND_SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1450
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1451 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1452 ** Get a VDBE for the given parser context. Create a new one if necessary.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1453 ** If an error occurs, return NULL and leave a message in pParse.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1454 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1455 Vdbe *sqlite3GetVdbe(Parse *pParse){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1456 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1457 if( v==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1458 v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1459 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1460 return v;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1461 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1462
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1463
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1464 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1465 ** Compute the iLimit and iOffset fields of the SELECT based on the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1466 ** pLimit and pOffset expressions. pLimit and pOffset hold the expressions
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1467 ** that appear in the original SQL statement after the LIMIT and OFFSET
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1468 ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1469 ** are the integer memory register numbers for counters used to compute
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1470 ** the limit and offset. If there is no limit and/or offset, then
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1471 ** iLimit and iOffset are negative.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1472 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1473 ** This routine changes the values of iLimit and iOffset only if
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1474 ** a limit or offset is defined by pLimit and pOffset. iLimit and
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1475 ** iOffset should have been preset to appropriate default values
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1476 ** (usually but not always -1) prior to calling this routine.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1477 ** Only if pLimit!=0 or pOffset!=0 do the limit registers get
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1478 ** redefined. The UNION ALL operator uses this property to force
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1479 ** the reuse of the same limit and offset registers across multiple
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1480 ** SELECT statements.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1481 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1482 static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1483 Vdbe *v = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1484 int iLimit = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1485 int iOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1486 int addr1, addr2;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1487
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1488 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1489 ** "LIMIT -1" always shows all rows. There is some
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1490 ** contraversy about what the correct behavior should be.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1491 ** The current implementation interprets "LIMIT 0" to mean
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1492 ** no rows.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1493 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1494 if( p->pLimit ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1495 p->iLimit = iLimit = pParse->nMem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1496 pParse->nMem += 2;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1497 v = sqlite3GetVdbe(pParse);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1498 if( v==0 ) return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1499 sqlite3ExprCode(pParse, p->pLimit);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1500 sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1501 sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1502 VdbeComment((v, "# LIMIT counter"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1503 sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1504 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1505 if( p->pOffset ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1506 p->iOffset = iOffset = pParse->nMem++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1507 v = sqlite3GetVdbe(pParse);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1508 if( v==0 ) return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1509 sqlite3ExprCode(pParse, p->pOffset);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1510 sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1511 sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1512 VdbeComment((v, "# OFFSET counter"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1513 addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1514 sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1515 sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1516 sqlite3VdbeJumpHere(v, addr1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1517 if( p->pLimit ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1518 sqlite3VdbeAddOp(v, OP_Add, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1519 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1520 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1521 if( p->pLimit ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1522 addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1523 sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1524 sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1525 addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1526 sqlite3VdbeJumpHere(v, addr1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1527 sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1528 VdbeComment((v, "# LIMIT+OFFSET"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1529 sqlite3VdbeJumpHere(v, addr2);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1530 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1531 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1532
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1533 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1534 ** Allocate a virtual index to use for sorting.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1535 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1536 static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1537 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1538 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1539 assert( pOrderBy->iECursor==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1540 pOrderBy->iECursor = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1541 addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1542 pOrderBy->iECursor, pOrderBy->nExpr+1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1543 assert( p->addrOpenVirt[2] == -1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1544 p->addrOpenVirt[2] = addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1545 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1546 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1547
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1548 #ifndef SQLITE_OMIT_COMPOUND_SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1549 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1550 ** Return the appropriate collating sequence for the iCol-th column of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1551 ** the result set for the compound-select statement "p". Return NULL if
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1552 ** the column has no default collating sequence.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1553 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1554 ** The collating sequence for the compound select is taken from the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1555 ** left-most term of the select that has a collating sequence.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1556 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1557 static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1558 CollSeq *pRet;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1559 if( p->pPrior ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1560 pRet = multiSelectCollSeq(pParse, p->pPrior, iCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1561 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1562 pRet = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1563 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1564 if( pRet==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1565 pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1566 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1567 return pRet;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1568 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1569 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1570
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1571 #ifndef SQLITE_OMIT_COMPOUND_SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1572 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1573 ** This routine is called to process a query that is really the union
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1574 ** or intersection of two or more separate queries.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1575 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1576 ** "p" points to the right-most of the two queries. the query on the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1577 ** left is p->pPrior. The left query could also be a compound query
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1578 ** in which case this routine will be called recursively.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1579 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1580 ** The results of the total query are to be written into a destination
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1581 ** of type eDest with parameter iParm.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1582 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1583 ** Example 1: Consider a three-way compound SQL statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1584 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1585 ** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1586 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1587 ** This statement is parsed up as follows:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1588 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1589 ** SELECT c FROM t3
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1590 ** |
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1591 ** `-----> SELECT b FROM t2
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1592 ** |
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1593 ** `------> SELECT a FROM t1
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1594 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1595 ** The arrows in the diagram above represent the Select.pPrior pointer.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1596 ** So if this routine is called with p equal to the t3 query, then
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1597 ** pPrior will be the t2 query. p->op will be TK_UNION in this case.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1598 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1599 ** Notice that because of the way SQLite parses compound SELECTs, the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1600 ** individual selects always group from left to right.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1601 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1602 static int multiSelect(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1603 Parse *pParse, /* Parsing context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1604 Select *p, /* The right-most of SELECTs to be coded */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1605 int eDest, /* \___ Store query results as specified */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1606 int iParm, /* / by these two parameters. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1607 char *aff /* If eDest is SRT_Union, the affinity string */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1608 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1609 int rc = SQLITE_OK; /* Success code from a subroutine */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1610 Select *pPrior; /* Another SELECT immediately to our left */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1611 Vdbe *v; /* Generate code to this VDBE */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1612 int nCol; /* Number of columns in the result set */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1613 ExprList *pOrderBy; /* The ORDER BY clause on p */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1614 int aSetP2[2]; /* Set P2 value of these op to number of columns */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1615 int nSetP2 = 0; /* Number of slots in aSetP2[] used */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1616
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1617 /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1618 ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1619 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1620 if( p==0 || p->pPrior==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1621 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1622 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1623 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1624 pPrior = p->pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1625 assert( pPrior->pRightmost!=pPrior );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1626 assert( pPrior->pRightmost==p->pRightmost );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1627 if( pPrior->pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1628 sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1629 selectOpName(p->op));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1630 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1631 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1632 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1633 if( pPrior->pLimit ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1634 sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1635 selectOpName(p->op));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1636 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1637 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1638 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1639
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1640 /* Make sure we have a valid query engine. If not, create a new one.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1641 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1642 v = sqlite3GetVdbe(pParse);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1643 if( v==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1644 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1645 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1646 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1647
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1648 /* Create the destination temporary table if necessary
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1649 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1650 if( eDest==SRT_VirtualTab ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1651 assert( p->pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1652 assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1653 aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1654 eDest = SRT_Table;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1655 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1656
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1657 /* Generate code for the left and right SELECT statements.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1658 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1659 pOrderBy = p->pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1660 switch( p->op ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1661 case TK_ALL: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1662 if( pOrderBy==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1663 int addr = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1664 assert( !pPrior->pLimit );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1665 pPrior->pLimit = p->pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1666 pPrior->pOffset = p->pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1667 rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1668 p->pLimit = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1669 p->pOffset = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1670 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1671 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1672 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1673 p->pPrior = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1674 p->iLimit = pPrior->iLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1675 p->iOffset = pPrior->iOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1676 if( p->iLimit>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1677 addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1678 VdbeComment((v, "# Jump ahead if LIMIT reached"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1679 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1680 rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1681 p->pPrior = pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1682 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1683 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1684 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1685 if( addr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1686 sqlite3VdbeJumpHere(v, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1687 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1688 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1689 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1690 /* For UNION ALL ... ORDER BY fall through to the next case */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1691 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1692 case TK_EXCEPT:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1693 case TK_UNION: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1694 int unionTab; /* Cursor number of the temporary table holding result */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1695 int op = 0; /* One of the SRT_ operations to apply to self */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1696 int priorOp; /* The SRT_ operation to apply to prior selects */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1697 Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1698 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1699
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1700 priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1701 if( eDest==priorOp && pOrderBy==0 && !p->pLimit && !p->pOffset ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1702 /* We can reuse a temporary table generated by a SELECT to our
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1703 ** right.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1704 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1705 unionTab = iParm;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1706 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1707 /* We will need to create our own temporary table to hold the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1708 ** intermediate results.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1709 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1710 unionTab = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1711 if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab,1) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1712 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1713 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1714 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1715 addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1716 if( priorOp==SRT_Table ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1717 assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1718 aSetP2[nSetP2++] = addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1719 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1720 assert( p->addrOpenVirt[0] == -1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1721 p->addrOpenVirt[0] = addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1722 p->pRightmost->usesVirt = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1723 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1724 createSortingIndex(pParse, p, pOrderBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1725 assert( p->pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1726 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1727
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1728 /* Code the SELECT statements to our left
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1729 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1730 assert( !pPrior->pOrderBy );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1731 rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1732 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1733 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1734 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1735
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1736 /* Code the current SELECT statement
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1737 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1738 switch( p->op ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1739 case TK_EXCEPT: op = SRT_Except; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1740 case TK_UNION: op = SRT_Union; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1741 case TK_ALL: op = SRT_Table; break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1742 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1743 p->pPrior = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1744 p->pOrderBy = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1745 p->disallowOrderBy = pOrderBy!=0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1746 pLimit = p->pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1747 p->pLimit = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1748 pOffset = p->pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1749 p->pOffset = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1750 rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1751 p->pPrior = pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1752 p->pOrderBy = pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1753 sqlite3ExprDelete(p->pLimit);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1754 p->pLimit = pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1755 p->pOffset = pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1756 p->iLimit = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1757 p->iOffset = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1758 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1759 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1760 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1761
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1762
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1763 /* Convert the data in the temporary table into whatever form
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1764 ** it is that we currently need.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1765 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1766 if( eDest!=priorOp || unionTab!=iParm ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1767 int iCont, iBreak, iStart;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1768 assert( p->pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1769 if( eDest==SRT_Callback ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1770 Select *pFirst = p;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1771 while( pFirst->pPrior ) pFirst = pFirst->pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1772 generateColumnNames(pParse, 0, pFirst->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1773 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1774 iBreak = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1775 iCont = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1776 computeLimitRegisters(pParse, p, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1777 sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1778 iStart = sqlite3VdbeCurrentAddr(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1779 rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1780 pOrderBy, -1, eDest, iParm,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1781 iCont, iBreak, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1782 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1783 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1784 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1785 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1786 sqlite3VdbeResolveLabel(v, iCont);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1787 sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1788 sqlite3VdbeResolveLabel(v, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1789 sqlite3VdbeAddOp(v, OP_Close, unionTab, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1790 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1791 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1792 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1793 case TK_INTERSECT: {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1794 int tab1, tab2;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1795 int iCont, iBreak, iStart;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1796 Expr *pLimit, *pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1797 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1798
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1799 /* INTERSECT is different from the others since it requires
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1800 ** two temporary tables. Hence it has its own case. Begin
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1801 ** by allocating the tables we will need.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1802 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1803 tab1 = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1804 tab2 = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1805 if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1806 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1807 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1808 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1809 createSortingIndex(pParse, p, pOrderBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1810
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1811 addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1812 assert( p->addrOpenVirt[0] == -1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1813 p->addrOpenVirt[0] = addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1814 p->pRightmost->usesVirt = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1815 assert( p->pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1816
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1817 /* Code the SELECTs to our left into temporary table "tab1".
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1818 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1819 rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1820 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1821 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1822 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1823
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1824 /* Code the current SELECT into temporary table "tab2"
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1825 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1826 addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1827 assert( p->addrOpenVirt[1] == -1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1828 p->addrOpenVirt[1] = addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1829 p->pPrior = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1830 pLimit = p->pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1831 p->pLimit = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1832 pOffset = p->pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1833 p->pOffset = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1834 rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1835 p->pPrior = pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1836 sqlite3ExprDelete(p->pLimit);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1837 p->pLimit = pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1838 p->pOffset = pOffset;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1839 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1840 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1841 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1842
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1843 /* Generate code to take the intersection of the two temporary
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1844 ** tables.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1845 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1846 assert( p->pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1847 if( eDest==SRT_Callback ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1848 Select *pFirst = p;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1849 while( pFirst->pPrior ) pFirst = pFirst->pPrior;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1850 generateColumnNames(pParse, 0, pFirst->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1851 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1852 iBreak = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1853 iCont = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1854 computeLimitRegisters(pParse, p, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1855 sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1856 iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1857 sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1858 rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1859 pOrderBy, -1, eDest, iParm,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1860 iCont, iBreak, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1861 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1862 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1863 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1864 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1865 sqlite3VdbeResolveLabel(v, iCont);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1866 sqlite3VdbeAddOp(v, OP_Next, tab1, iStart);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1867 sqlite3VdbeResolveLabel(v, iBreak);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1868 sqlite3VdbeAddOp(v, OP_Close, tab2, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1869 sqlite3VdbeAddOp(v, OP_Close, tab1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1870 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1871 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1872 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1873
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1874 /* Make sure all SELECTs in the statement have the same number of elements
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1875 ** in their result sets.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1876 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1877 assert( p->pEList && pPrior->pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1878 if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1879 sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1880 " do not have the same number of result columns", selectOpName(p->op));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1881 rc = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1882 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1883 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1884
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1885 /* Set the number of columns in temporary tables
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1886 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1887 nCol = p->pEList->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1888 while( nSetP2 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1889 sqlite3VdbeChangeP2(v, aSetP2[--nSetP2], nCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1890 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1891
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1892 /* Compute collating sequences used by either the ORDER BY clause or
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1893 ** by any temporary tables needed to implement the compound select.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1894 ** Attach the KeyInfo structure to all temporary tables. Invoke the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1895 ** ORDER BY processing if there is an ORDER BY clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1896 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1897 ** This section is run by the right-most SELECT statement only.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1898 ** SELECT statements to the left always skip this part. The right-most
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1899 ** SELECT might also skip this part if it has no ORDER BY clause and
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1900 ** no temp tables are required.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1901 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1902 if( pOrderBy || p->usesVirt ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1903 int i; /* Loop counter */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1904 KeyInfo *pKeyInfo; /* Collating sequence for the result set */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1905 Select *pLoop; /* For looping through SELECT statements */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1906 CollSeq **apColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1907 CollSeq **aCopy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1908
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1909 assert( p->pRightmost==p );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1910 pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*2*sizeof(CollSeq*) + nCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1911 if( !pKeyInfo ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1912 rc = SQLITE_NOMEM;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1913 goto multi_select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1914 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1915
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1916 pKeyInfo->enc = ENC(pParse->db);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1917 pKeyInfo->nField = nCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1918
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1919 for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1920 *apColl = multiSelectCollSeq(pParse, p, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1921 if( 0==*apColl ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1922 *apColl = pParse->db->pDfltColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1923 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1924 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1925
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1926 for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1927 for(i=0; i<2; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1928 int addr = pLoop->addrOpenVirt[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1929 if( addr<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1930 /* If [0] is unused then [1] is also unused. So we can
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1931 ** always safely abort as soon as the first unused slot is found */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1932 assert( pLoop->addrOpenVirt[1]<0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1933 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1934 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1935 sqlite3VdbeChangeP2(v, addr, nCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1936 sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1937 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1938 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1939
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1940 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1941 struct ExprList_item *pOTerm = pOrderBy->a;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1942 int nOrderByExpr = pOrderBy->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1943 int addr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1944 u8 *pSortOrder;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1945
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1946 aCopy = &pKeyInfo->aColl[nCol];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1947 pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1948 memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1949 apColl = pKeyInfo->aColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1950 for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1951 Expr *pExpr = pOTerm->pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1952 char *zName = pOTerm->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1953 assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1954 if( zName ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1955 *apColl = sqlite3LocateCollSeq(pParse, zName, -1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1956 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1957 *apColl = aCopy[pExpr->iColumn];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1958 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1959 *pSortOrder = pOTerm->sortOrder;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1960 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1961 assert( p->pRightmost==p );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1962 assert( p->addrOpenVirt[2]>=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1963 addr = p->addrOpenVirt[2];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1964 sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1965 pKeyInfo->nField = nOrderByExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1966 sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1967 pKeyInfo = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1968 generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1969 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1970
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1971 sqliteFree(pKeyInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1972 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1973
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1974 multi_select_end:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1975 return rc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1976 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1977 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1978
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1979 #ifndef SQLITE_OMIT_VIEW
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1980 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1981 ** Scan through the expression pExpr. Replace every reference to
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1982 ** a column in table number iTable with a copy of the iColumn-th
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1983 ** entry in pEList. (But leave references to the ROWID column
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1984 ** unchanged.)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1985 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1986 ** This routine is part of the flattening procedure. A subquery
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1987 ** whose result set is defined by pEList appears as entry in the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1988 ** FROM clause of a SELECT such that the VDBE cursor assigned to that
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1989 ** FORM clause entry is iTable. This routine make the necessary
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1990 ** changes to pExpr so that it refers directly to the source table
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1991 ** of the subquery rather the result set of the subquery.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1992 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1993 static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1994 static void substSelect(Select *, int, ExprList *); /* Forward Decl */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1995 static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1996 if( pExpr==0 ) return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1997 if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1998 if( pExpr->iColumn<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1999 pExpr->op = TK_NULL;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2000 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2001 Expr *pNew;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2002 assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2003 assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2004 pNew = pEList->a[pExpr->iColumn].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2005 assert( pNew!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2006 pExpr->op = pNew->op;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2007 assert( pExpr->pLeft==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2008 pExpr->pLeft = sqlite3ExprDup(pNew->pLeft);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2009 assert( pExpr->pRight==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2010 pExpr->pRight = sqlite3ExprDup(pNew->pRight);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2011 assert( pExpr->pList==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2012 pExpr->pList = sqlite3ExprListDup(pNew->pList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2013 pExpr->iTable = pNew->iTable;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2014 pExpr->iColumn = pNew->iColumn;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2015 pExpr->iAgg = pNew->iAgg;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2016 sqlite3TokenCopy(&pExpr->token, &pNew->token);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2017 sqlite3TokenCopy(&pExpr->span, &pNew->span);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2018 pExpr->pSelect = sqlite3SelectDup(pNew->pSelect);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2019 pExpr->flags = pNew->flags;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2020 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2021 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2022 substExpr(pExpr->pLeft, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2023 substExpr(pExpr->pRight, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2024 substSelect(pExpr->pSelect, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2025 substExprList(pExpr->pList, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2026 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2027 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2028 static void substExprList(ExprList *pList, int iTable, ExprList *pEList){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2029 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2030 if( pList==0 ) return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2031 for(i=0; i<pList->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2032 substExpr(pList->a[i].pExpr, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2033 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2034 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2035 static void substSelect(Select *p, int iTable, ExprList *pEList){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2036 if( !p ) return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2037 substExprList(p->pEList, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2038 substExprList(p->pGroupBy, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2039 substExprList(p->pOrderBy, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2040 substExpr(p->pHaving, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2041 substExpr(p->pWhere, iTable, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2042 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2043 #endif /* !defined(SQLITE_OMIT_VIEW) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2044
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2045 #ifndef SQLITE_OMIT_VIEW
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2046 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2047 ** This routine attempts to flatten subqueries in order to speed
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2048 ** execution. It returns 1 if it makes changes and 0 if no flattening
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2049 ** occurs.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2050 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2051 ** To understand the concept of flattening, consider the following
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2052 ** query:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2053 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2054 ** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2055 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2056 ** The default way of implementing this query is to execute the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2057 ** subquery first and store the results in a temporary table, then
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2058 ** run the outer query on that temporary table. This requires two
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2059 ** passes over the data. Furthermore, because the temporary table
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2060 ** has no indices, the WHERE clause on the outer query cannot be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2061 ** optimized.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2062 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2063 ** This routine attempts to rewrite queries such as the above into
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2064 ** a single flat select, like this:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2065 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2066 ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2067 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2068 ** The code generated for this simpification gives the same result
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2069 ** but only has to scan the data once. And because indices might
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2070 ** exist on the table t1, a complete scan of the data might be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2071 ** avoided.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2072 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2073 ** Flattening is only attempted if all of the following are true:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2074 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2075 ** (1) The subquery and the outer query do not both use aggregates.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2076 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2077 ** (2) The subquery is not an aggregate or the outer query is not a join.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2078 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2079 ** (3) The subquery is not the right operand of a left outer join, or
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2080 ** the subquery is not itself a join. (Ticket #306)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2081 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2082 ** (4) The subquery is not DISTINCT or the outer query is not a join.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2083 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2084 ** (5) The subquery is not DISTINCT or the outer query does not use
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2085 ** aggregates.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2086 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2087 ** (6) The subquery does not use aggregates or the outer query is not
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2088 ** DISTINCT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2089 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2090 ** (7) The subquery has a FROM clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2091 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2092 ** (8) The subquery does not use LIMIT or the outer query is not a join.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2093 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2094 ** (9) The subquery does not use LIMIT or the outer query does not use
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2095 ** aggregates.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2096 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2097 ** (10) The subquery does not use aggregates or the outer query does not
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2098 ** use LIMIT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2099 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2100 ** (11) The subquery and the outer query do not both have ORDER BY clauses.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2101 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2102 ** (12) The subquery is not the right term of a LEFT OUTER JOIN or the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2103 ** subquery has no WHERE clause. (added by ticket #350)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2104 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2105 ** (13) The subquery and outer query do not both use LIMIT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2106 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2107 ** (14) The subquery does not use OFFSET
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2108 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2109 ** In this routine, the "p" parameter is a pointer to the outer query.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2110 ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2111 ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2112 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2113 ** If flattening is not attempted, this routine is a no-op and returns 0.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2114 ** If flattening is attempted this routine returns 1.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2115 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2116 ** All of the expression analysis must occur on both the outer query and
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2117 ** the subquery before this routine runs.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2118 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2119 static int flattenSubquery(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2120 Select *p, /* The parent or outer SELECT statement */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2121 int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2122 int isAgg, /* True if outer SELECT uses aggregate functions */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2123 int subqueryIsAgg /* True if the subquery uses aggregate functions */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2124 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2125 Select *pSub; /* The inner query or "subquery" */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2126 SrcList *pSrc; /* The FROM clause of the outer query */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2127 SrcList *pSubSrc; /* The FROM clause of the subquery */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2128 ExprList *pList; /* The result set of the outer query */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2129 int iParent; /* VDBE cursor number of the pSub result set temp table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2130 int i; /* Loop counter */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2131 Expr *pWhere; /* The WHERE clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2132 struct SrcList_item *pSubitem; /* The subquery */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2133
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2134 /* Check to see if flattening is permitted. Return 0 if not.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2135 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2136 if( p==0 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2137 pSrc = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2138 assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2139 pSubitem = &pSrc->a[iFrom];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2140 pSub = pSubitem->pSelect;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2141 assert( pSub!=0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2142 if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2143 if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2144 pSubSrc = pSub->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2145 assert( pSubSrc );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2146 /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2147 ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2148 ** because they could be computed at compile-time. But when LIMIT and OFFSET
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2149 ** became arbitrary expressions, we were forced to add restrictions (13)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2150 ** and (14). */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2151 if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2152 if( pSub->pOffset ) return 0; /* Restriction (14) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2153 if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2154 if( (pSub->isDistinct || pSub->pLimit)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2155 && (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2156 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2157 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2158 if( p->isDistinct && subqueryIsAgg ) return 0; /* Restriction (6) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2159 if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2160 return 0; /* Restriction (11) */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2161 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2162
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2163 /* Restriction 3: If the subquery is a join, make sure the subquery is
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2164 ** not used as the right operand of an outer join. Examples of why this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2165 ** is not allowed:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2166 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2167 ** t1 LEFT OUTER JOIN (t2 JOIN t3)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2168 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2169 ** If we flatten the above, we would get
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2170 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2171 ** (t1 LEFT OUTER JOIN t2) JOIN t3
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2172 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2173 ** which is not at all the same thing.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2174 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2175 if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2176 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2177 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2178
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2179 /* Restriction 12: If the subquery is the right operand of a left outer
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2180 ** join, make sure the subquery has no WHERE clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2181 ** An examples of why this is not allowed:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2182 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2183 ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2184 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2185 ** If we flatten the above, we would get
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2186 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2187 ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2188 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2189 ** But the t2.x>0 test will always fail on a NULL row of t2, which
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2190 ** effectively converts the OUTER JOIN into an INNER JOIN.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2191 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2192 if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2193 && pSub->pWhere!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2194 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2195 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2196
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2197 /* If we reach this point, it means flattening is permitted for the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2198 ** iFrom-th entry of the FROM clause in the outer query.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2199 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2200
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2201 /* Move all of the FROM elements of the subquery into the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2202 ** the FROM clause of the outer query. Before doing this, remember
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2203 ** the cursor number for the original outer query FROM element in
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2204 ** iParent. The iParent cursor will never be used. Subsequent code
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2205 ** will scan expressions looking for iParent references and replace
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2206 ** those references with expressions that resolve to the subquery FROM
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2207 ** elements we are now copying in.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2208 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2209 iParent = pSubitem->iCursor;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2210 {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2211 int nSubSrc = pSubSrc->nSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2212 int jointype = pSubitem->jointype;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2213
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2214 sqlite3DeleteTable(0, pSubitem->pTab);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2215 sqliteFree(pSubitem->zDatabase);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2216 sqliteFree(pSubitem->zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2217 sqliteFree(pSubitem->zAlias);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2218 if( nSubSrc>1 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2219 int extra = nSubSrc - 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2220 for(i=1; i<nSubSrc; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2221 pSrc = sqlite3SrcListAppend(pSrc, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2222 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2223 p->pSrc = pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2224 for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2225 pSrc->a[i] = pSrc->a[i-extra];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2226 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2227 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2228 for(i=0; i<nSubSrc; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2229 pSrc->a[i+iFrom] = pSubSrc->a[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2230 memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2231 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2232 pSrc->a[iFrom+nSubSrc-1].jointype = jointype;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2233 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2234
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2235 /* Now begin substituting subquery result set expressions for
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2236 ** references to the iParent in the outer query.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2237 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2238 ** Example:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2239 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2240 ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2241 ** \ \_____________ subquery __________/ /
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2242 ** \_____________________ outer query ______________________________/
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2243 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2244 ** We look at every expression in the outer query and every place we see
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2245 ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2246 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2247 pList = p->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2248 for(i=0; i<pList->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2249 Expr *pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2250 if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2251 pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2252 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2253 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2254 substExprList(p->pEList, iParent, pSub->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2255 if( isAgg ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2256 substExprList(p->pGroupBy, iParent, pSub->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2257 substExpr(p->pHaving, iParent, pSub->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2258 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2259 if( pSub->pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2260 assert( p->pOrderBy==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2261 p->pOrderBy = pSub->pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2262 pSub->pOrderBy = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2263 }else if( p->pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2264 substExprList(p->pOrderBy, iParent, pSub->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2265 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2266 if( pSub->pWhere ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2267 pWhere = sqlite3ExprDup(pSub->pWhere);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2268 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2269 pWhere = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2270 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2271 if( subqueryIsAgg ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2272 assert( p->pHaving==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2273 p->pHaving = p->pWhere;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2274 p->pWhere = pWhere;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2275 substExpr(p->pHaving, iParent, pSub->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2276 p->pHaving = sqlite3ExprAnd(p->pHaving, sqlite3ExprDup(pSub->pHaving));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2277 assert( p->pGroupBy==0 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2278 p->pGroupBy = sqlite3ExprListDup(pSub->pGroupBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2279 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2280 substExpr(p->pWhere, iParent, pSub->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2281 p->pWhere = sqlite3ExprAnd(p->pWhere, pWhere);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2282 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2283
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2284 /* The flattened query is distinct if either the inner or the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2285 ** outer query is distinct.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2286 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2287 p->isDistinct = p->isDistinct || pSub->isDistinct;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2288
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2289 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2290 ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2291 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2292 ** One is tempted to try to add a and b to combine the limits. But this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2293 ** does not work if either limit is negative.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2294 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2295 if( pSub->pLimit ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2296 p->pLimit = pSub->pLimit;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2297 pSub->pLimit = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2298 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2299
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2300 /* Finially, delete what is left of the subquery and return
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2301 ** success.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2302 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2303 sqlite3SelectDelete(pSub);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2304 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2305 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2306 #endif /* SQLITE_OMIT_VIEW */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2307
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2308 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2309 ** Analyze the SELECT statement passed in as an argument to see if it
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2310 ** is a simple min() or max() query. If it is and this query can be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2311 ** satisfied using a single seek to the beginning or end of an index,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2312 ** then generate the code for this SELECT and return 1. If this is not a
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2313 ** simple min() or max() query, then return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2314 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2315 ** A simply min() or max() query looks like this:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2316 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2317 ** SELECT min(a) FROM table;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2318 ** SELECT max(a) FROM table;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2319 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2320 ** The query may have only a single table in its FROM argument. There
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2321 ** can be no GROUP BY or HAVING or WHERE clauses. The result set must
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2322 ** be the min() or max() of a single column of the table. The column
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2323 ** in the min() or max() function must be indexed.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2324 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2325 ** The parameters to this routine are the same as for sqlite3Select().
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2326 ** See the header comment on that routine for additional information.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2327 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2328 static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2329 Expr *pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2330 int iCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2331 Table *pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2332 Index *pIdx;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2333 int base;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2334 Vdbe *v;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2335 int seekOp;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2336 ExprList *pEList, *pList, eList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2337 struct ExprList_item eListItem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2338 SrcList *pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2339 int brk;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2340 int iDb;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2341
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2342 /* Check to see if this query is a simple min() or max() query. Return
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2343 ** zero if it is not.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2344 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2345 if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2346 pSrc = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2347 if( pSrc->nSrc!=1 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2348 pEList = p->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2349 if( pEList->nExpr!=1 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2350 pExpr = pEList->a[0].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2351 if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2352 pList = pExpr->pList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2353 if( pList==0 || pList->nExpr!=1 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2354 if( pExpr->token.n!=3 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2355 if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2356 seekOp = OP_Rewind;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2357 }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2358 seekOp = OP_Last;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2359 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2360 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2361 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2362 pExpr = pList->a[0].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2363 if( pExpr->op!=TK_COLUMN ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2364 iCol = pExpr->iColumn;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2365 pTab = pSrc->a[0].pTab;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2366
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2367
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2368 /* If we get to here, it means the query is of the correct form.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2369 ** Check to make sure we have an index and make pIdx point to the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2370 ** appropriate index. If the min() or max() is on an INTEGER PRIMARY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2371 ** key column, no index is necessary so set pIdx to NULL. If no
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2372 ** usable index is found, return 0.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2373 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2374 if( iCol<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2375 pIdx = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2376 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2377 CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2378 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2379 assert( pIdx->nColumn>=1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2380 if( pIdx->aiColumn[0]==iCol &&
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2381 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2382 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2383 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2384 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2385 if( pIdx==0 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2386 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2387
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2388 /* Identify column types if we will be using the callback. This
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2389 ** step is skipped if the output is going to a table or a memory cell.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2390 ** The column names have already been generated in the calling function.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2391 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2392 v = sqlite3GetVdbe(pParse);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2393 if( v==0 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2394
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2395 /* If the output is destined for a temporary table, open that table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2396 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2397 if( eDest==SRT_VirtualTab ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2398 sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2399 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2400
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2401 /* Generating code to find the min or the max. Basically all we have
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2402 ** to do is find the first or the last entry in the chosen index. If
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2403 ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2404 ** or last entry in the main table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2405 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2406 iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2407 assert( iDb>=0 || pTab->isTransient );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2408 sqlite3CodeVerifySchema(pParse, iDb);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2409 sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2410 base = pSrc->a[0].iCursor;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2411 brk = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2412 computeLimitRegisters(pParse, p, brk);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2413 if( pSrc->a[0].pSelect==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2414 sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2415 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2416 if( pIdx==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2417 sqlite3VdbeAddOp(v, seekOp, base, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2418 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2419 /* Even though the cursor used to open the index here is closed
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2420 ** as soon as a single value has been read from it, allocate it
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2421 ** using (pParse->nTab++) to prevent the cursor id from being
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2422 ** reused. This is important for statements of the form
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2423 ** "INSERT INTO x SELECT max() FROM x".
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2424 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2425 int iIdx;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2426 KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2427 iIdx = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2428 assert( pIdx->pSchema==pTab->pSchema );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2429 sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2430 sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2431 (char*)pKey, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2432 if( seekOp==OP_Rewind ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2433 sqlite3VdbeAddOp(v, OP_Null, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2434 sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2435 seekOp = OP_MoveGt;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2436 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2437 sqlite3VdbeAddOp(v, seekOp, iIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2438 sqlite3VdbeAddOp(v, OP_IdxRowid, iIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2439 sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2440 sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2441 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2442 eList.nExpr = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2443 memset(&eListItem, 0, sizeof(eListItem));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2444 eList.a = &eListItem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2445 eList.a[0].pExpr = pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2446 selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2447 sqlite3VdbeResolveLabel(v, brk);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2448 sqlite3VdbeAddOp(v, OP_Close, base, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2449
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2450 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2451 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2452
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2453 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2454 ** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2455 ** the number of errors seen.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2456 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2457 ** An ORDER BY or GROUP BY is a list of expressions. If any expression
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2458 ** is an integer constant, then that expression is replaced by the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2459 ** corresponding entry in the result set.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2460 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2461 static int processOrderGroupBy(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2462 NameContext *pNC, /* Name context of the SELECT statement. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2463 ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2464 const char *zType /* Either "ORDER" or "GROUP", as appropriate */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2465 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2466 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2467 ExprList *pEList = pNC->pEList; /* The result set of the SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2468 Parse *pParse = pNC->pParse; /* The result set of the SELECT */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2469 assert( pEList );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2470
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2471 if( pOrderBy==0 ) return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2472 for(i=0; i<pOrderBy->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2473 int iCol;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2474 Expr *pE = pOrderBy->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2475 if( sqlite3ExprIsInteger(pE, &iCol) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2476 if( iCol>0 && iCol<=pEList->nExpr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2477 sqlite3ExprDelete(pE);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2478 pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2479 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2480 sqlite3ErrorMsg(pParse,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2481 "%s BY column number %d out of range - should be "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2482 "between 1 and %d", zType, iCol, pEList->nExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2483 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2484 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2485 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2486 if( sqlite3ExprResolveNames(pNC, pE) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2487 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2488 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2489 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2490 return 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2491 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2492
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2493 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2494 ** This routine resolves any names used in the result set of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2495 ** supplied SELECT statement. If the SELECT statement being resolved
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2496 ** is a sub-select, then pOuterNC is a pointer to the NameContext
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2497 ** of the parent SELECT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2498 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2499 int sqlite3SelectResolve(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2500 Parse *pParse, /* The parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2501 Select *p, /* The SELECT statement being coded. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2502 NameContext *pOuterNC /* The outer name context. May be NULL. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2503 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2504 ExprList *pEList; /* Result set. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2505 int i; /* For-loop variable used in multiple places */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2506 NameContext sNC; /* Local name-context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2507 ExprList *pGroupBy; /* The group by clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2508
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2509 /* If this routine has run before, return immediately. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2510 if( p->isResolved ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2511 assert( !pOuterNC );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2512 return SQLITE_OK;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2513 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2514 p->isResolved = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2515
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2516 /* If there have already been errors, do nothing. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2517 if( pParse->nErr>0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2518 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2519 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2520
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2521 /* Prepare the select statement. This call will allocate all cursors
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2522 ** required to handle the tables and subqueries in the FROM clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2523 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2524 if( prepSelectStmt(pParse, p) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2525 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2526 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2527
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2528 /* Resolve the expressions in the LIMIT and OFFSET clauses. These
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2529 ** are not allowed to refer to any names, so pass an empty NameContext.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2530 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2531 memset(&sNC, 0, sizeof(sNC));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2532 sNC.pParse = pParse;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2533 if( sqlite3ExprResolveNames(&sNC, p->pLimit) ||
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2534 sqlite3ExprResolveNames(&sNC, p->pOffset) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2535 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2536 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2537
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2538 /* Set up the local name-context to pass to ExprResolveNames() to
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2539 ** resolve the expression-list.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2540 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2541 sNC.allowAgg = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2542 sNC.pSrcList = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2543 sNC.pNext = pOuterNC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2544
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2545 /* Resolve names in the result set. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2546 pEList = p->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2547 if( !pEList ) return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2548 for(i=0; i<pEList->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2549 Expr *pX = pEList->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2550 if( sqlite3ExprResolveNames(&sNC, pX) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2551 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2552 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2553 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2554
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2555 /* If there are no aggregate functions in the result-set, and no GROUP BY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2556 ** expression, do not allow aggregates in any of the other expressions.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2557 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2558 assert( !p->isAgg );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2559 pGroupBy = p->pGroupBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2560 if( pGroupBy || sNC.hasAgg ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2561 p->isAgg = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2562 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2563 sNC.allowAgg = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2564 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2565
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2566 /* If a HAVING clause is present, then there must be a GROUP BY clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2567 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2568 if( p->pHaving && !pGroupBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2569 sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2570 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2571 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2572
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2573 /* Add the expression list to the name-context before parsing the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2574 ** other expressions in the SELECT statement. This is so that
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2575 ** expressions in the WHERE clause (etc.) can refer to expressions by
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2576 ** aliases in the result set.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2577 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2578 ** Minor point: If this is the case, then the expression will be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2579 ** re-evaluated for each reference to it.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2580 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2581 sNC.pEList = p->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2582 if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2583 sqlite3ExprResolveNames(&sNC, p->pHaving) ||
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2584 processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2585 processOrderGroupBy(&sNC, pGroupBy, "GROUP")
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2586 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2587 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2588 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2589
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2590 /* Make sure the GROUP BY clause does not contain aggregate functions.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2591 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2592 if( pGroupBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2593 struct ExprList_item *pItem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2594
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2595 for(i=0, pItem=pGroupBy->a; i<pGroupBy->nExpr; i++, pItem++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2596 if( ExprHasProperty(pItem->pExpr, EP_Agg) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2597 sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2598 "the GROUP BY clause");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2599 return SQLITE_ERROR;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2600 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2601 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2602 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2603
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2604 return SQLITE_OK;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2605 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2606
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2607 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2608 ** Reset the aggregate accumulator.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2609 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2610 ** The aggregate accumulator is a set of memory cells that hold
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2611 ** intermediate results while calculating an aggregate. This
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2612 ** routine simply stores NULLs in all of those memory cells.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2613 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2614 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2615 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2616 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2617 struct AggInfo_func *pFunc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2618 if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2619 return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2620 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2621 for(i=0; i<pAggInfo->nColumn; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2622 sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2623 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2624 for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2625 sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2626 if( pFunc->iDistinct>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2627 Expr *pE = pFunc->pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2628 if( pE->pList==0 || pE->pList->nExpr!=1 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2629 sqlite3ErrorMsg(pParse, "DISTINCT in aggregate must be followed "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2630 "by an expression");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2631 pFunc->iDistinct = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2632 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2633 KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2634 sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2635 (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2636 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2637 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2638 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2639 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2640
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2641 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2642 ** Invoke the OP_AggFinalize opcode for every aggregate function
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2643 ** in the AggInfo structure.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2644 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2645 static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2646 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2647 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2648 struct AggInfo_func *pF;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2649 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2650 ExprList *pList = pF->pExpr->pList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2651 sqlite3VdbeOp3(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2652 (void*)pF->pFunc, P3_FUNCDEF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2653 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2654 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2655
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2656 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2657 ** Update the accumulator memory cells for an aggregate based on
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2658 ** the current cursor position.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2659 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2660 static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2661 Vdbe *v = pParse->pVdbe;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2662 int i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2663 struct AggInfo_func *pF;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2664 struct AggInfo_col *pC;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2665
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2666 pAggInfo->directMode = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2667 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2668 int nArg;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2669 int addrNext = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2670 ExprList *pList = pF->pExpr->pList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2671 if( pList ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2672 nArg = pList->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2673 sqlite3ExprCodeExprList(pParse, pList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2674 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2675 nArg = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2676 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2677 if( pF->iDistinct>=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2678 addrNext = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2679 assert( nArg==1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2680 codeDistinct(v, pF->iDistinct, addrNext, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2681 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2682 if( pF->pFunc->needCollSeq ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2683 CollSeq *pColl = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2684 struct ExprList_item *pItem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2685 int j;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2686 assert( pList!=0 ); /* pList!=0 if pF->pFunc->needCollSeq is true */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2687 for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2688 pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2689 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2690 if( !pColl ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2691 pColl = pParse->db->pDfltColl;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2692 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2693 sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2694 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2695 sqlite3VdbeOp3(v, OP_AggStep, pF->iMem, nArg, (void*)pF->pFunc, P3_FUNCDEF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2696 if( addrNext ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2697 sqlite3VdbeResolveLabel(v, addrNext);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2698 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2699 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2700 for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2701 sqlite3ExprCode(pParse, pC->pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2702 sqlite3VdbeAddOp(v, OP_MemStore, pC->iMem, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2703 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2704 pAggInfo->directMode = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2705 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2706
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2707
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2708 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2709 ** Generate code for the given SELECT statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2710 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2711 ** The results are distributed in various ways depending on the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2712 ** value of eDest and iParm.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2713 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2714 ** eDest Value Result
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2715 ** ------------ -------------------------------------------
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2716 ** SRT_Callback Invoke the callback for each row of the result.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2717 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2718 ** SRT_Mem Store first result in memory cell iParm
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2719 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2720 ** SRT_Set Store results as keys of table iParm.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2721 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2722 ** SRT_Union Store results as a key in a temporary table iParm
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2723 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2724 ** SRT_Except Remove results from the temporary table iParm.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2725 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2726 ** SRT_Table Store results in temporary table iParm
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2727 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2728 ** The table above is incomplete. Additional eDist value have be added
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2729 ** since this comment was written. See the selectInnerLoop() function for
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2730 ** a complete listing of the allowed values of eDest and their meanings.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2731 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2732 ** This routine returns the number of errors. If any errors are
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2733 ** encountered, then an appropriate error message is left in
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2734 ** pParse->zErrMsg.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2735 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2736 ** This routine does NOT free the Select structure passed in. The
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2737 ** calling function needs to do that.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2738 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2739 ** The pParent, parentTab, and *pParentAgg fields are filled in if this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2740 ** SELECT is a subquery. This routine may try to combine this SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2741 ** with its parent to form a single flat query. In so doing, it might
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2742 ** change the parent query from a non-aggregate to an aggregate query.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2743 ** For that reason, the pParentAgg flag is passed as a pointer, so it
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2744 ** can be changed.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2745 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2746 ** Example 1: The meaning of the pParent parameter.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2747 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2748 ** SELECT * FROM t1 JOIN (SELECT x, count(*) FROM t2) JOIN t3;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2749 ** \ \_______ subquery _______/ /
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2750 ** \ /
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2751 ** \____________________ outer query ___________________/
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2752 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2753 ** This routine is called for the outer query first. For that call,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2754 ** pParent will be NULL. During the processing of the outer query, this
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2755 ** routine is called recursively to handle the subquery. For the recursive
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2756 ** call, pParent will point to the outer query. Because the subquery is
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2757 ** the second element in a three-way join, the parentTab parameter will
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2758 ** be 1 (the 2nd value of a 0-indexed array.)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2759 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2760 int sqlite3Select(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2761 Parse *pParse, /* The parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2762 Select *p, /* The SELECT statement being coded. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2763 int eDest, /* How to dispose of the results */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2764 int iParm, /* A parameter used by the eDest disposal method */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2765 Select *pParent, /* Another SELECT for which this is a sub-query */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2766 int parentTab, /* Index in pParent->pSrc of this query */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2767 int *pParentAgg, /* True if pParent uses aggregate functions */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2768 char *aff /* If eDest is SRT_Union, the affinity string */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2769 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2770 int i, j; /* Loop counters */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2771 WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2772 Vdbe *v; /* The virtual machine under construction */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2773 int isAgg; /* True for select lists like "count(*)" */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2774 ExprList *pEList; /* List of columns to extract. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2775 SrcList *pTabList; /* List of tables to select from */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2776 Expr *pWhere; /* The WHERE clause. May be NULL */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2777 ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2778 ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2779 Expr *pHaving; /* The HAVING clause. May be NULL */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2780 int isDistinct; /* True if the DISTINCT keyword is present */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2781 int distinct; /* Table to use for the distinct set */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2782 int rc = 1; /* Value to return from this function */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2783 int addrSortIndex; /* Address of an OP_OpenVirtual instruction */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2784 AggInfo sAggInfo; /* Information used by aggregate queries */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2785 int iEnd; /* Address of the end of the query */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2786
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2787 if( p==0 || sqlite3MallocFailed() || pParse->nErr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2788 return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2789 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2790 if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2791 memset(&sAggInfo, 0, sizeof(sAggInfo));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2792
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2793 #ifndef SQLITE_OMIT_COMPOUND_SELECT
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2794 /* If there is are a sequence of queries, do the earlier ones first.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2795 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2796 if( p->pPrior ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2797 if( p->pRightmost==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2798 Select *pLoop;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2799 for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2800 pLoop->pRightmost = p;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2801 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2802 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2803 return multiSelect(pParse, p, eDest, iParm, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2804 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2805 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2806
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2807 pOrderBy = p->pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2808 if( IgnorableOrderby(eDest) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2809 p->pOrderBy = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2810 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2811 if( sqlite3SelectResolve(pParse, p, 0) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2812 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2813 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2814 p->pOrderBy = pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2815
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2816 /* Make local copies of the parameters for this query.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2817 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2818 pTabList = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2819 pWhere = p->pWhere;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2820 pGroupBy = p->pGroupBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2821 pHaving = p->pHaving;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2822 isAgg = p->isAgg;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2823 isDistinct = p->isDistinct;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2824 pEList = p->pEList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2825 if( pEList==0 ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2826
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2827 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2828 ** Do not even attempt to generate any code if we have already seen
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2829 ** errors before this routine starts.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2830 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2831 if( pParse->nErr>0 ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2832
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2833 /* If writing to memory or generating a set
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2834 ** only a single column may be output.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2835 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2836 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2837 if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2838 sqlite3ErrorMsg(pParse, "only a single result allowed for "
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2839 "a SELECT that is part of an expression");
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2840 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2841 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2842 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2843
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2844 /* ORDER BY is ignored for some destinations.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2845 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2846 if( IgnorableOrderby(eDest) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2847 pOrderBy = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2848 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2849
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2850 /* Begin generating code.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2851 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2852 v = sqlite3GetVdbe(pParse);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2853 if( v==0 ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2854
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2855 /* Generate code for all sub-queries in the FROM clause
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2856 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2857 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2858 for(i=0; i<pTabList->nSrc; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2859 const char *zSavedAuthContext = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2860 int needRestoreContext;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2861 struct SrcList_item *pItem = &pTabList->a[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2862
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2863 if( pItem->pSelect==0 || pItem->isPopulated ) continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2864 if( pItem->zName!=0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2865 zSavedAuthContext = pParse->zAuthContext;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2866 pParse->zAuthContext = pItem->zName;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2867 needRestoreContext = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2868 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2869 needRestoreContext = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2870 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2871 sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2872 pItem->iCursor, p, i, &isAgg, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2873 if( needRestoreContext ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2874 pParse->zAuthContext = zSavedAuthContext;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2875 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2876 pTabList = p->pSrc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2877 pWhere = p->pWhere;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2878 if( !IgnorableOrderby(eDest) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2879 pOrderBy = p->pOrderBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2880 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2881 pGroupBy = p->pGroupBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2882 pHaving = p->pHaving;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2883 isDistinct = p->isDistinct;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2884 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2885 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2886
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2887 /* Check for the special case of a min() or max() function by itself
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2888 ** in the result set.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2889 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2890 if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2891 rc = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2892 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2893 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2894
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2895 /* Check to see if this is a subquery that can be "flattened" into its parent.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2896 ** If flattening is a possiblity, do so and return immediately.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2897 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2898 #ifndef SQLITE_OMIT_VIEW
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2899 if( pParent && pParentAgg &&
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2900 flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2901 if( isAgg ) *pParentAgg = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2902 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2903 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2904 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2905
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2906 /* If there is an ORDER BY clause, resolve any collation sequences
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2907 ** names that have been explicitly specified and create a sorting index.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2908 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2909 ** This sorting index might end up being unused if the data can be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2910 ** extracted in pre-sorted order. If that is the case, then the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2911 ** OP_OpenVirtual instruction will be changed to an OP_Noop once
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2912 ** we figure out that the sorting index is not needed. The addrSortIndex
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2913 ** variable is used to facilitate that change.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2914 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2915 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2916 struct ExprList_item *pTerm;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2917 KeyInfo *pKeyInfo;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2918 for(i=0, pTerm=pOrderBy->a; i<pOrderBy->nExpr; i++, pTerm++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2919 if( pTerm->zName ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2920 pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2921 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2922 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2923 if( pParse->nErr ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2924 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2925 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2926 pKeyInfo = keyInfoFromExprList(pParse, pOrderBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2927 pOrderBy->iECursor = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2928 p->addrOpenVirt[2] = addrSortIndex =
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2929 sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2930 (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2931 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2932 addrSortIndex = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2933 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2934
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2935 /* If the output is destined for a temporary table, open that table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2936 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2937 if( eDest==SRT_VirtualTab ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2938 sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2939 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2940
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2941 /* Set the limiter.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2942 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2943 iEnd = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2944 computeLimitRegisters(pParse, p, iEnd);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2945
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2946 /* Open a virtual index to use for the distinct set.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2947 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2948 if( isDistinct ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2949 KeyInfo *pKeyInfo;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2950 distinct = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2951 pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2952 sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2953 (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2954 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2955 distinct = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2956 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2957
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2958 /* Aggregate and non-aggregate queries are handled differently */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2959 if( !isAgg && pGroupBy==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2960 /* This case is for non-aggregate queries
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2961 ** Begin the database scan
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2962 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2963 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2964 if( pWInfo==0 ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2965
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2966 /* If sorting index that was created by a prior OP_OpenVirtual
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2967 ** instruction ended up not being needed, then change the OP_OpenVirtual
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2968 ** into an OP_Noop.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2969 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2970 if( addrSortIndex>=0 && pOrderBy==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2971 sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2972 p->addrOpenVirt[2] = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2973 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2974
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2975 /* Use the standard inner loop
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2976 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2977 if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2978 iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2979 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2980 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2981
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2982 /* End the database scan loop.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2983 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2984 sqlite3WhereEnd(pWInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2985 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2986 /* This is the processing for aggregate queries */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2987 NameContext sNC; /* Name context for processing aggregate information */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2988 int iAMem; /* First Mem address for storing current GROUP BY */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2989 int iBMem; /* First Mem address for previous GROUP BY */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2990 int iUseFlag; /* Mem address holding flag indicating that at least
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2991 ** one row of the input to the aggregator has been
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2992 ** processed */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2993 int iAbortFlag; /* Mem address which causes query abort if positive */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2994 int groupBySort; /* Rows come from source in GROUP BY order */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2995
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2996
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2997 /* The following variables hold addresses or labels for parts of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2998 ** virtual machine program we are putting together */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2999 int addrOutputRow; /* Start of subroutine that outputs a result row */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3000 int addrSetAbort; /* Set the abort flag and return */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3001 int addrInitializeLoop; /* Start of code that initializes the input loop */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3002 int addrTopOfLoop; /* Top of the input loop */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3003 int addrGroupByChange; /* Code that runs when any GROUP BY term changes */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3004 int addrProcessRow; /* Code to process a single input row */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3005 int addrEnd; /* End of all processing */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3006 int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3007 int addrReset; /* Subroutine for resetting the accumulator */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3008
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3009 addrEnd = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3010
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3011 /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3012 ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3013 ** SELECT statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3014 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3015 memset(&sNC, 0, sizeof(sNC));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3016 sNC.pParse = pParse;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3017 sNC.pSrcList = pTabList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3018 sNC.pAggInfo = &sAggInfo;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3019 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3020 sAggInfo.pGroupBy = pGroupBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3021 if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3022 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3023 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3024 if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3025 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3026 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3027 if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3028 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3029 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3030 sAggInfo.nAccumulator = sAggInfo.nColumn;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3031 for(i=0; i<sAggInfo.nFunc; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3032 if( sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3033 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3034 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3035 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3036 if( sqlite3MallocFailed() ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3037
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3038 /* Processing for aggregates with GROUP BY is very different and
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3039 ** much more complex tha aggregates without a GROUP BY.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3040 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3041 if( pGroupBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3042 KeyInfo *pKeyInfo; /* Keying information for the group by clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3043
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3044 /* Create labels that we will be needing
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3045 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3046
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3047 addrInitializeLoop = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3048 addrGroupByChange = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3049 addrProcessRow = sqlite3VdbeMakeLabel(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3050
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3051 /* If there is a GROUP BY clause we might need a sorting index to
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3052 ** implement it. Allocate that sorting index now. If it turns out
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3053 ** that we do not need it after all, the OpenVirtual instruction
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3054 ** will be converted into a Noop.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3055 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3056 sAggInfo.sortingIdx = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3057 pKeyInfo = keyInfoFromExprList(pParse, pGroupBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3058 addrSortingIdx =
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3059 sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3060 sAggInfo.nSortingColumn,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3061 (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3062
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3063 /* Initialize memory locations used by GROUP BY aggregate processing
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3064 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3065 iUseFlag = pParse->nMem++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3066 iAbortFlag = pParse->nMem++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3067 iAMem = pParse->nMem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3068 pParse->nMem += pGroupBy->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3069 iBMem = pParse->nMem;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3070 pParse->nMem += pGroupBy->nExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3071 sqlite3VdbeAddOp(v, OP_MemInt, 0, iAbortFlag);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3072 VdbeComment((v, "# clear abort flag"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3073 sqlite3VdbeAddOp(v, OP_MemInt, 0, iUseFlag);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3074 VdbeComment((v, "# indicate accumulator empty"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3075 sqlite3VdbeAddOp(v, OP_Goto, 0, addrInitializeLoop);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3076
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3077 /* Generate a subroutine that outputs a single row of the result
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3078 ** set. This subroutine first looks at the iUseFlag. If iUseFlag
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3079 ** is less than or equal to zero, the subroutine is a no-op. If
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3080 ** the processing calls for the query to abort, this subroutine
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3081 ** increments the iAbortFlag memory location before returning in
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3082 ** order to signal the caller to abort.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3083 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3084 addrSetAbort = sqlite3VdbeCurrentAddr(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3085 sqlite3VdbeAddOp(v, OP_MemInt, 1, iAbortFlag);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3086 VdbeComment((v, "# set abort flag"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3087 sqlite3VdbeAddOp(v, OP_Return, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3088 addrOutputRow = sqlite3VdbeCurrentAddr(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3089 sqlite3VdbeAddOp(v, OP_IfMemPos, iUseFlag, addrOutputRow+2);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3090 VdbeComment((v, "# Groupby result generator entry point"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3091 sqlite3VdbeAddOp(v, OP_Return, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3092 finalizeAggFunctions(pParse, &sAggInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3093 if( pHaving ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3094 sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3095 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3096 rc = selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3097 distinct, eDest, iParm,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3098 addrOutputRow+1, addrSetAbort, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3099 if( rc ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3100 goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3101 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3102 sqlite3VdbeAddOp(v, OP_Return, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3103 VdbeComment((v, "# end groupby result generator"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3104
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3105 /* Generate a subroutine that will reset the group-by accumulator
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3106 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3107 addrReset = sqlite3VdbeCurrentAddr(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3108 resetAccumulator(pParse, &sAggInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3109 sqlite3VdbeAddOp(v, OP_Return, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3110
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3111 /* Begin a loop that will extract all source rows in GROUP BY order.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3112 ** This might involve two separate loops with an OP_Sort in between, or
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3113 ** it might be a single loop that uses an index to extract information
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3114 ** in the right order to begin with.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3115 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3116 sqlite3VdbeResolveLabel(v, addrInitializeLoop);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3117 sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3118 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3119 if( pWInfo==0 ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3120 if( pGroupBy==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3121 /* The optimizer is able to deliver rows in group by order so
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3122 ** we do not have to sort. The OP_OpenVirtual table will be
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3123 ** cancelled later because we still need to use the pKeyInfo
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3124 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3125 pGroupBy = p->pGroupBy;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3126 groupBySort = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3127 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3128 /* Rows are coming out in undetermined order. We have to push
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3129 ** each row into a sorting index, terminate the first loop,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3130 ** then loop over the sorting index in order to get the output
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3131 ** in sorted order
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3132 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3133 groupBySort = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3134 sqlite3ExprCodeExprList(pParse, pGroupBy);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3135 sqlite3VdbeAddOp(v, OP_Sequence, sAggInfo.sortingIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3136 j = pGroupBy->nExpr+1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3137 for(i=0; i<sAggInfo.nColumn; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3138 struct AggInfo_col *pCol = &sAggInfo.aCol[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3139 if( pCol->iSorterColumn<j ) continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3140 if( pCol->iColumn<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3141 sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3142 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3143 sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3144 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3145 j++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3146 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3147 sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3148 sqlite3VdbeAddOp(v, OP_IdxInsert, sAggInfo.sortingIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3149 sqlite3WhereEnd(pWInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3150 sqlite3VdbeAddOp(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3151 VdbeComment((v, "# GROUP BY sort"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3152 sAggInfo.useSortingIdx = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3153 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3154
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3155 /* Evaluate the current GROUP BY terms and store in b0, b1, b2...
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3156 ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3157 ** Then compare the current GROUP BY terms against the GROUP BY terms
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3158 ** from the previous row currently stored in a0, a1, a2...
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3159 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3160 addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3161 for(j=0; j<pGroupBy->nExpr; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3162 if( groupBySort ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3163 sqlite3VdbeAddOp(v, OP_Column, sAggInfo.sortingIdx, j);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3164 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3165 sAggInfo.directMode = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3166 sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3167 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3168 sqlite3VdbeAddOp(v, OP_MemStore, iBMem+j, j<pGroupBy->nExpr-1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3169 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3170 for(j=pGroupBy->nExpr-1; j>=0; j--){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3171 if( j<pGroupBy->nExpr-1 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3172 sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3173 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3174 sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3175 if( j==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3176 sqlite3VdbeAddOp(v, OP_Eq, 0x200, addrProcessRow);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3177 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3178 sqlite3VdbeAddOp(v, OP_Ne, 0x200, addrGroupByChange);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3179 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3180 sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3181 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3182
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3183 /* Generate code that runs whenever the GROUP BY changes.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3184 ** Change in the GROUP BY are detected by the previous code
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3185 ** block. If there were no changes, this block is skipped.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3186 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3187 ** This code copies current group by terms in b0,b1,b2,...
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3188 ** over to a0,a1,a2. It then calls the output subroutine
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3189 ** and resets the aggregate accumulator registers in preparation
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3190 ** for the next GROUP BY batch.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3191 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3192 sqlite3VdbeResolveLabel(v, addrGroupByChange);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3193 for(j=0; j<pGroupBy->nExpr; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3194 sqlite3VdbeAddOp(v, OP_MemMove, iAMem+j, iBMem+j);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3195 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3196 sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3197 VdbeComment((v, "# output one row"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3198 sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3199 VdbeComment((v, "# check abort flag"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3200 sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3201 VdbeComment((v, "# reset accumulator"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3202
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3203 /* Update the aggregate accumulators based on the content of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3204 ** the current row
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3205 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3206 sqlite3VdbeResolveLabel(v, addrProcessRow);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3207 updateAccumulator(pParse, &sAggInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3208 sqlite3VdbeAddOp(v, OP_MemInt, 1, iUseFlag);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3209 VdbeComment((v, "# indicate data in accumulator"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3210
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3211 /* End of the loop
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3212 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3213 if( groupBySort ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3214 sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3215 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3216 sqlite3WhereEnd(pWInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3217 sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3218 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3219
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3220 /* Output the final row of result
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3221 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3222 sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3223 VdbeComment((v, "# output final row"));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3224
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3225 } /* endif pGroupBy */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3226 else {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3227 /* This case runs if the aggregate has no GROUP BY clause. The
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3228 ** processing is much simpler since there is only a single row
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3229 ** of output.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3230 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3231 resetAccumulator(pParse, &sAggInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3232 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3233 if( pWInfo==0 ) goto select_end;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3234 updateAccumulator(pParse, &sAggInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3235 sqlite3WhereEnd(pWInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3236 finalizeAggFunctions(pParse, &sAggInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3237 pOrderBy = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3238 if( pHaving ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3239 sqlite3ExprIfFalse(pParse, pHaving, addrEnd, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3240 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3241 selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3242 eDest, iParm, addrEnd, addrEnd, aff);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3243 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3244 sqlite3VdbeResolveLabel(v, addrEnd);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3245
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3246 } /* endif aggregate query */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3247
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3248 /* If there is an ORDER BY clause, then we need to sort the results
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3249 ** and send them to the callback one by one.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3250 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3251 if( pOrderBy ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3252 generateSortTail(pParse, p, v, pEList->nExpr, eDest, iParm);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3253 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3254
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3255 #ifndef SQLITE_OMIT_SUBQUERY
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3256 /* If this was a subquery, we have now converted the subquery into a
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3257 ** temporary table. So set the SrcList_item.isPopulated flag to prevent
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3258 ** this subquery from being evaluated again and to force the use of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3259 ** the temporary table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3260 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3261 if( pParent ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3262 assert( pParent->pSrc->nSrc>parentTab );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3263 assert( pParent->pSrc->a[parentTab].pSelect==p );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3264 pParent->pSrc->a[parentTab].isPopulated = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3265 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3266 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3267
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3268 /* Jump here to skip this query
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3269 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3270 sqlite3VdbeResolveLabel(v, iEnd);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3271
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3272 /* The SELECT was successfully coded. Set the return code to 0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3273 ** to indicate no errors.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3274 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3275 rc = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3276
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3277 /* Control jumps to here if an error is encountered above, or upon
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3278 ** successful coding of the SELECT.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3279 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3280 select_end:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3281
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3282 /* Identify column names if we will be using them in a callback. This
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3283 ** step is skipped if the output is going to some other destination.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3284 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3285 if( rc==SQLITE_OK && eDest==SRT_Callback ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3286 generateColumnNames(pParse, pTabList, pEList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3287 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3288
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3289 sqliteFree(sAggInfo.aCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3290 sqliteFree(sAggInfo.aFunc);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3291 return rc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3292 }