KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > hql > ast > tree > SelectClause


1 // $Id: SelectClause.java,v 1.1 2005/07/12 20:27:16 steveebersole Exp $
2
package org.hibernate.hql.ast.tree;
3
4 import java.lang.reflect.Constructor JavaDoc;
5 import java.util.ArrayList JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.List JavaDoc;
8
9 import org.hibernate.hql.antlr.SqlTokenTypes;
10 import org.hibernate.hql.ast.util.ASTAppender;
11 import org.hibernate.hql.ast.util.ASTIterator;
12 import org.hibernate.hql.ast.util.ASTPrinter;
13 import org.hibernate.type.Type;
14
15 import antlr.SemanticException;
16 import antlr.collections.AST;
17
18 /**
19  * Represents the list of expressions in a SELECT clause.
20  *
21  * @author josh Sep 21, 2004 7:53:55 AM
22  */

23 public class SelectClause extends SelectExpressionList {
24
25     private boolean prepared = false;
26     private boolean scalarSelect;
27
28     private List JavaDoc fromElementsForLoad = new ArrayList JavaDoc();
29     //private Type[] sqlResultTypes;
30
private Type[] queryReturnTypes;
31     private String JavaDoc[][] columnNames;
32     private ConstructorNode constructorNode;
33     private List JavaDoc collectionFromElements;
34     private String JavaDoc[] aliases;
35
36     /**
37      * Does this SelectClause represent a scalar query
38      *
39      * @return True if this is a scalara select clause; false otherwise.
40      */

41     public boolean isScalarSelect() {
42         return scalarSelect;
43     }
44
45     /**
46      * FromElements which need to be accounted for in the load phase (either for return or for fetch).
47      *
48      * @return List of appropriate FromElements.
49      */

50     public List JavaDoc getFromElementsForLoad() {
51         return fromElementsForLoad;
52     }
53
54     /*
55      * The types represented in the SQL result set.
56      *
57      * @return The types represented in the SQL result set.
58      */

59     /*public Type[] getSqlResultTypes() {
60         return sqlResultTypes;
61     }*/

62
63     /**
64      * The types actually being returned from this query at the "object level".
65      *
66      * @return The query return types.
67      */

68     public Type[] getQueryReturnTypes() {
69         return queryReturnTypes;
70     }
71     
72     /**
73      * The HQL aliases, or generated aliases
74      */

75     public String JavaDoc[] getQueryReturnAliases() {
76         return aliases;
77     }
78
79     /**
80      * The column alias names being used in the generated SQL.
81      *
82      * @return The SQL column aliases.
83      */

84     public String JavaDoc[][] getColumnNames() {
85         return columnNames;
86     }
87
88     /**
89      * The constructor to use for dynamic instantiation queries.
90      *
91      * @return The appropriate Constructor reference, or null if not a
92      * dynamic instantiation query.
93      */

94     public Constructor JavaDoc getConstructor() {
95         return constructorNode == null ? null : constructorNode.getConstructor();
96     }
97     
98     public boolean isMap() {
99         return constructorNode == null ? false : constructorNode.isMap();
100     }
101     
102     public boolean isList() {
103         return constructorNode == null ? false : constructorNode.isList();
104     }
105     
106     /**
107      * Prepares an explicitly defined select clause.
108      *
109      * @param fromClause The from clause linked to this select clause.
110      * @throws SemanticException
111      */

112     public void initializeExplicitSelectClause(FromClause fromClause) throws SemanticException {
113         if ( prepared ) {
114             throw new IllegalStateException JavaDoc( "SelectClause was already prepared!" );
115         }
116
117         //explicit = true; // This is an explict Select.
118
//ArrayList sqlResultTypeList = new ArrayList();
119
ArrayList JavaDoc queryReturnTypeList = new ArrayList JavaDoc();
120
121         // First, collect all of the select expressions.
122
// NOTE: This must be done *before* invoking setScalarColumnText() because setScalarColumnText()
123
// changes the AST!!!
124
SelectExpression[] selectExpressions = collectSelectExpressions();
125         
126         for ( int i = 0; i < selectExpressions.length; i++ ) {
127             SelectExpression expr = selectExpressions[i];
128
129             if ( expr.isConstructor() ) {
130                 constructorNode = ( ConstructorNode ) expr;
131                 List JavaDoc constructorArgumentTypeList = constructorNode.getConstructorArgumentTypeList();
132                 //sqlResultTypeList.addAll( constructorArgumentTypeList );
133
queryReturnTypeList.addAll( constructorArgumentTypeList );
134                 scalarSelect = true;
135             }
136             else {
137                 Type type = expr.getDataType();
138                 if ( type == null ) {
139                     throw new IllegalStateException JavaDoc( "No data type for node: " + expr.getClass().getName() + " "
140                             + new ASTPrinter( SqlTokenTypes.class ).showAsString( ( AST ) expr, "" ) );
141                 }
142                 //sqlResultTypeList.add( type );
143

144                 // If the data type is not an association type, it could not have been in the FROM clause.
145
if ( expr.isScalar() ) {
146                     scalarSelect = true;
147                 }
148
149                 if ( isReturnableEntity( expr ) ) {
150                     fromElementsForLoad.add( expr.getFromElement() );
151                 }
152
153                 // Always add the type to the return type list.
154
queryReturnTypeList.add( type );
155             }
156         }
157
158         //init the aliases, after initing the constructornode
159
initAliases(selectExpressions);
160
161         if ( !getWalker().isShallowQuery() ) {
162             // add the fetched entities
163
List JavaDoc fromElements = fromClause.getProjectionList();
164     
165             ASTAppender appender = new ASTAppender( getASTFactory(), this ); // Get ready to start adding nodes.
166
int size = fromElements.size();
167     
168             Iterator JavaDoc iterator = fromElements.iterator();
169             for ( int k = 0; iterator.hasNext(); k++ ) {
170                 FromElement fromElement = ( FromElement ) iterator.next();
171     
172                 if ( fromElement.isFetch() ) {
173                     Type type = fromElement.getSelectType();
174                     addCollectionFromElement( fromElement );
175                     if ( type != null ) {
176                         boolean collectionOfElements = fromElement.isCollectionOfValuesOrComponents();
177                         if ( !collectionOfElements ) {
178                             // Add the type to the list of returned sqlResultTypes.
179
fromElement.setIncludeSubclasses( true );
180                             fromElementsForLoad.add( fromElement );
181                             //sqlResultTypeList.add( type );
182
// Generate the select expression.
183
String JavaDoc text = fromElement.renderIdentifierSelect( size, k );
184                             SelectExpressionImpl generatedExpr = ( SelectExpressionImpl ) appender.append( SqlTokenTypes.SELECT_EXPR, text, false );
185                             if ( generatedExpr != null ) {
186                                 generatedExpr.setFromElement( fromElement );
187                             }
188                         }
189                     }
190                 }
191             }
192     
193             // generate id select fragment and then property select fragment for
194
// each expression, just like generateSelectFragments().
195
renderNonScalarSelects( collectSelectExpressions(), fromClause );
196         }
197
198         if ( scalarSelect || getWalker().isShallowQuery() ) {
199             // If there are any scalars (non-entities) selected, render the select column aliases.
200
renderScalarSelects( selectExpressions, fromClause );
201         }
202
203         finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
204     }
205
206     private void finishInitialization(/*ArrayList sqlResultTypeList,*/ ArrayList JavaDoc queryReturnTypeList) {
207         //sqlResultTypes = ( Type[] ) sqlResultTypeList.toArray( new Type[sqlResultTypeList.size()] );
208
queryReturnTypes = ( Type[] ) queryReturnTypeList.toArray( new Type[queryReturnTypeList.size()] );
209         initializeColumnNames();
210         prepared = true;
211     }
212
213     private void initializeColumnNames() {
214         // Generate an 2d array of column names, the first dimension is parallel with the
215
// return types array. The second dimension is the list of column names for each
216
// type.
217

218         // todo: we should really just collect these from the various SelectExpressions, rather than regenerating here
219
columnNames = getSessionFactoryHelper().generateColumnNames( queryReturnTypes );
220     }
221
222     /**
223      * Prepares a derived (i.e., not explicitly defined in the query) select clause.
224      *
225      * @param fromClause The from clause to which this select clause is linked.
226      */

227     public void initializeDerivedSelectClause(FromClause fromClause) throws SemanticException {
228         if ( prepared ) {
229             throw new IllegalStateException JavaDoc( "SelectClause was already prepared!" );
230         }
231         List JavaDoc fromElements = fromClause.getProjectionList();
232
233         ASTAppender appender = new ASTAppender( getASTFactory(), this ); // Get ready to start adding nodes.
234
int size = fromElements.size();
235         ArrayList JavaDoc sqlResultTypeList = new ArrayList JavaDoc( size );
236         ArrayList JavaDoc queryReturnTypeList = new ArrayList JavaDoc( size );
237
238         Iterator JavaDoc iterator = fromElements.iterator();
239         for ( int k = 0; iterator.hasNext(); k++ ) {
240             FromElement fromElement = ( FromElement ) iterator.next();
241             Type type = fromElement.getSelectType();
242
243             addCollectionFromElement( fromElement );
244
245             if ( type != null ) {
246                 boolean collectionOfElements = fromElement.isCollectionOfValuesOrComponents();
247                 if ( !collectionOfElements ) {
248                     if ( !fromElement.isFetch() ) {
249                         // Add the type to the list of returned sqlResultTypes.
250
queryReturnTypeList.add( type );
251                     }
252                     fromElementsForLoad.add( fromElement );
253                     sqlResultTypeList.add( type );
254                     // Generate the select expression.
255
String JavaDoc text = fromElement.renderIdentifierSelect( size, k );
256                     SelectExpressionImpl generatedExpr = ( SelectExpressionImpl ) appender.append( SqlTokenTypes.SELECT_EXPR, text, false );
257                     if ( generatedExpr != null ) {
258                         generatedExpr.setFromElement( fromElement );
259                     }
260                 }
261             }
262         }
263
264         // Get all the select expressions (that we just generated) and render the select.
265
SelectExpression[] selectExpressions = collectSelectExpressions();
266
267         if ( getWalker().isShallowQuery() ) {
268             renderScalarSelects( selectExpressions, fromClause );
269         }
270         else {
271             renderNonScalarSelects( selectExpressions, fromClause );
272         }
273         finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
274     }
275     
276     public static boolean VERSION2_SQL = false;
277
278     private void addCollectionFromElement(FromElement fromElement) {
279         if ( fromElement.isFetch() ) {
280             if ( fromElement.isCollectionJoin() || fromElement.getQueryableCollection() != null ) {
281                 String JavaDoc suffix;
282                 if (collectionFromElements==null) {
283                     collectionFromElements = new ArrayList JavaDoc();
284                     suffix = VERSION2_SQL ? "__" : "0__";
285                 }
286                 else {
287                     suffix = Integer.toString( collectionFromElements.size() ) + "__";
288                 }
289                 collectionFromElements.add( fromElement );
290                 fromElement.setCollectionSuffix( suffix );
291             }
292         }
293     }
294
295     protected AST getFirstSelectExpression() {
296         AST n = getFirstChild();
297         // Skip 'DISTINCT' and 'ALL', so we return the first expression node.
298
while ( n != null && ( n.getType() == SqlTokenTypes.DISTINCT || n.getType() == SqlTokenTypes.ALL ) ) {
299             n = n.getNextSibling();
300         }
301         return n;
302     }
303
304     private boolean isReturnableEntity(SelectExpression selectExpression) throws SemanticException {
305         FromElement fromElement = selectExpression.getFromElement();
306         boolean isFetchOrValueCollection = fromElement != null &&
307                 ( fromElement.isFetch() || fromElement.isCollectionOfValuesOrComponents() );
308         if ( isFetchOrValueCollection ) {
309             return false;
310         }
311         else {
312             return selectExpression.isReturnableEntity();
313         }
314     }
315
316     private void renderScalarSelects(SelectExpression[] se, FromClause currentFromClause) throws SemanticException {
317         if ( !currentFromClause.isSubQuery() ) {
318             for ( int i = 0; i < se.length; i++ ) {
319                 SelectExpression expr = se[i];
320                 expr.setScalarColumnText( i ); // Create SQL_TOKEN nodes for the columns.
321
}
322         }
323     }
324     
325     private void initAliases(SelectExpression[] selectExpressions) {
326         if (constructorNode==null) {
327             aliases = new String JavaDoc[selectExpressions.length];
328             for ( int i=0; i<selectExpressions.length; i++ ) {
329                 String JavaDoc alias = selectExpressions[i].getAlias();
330                 aliases[i] = alias==null ? Integer.toString(i) : alias;
331             }
332         }
333         else {
334             aliases = constructorNode.getAliases();
335         }
336     }
337
338     private void renderNonScalarSelects(SelectExpression[] selectExpressions, FromClause currentFromClause)
339     throws SemanticException {
340         ASTAppender appender = new ASTAppender( getASTFactory(), this );
341         final int size = selectExpressions.length;
342         int nonscalarSize = 0;
343         for ( int i = 0; i < size; i++ ) {
344             if ( !selectExpressions[i].isScalar() ) nonscalarSize++;
345         }
346
347         int j = 0;
348         for ( int i = 0; i < size; i++ ) {
349             if ( !selectExpressions[i].isScalar() ) {
350                 SelectExpression expr = selectExpressions[i];
351                 FromElement fromElement = expr.getFromElement();
352                 if ( fromElement != null ) {
353                     renderNonScalarIdentifiers( fromElement, nonscalarSize, j, expr, appender );
354                     j++;
355                 }
356             }
357         }
358
359         if ( !currentFromClause.isSubQuery() ) {
360             // Generate the property select tokens.
361
int k = 0;
362             for ( int i = 0; i < size; i++ ) {
363                 if ( !selectExpressions[i].isScalar() ) {
364                     FromElement fromElement = selectExpressions[i].getFromElement();
365                     if ( fromElement != null ) {
366                         renderNonScalarProperties( appender, fromElement, nonscalarSize, k );
367                         k++;
368                     }
369                 }
370             }
371         }
372     }
373
374     private void renderNonScalarIdentifiers(FromElement fromElement, int nonscalarSize, int j, SelectExpression expr, ASTAppender appender) {
375         String JavaDoc text = fromElement.renderIdentifierSelect( nonscalarSize, j );
376         if ( !fromElement.getFromClause().isSubQuery() ) {
377             if ( !scalarSelect && !getWalker().isShallowQuery() ) {
378                 //TODO: is this a bit ugly?
379
expr.setText( text );
380             }
381             else {
382                 appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
383             }
384         }
385     }
386
387     private void renderNonScalarProperties(ASTAppender appender, FromElement fromElement, int nonscalarSize, int k) {
388         String JavaDoc text = fromElement.renderPropertySelect( nonscalarSize, k );
389         appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
390         if ( fromElement.getQueryableCollection() != null && fromElement.isFetch() ) {
391             text = fromElement.renderCollectionSelectFragment( nonscalarSize, k );
392             appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
393         }
394         // Look through the FromElement's children to find any collections of values that should be fetched...
395
ASTIterator iter = new ASTIterator( fromElement );
396         while ( iter.hasNext() ) {
397             FromElement child = ( FromElement ) iter.next();
398             if ( child.isCollectionOfValuesOrComponents() && child.isFetch() ) {
399                 // Need a better way to define the suffixes here...
400
text = child.renderValueCollectionSelectFragment( nonscalarSize, nonscalarSize + k );
401                 appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
402             }
403         }
404     }
405
406     public List JavaDoc getCollectionFromElements() {
407         return collectionFromElements;
408     }
409 }
410
Popular Tags