KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > hql > classic > FromParser


1 //$Id: FromParser.java,v 1.2 2005/02/13 11:50:03 oneovthafew Exp $
2
package org.hibernate.hql.classic;
3
4 import org.hibernate.QueryException;
5 import org.hibernate.hql.QueryTranslator;
6 import org.hibernate.persister.entity.Queryable;
7 import org.hibernate.sql.JoinFragment;
8
9 import java.util.HashMap JavaDoc;
10 import java.util.Map JavaDoc;
11
12 /**
13  * Parses the from clause of a hibernate query, looking for tables and
14  * aliases for the SQL query.
15  */

16
17 public class FromParser implements Parser {
18
19     private final PathExpressionParser peParser = new FromPathExpressionParser();
20     private String JavaDoc entityName;
21     private String JavaDoc alias;
22     private boolean afterIn;
23     private boolean afterAs;
24     private boolean afterClass;
25     private boolean expectingJoin;
26     private boolean expectingIn;
27     private boolean expectingAs;
28     private boolean afterJoinType;
29     private int joinType;
30     private boolean afterFetch;
31
32     private static final int NONE = -666;
33
34     private static final Map JavaDoc JOIN_TYPES = new HashMap JavaDoc();
35
36     static {
37         JOIN_TYPES.put( "left", new Integer JavaDoc( JoinFragment.LEFT_OUTER_JOIN ) );
38         JOIN_TYPES.put( "right", new Integer JavaDoc( JoinFragment.RIGHT_OUTER_JOIN ) );
39         JOIN_TYPES.put( "full", new Integer JavaDoc( JoinFragment.FULL_JOIN ) );
40         JOIN_TYPES.put( "inner", new Integer JavaDoc( JoinFragment.INNER_JOIN ) );
41     }
42
43     public void token(String JavaDoc token, QueryTranslatorImpl q) throws QueryException {
44
45         // start by looking for HQL keywords...
46
String JavaDoc lcToken = token.toLowerCase();
47         if ( lcToken.equals( "," ) ) {
48             if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: ," );
49             expectingJoin = false;
50             expectingAs = false;
51         }
52         else if ( lcToken.equals( "join" ) ) {
53             if ( !afterJoinType ) {
54                 if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: join" );
55                 // inner joins can be abbreviated to 'join'
56
joinType = JoinFragment.INNER_JOIN;
57                 expectingJoin = false;
58                 expectingAs = false;
59             }
60             else {
61                 afterJoinType = false;
62             }
63         }
64         else if ( lcToken.equals( "fetch" ) ) {
65             if ( q.isShallowQuery() ) throw new QueryException( QueryTranslator.ERROR_CANNOT_FETCH_WITH_ITERATE );
66             if ( joinType == NONE ) throw new QueryException( "unexpected token: fetch" );
67             if ( joinType == JoinFragment.FULL_JOIN || joinType == JoinFragment.RIGHT_OUTER_JOIN ) {
68                 throw new QueryException( "fetch may only be used with inner join or left outer join" );
69             }
70             afterFetch = true;
71         }
72         else if ( lcToken.equals( "outer" ) ) {
73             // 'outer' is optional and is ignored
74
if ( !afterJoinType ||
75                     ( joinType != JoinFragment.LEFT_OUTER_JOIN && joinType != JoinFragment.RIGHT_OUTER_JOIN )
76             ) {
77                 throw new QueryException( "unexpected token: outer" );
78             }
79         }
80         else if ( JOIN_TYPES.containsKey( lcToken ) ) {
81             if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: " + token );
82             joinType = ( ( Integer JavaDoc ) JOIN_TYPES.get( lcToken ) ).intValue();
83             afterJoinType = true;
84             expectingJoin = false;
85             expectingAs = false;
86         }
87         else if ( lcToken.equals( "class" ) ) {
88             if ( !afterIn ) throw new QueryException( "unexpected token: class" );
89             if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
90             afterClass = true;
91         }
92         else if ( lcToken.equals( "in" ) ) {
93             if ( !expectingIn ) throw new QueryException( "unexpected token: in" );
94             afterIn = true;
95             expectingIn = false;
96         }
97         else if ( lcToken.equals( "as" ) ) {
98             if ( !expectingAs ) throw new QueryException( "unexpected token: as" );
99             afterAs = true;
100             expectingAs = false;
101         }
102         else {
103
104             if ( afterJoinType ) throw new QueryException( "join expected: " + token );
105             if ( expectingJoin ) throw new QueryException( "unexpected token: " + token );
106             if ( expectingIn ) throw new QueryException( "in expected: " + token );
107
108             // now anything that is not a HQL keyword
109

110             if ( afterAs || expectingAs ) {
111
112                 // (AS is always optional, for consistency with SQL/OQL)
113

114                 // process the "new" HQL style where aliases are assigned
115
// _after_ the class name or path expression ie. using
116
// the AS construction
117

118                 if ( entityName != null ) {
119                     q.setAliasName( token, entityName );
120                 }
121                 else {
122                     throw new QueryException( "unexpected: as " + token );
123                 }
124                 afterAs = false;
125                 expectingJoin = true;
126                 expectingAs = false;
127                 entityName = null;
128
129             }
130             else if ( afterIn ) {
131
132                 // process the "old" HQL style where aliases appear _first_
133
// ie. using the IN or IN CLASS constructions
134

135                 if ( alias == null ) throw new QueryException( "alias not specified for: " + token );
136
137                 if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
138
139                 if ( afterClass ) {
140                     // treat it as a classname
141
Queryable p = q.getEntityPersisterUsingImports( token );
142                     if ( p == null ) throw new QueryException( "persister not found: " + token );
143                     q.addFromClass( alias, p );
144                 }
145                 else {
146                     // treat it as a path expression
147
peParser.setJoinType( JoinFragment.INNER_JOIN );
148                     peParser.setUseThetaStyleJoin( true );
149                     ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
150                     if ( !peParser.isCollectionValued() ) throw new QueryException( "path expression did not resolve to collection: " + token );
151                     String JavaDoc nm = peParser.addFromCollection( q );
152                     q.setAliasName( alias, nm );
153                 }
154
155                 alias = null;
156                 afterIn = false;
157                 afterClass = false;
158                 expectingJoin = true;
159             }
160             else {
161
162                 // handle a path expression or class name that
163
// appears at the start, in the "new" HQL
164
// style or an alias that appears at the start
165
// in the "old" HQL style
166

167                 Queryable p = q.getEntityPersisterUsingImports( token );
168                 if ( p != null ) {
169                     // starts with the name of a mapped class (new style)
170
if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
171                     entityName = q.createNameFor( p.getEntityName() );
172                     q.addFromClass( entityName, p );
173                     expectingAs = true;
174                 }
175                 else if ( token.indexOf( '.' ) < 0 ) {
176                     // starts with an alias (old style)
177
// semi-bad thing about this: can't re-alias another alias.....
178
alias = token;
179                     expectingIn = true;
180                 }
181                 else {
182
183                     // starts with a path expression (new style)
184

185                     // force HQL style: from Person p inner join p.cars c
186
//if (joinType==NONE) throw new QueryException("path expression must be preceded by full, left, right or inner join");
187

188                     //allow ODMG OQL style: from Person p, p.cars c
189
if ( joinType != NONE ) {
190                         peParser.setJoinType( joinType );
191                     }
192                     else {
193                         peParser.setJoinType( JoinFragment.INNER_JOIN );
194                     }
195                     peParser.setUseThetaStyleJoin( q.isSubquery() );
196
197                     ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
198                     entityName = peParser.addFromAssociation( q );
199
200                     joinType = NONE;
201                     peParser.setJoinType( JoinFragment.INNER_JOIN );
202
203                     if ( afterFetch ) {
204                         peParser.fetch( q, entityName );
205                         afterFetch = false;
206                     }
207
208                     expectingAs = true;
209
210                 }
211             }
212         }
213
214     }
215
216     public void start(QueryTranslatorImpl q) {
217         entityName = null;
218         alias = null;
219         afterIn = false;
220         afterAs = false;
221         afterClass = false;
222         expectingJoin = false;
223         expectingIn = false;
224         expectingAs = false;
225         joinType = NONE;
226     }
227
228     public void end(QueryTranslatorImpl q) {
229     }
230
231 }
232
Popular Tags