KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > extractor > runtime > QueryFactory


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 XQuark Group.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.extractor.runtime;
24
25 import java.io.StringReader JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.xquark.extractor.algebra.*;
32 import org.xquark.extractor.common.*;
33 import org.xquark.extractor.metadata.MetaDataManager;
34 import org.xquark.extractor.runtime.Query.SQLExecutionInfo;
35 import org.xquark.extractor.sql.AbstractGenSqlVisitor;
36 import org.xquark.extractor.sql.SqlExpression;
37 import org.xquark.xml.xdbc.XMLDBCException;
38 import org.xquark.xml.xdbc.XMLDBCNotSupportedException;
39 import org.xquark.xquery.metadata.VarCounter;
40 import org.xquark.xquery.metadata.resolver.MetadataAccess;
41 import org.xquark.xquery.normalize.DependNode;
42 import org.xquark.xquery.normalize.TransformXQueryExpression;
43 import org.xquark.xquery.parser.*;
44 import org.xquark.xquery.typing.*;
45
46 /**
47  * Produces DBMS-specific queries and embed specific compilation algorithm.
48  */

49 public abstract class QueryFactory {
50
51     private static Log log = LogFactory.getLog(QueryFactory.class);
52     
53     protected XQueryParser _parser = null;
54     protected GenAlgebraVisitor _genAlgebraVisitor = null;
55     protected AlgebraTypeVisitor _algebraTypeVisitor = null;
56     protected RemoveIntermediateProjectVisitor _removeProjectVisitor = null;
57     protected BuildReferredAttributes _brav = null;
58     protected AnalyzePredicateVisitor _apv = null;
59     protected AbstractGenSqlVisitor _genSqlVisitor = null;
60     protected String JavaDoc _baseURI = null;
61     protected MetaDataManager _metadataManager = null;
62     protected MetadataAccess _metadata = null;
63     protected ExtractorStatement _stmt = null;
64
65     /* counters : only one per kind because statement is mono-threaded */
66     protected AliasIDGenerator _attIDProvider = new AliasIDGenerator();
67     protected AliasIDGenerator _relIDProvider = new AliasIDGenerator();
68
69     public QueryFactory(MetaDataManager metadataManager, MetadataAccess metadata) throws XMLDBCException {
70         try {
71             _metadataManager = metadataManager;
72             _metadata = metadata;
73             createParser();
74             createVisitors();
75         } catch (ParseException ex) {
76             throw new XMLDBCException("Can not create statement", ex);
77         } catch (TypeException ex) {
78             throw new XMLDBCException("Can not create statement", ex);
79         }
80     }
81
82 // public Query createQuery(String query) throws XMLDBCException {
83
// return new Query(query, this);
84
// }
85

86     public Query createCompiledQuery(String JavaDoc query) throws XMLDBCException {
87         XQueryModule module = parseXQuery(query);
88         return new Query(query, this, compileQuery(module), module);
89     }
90
91     public void setStatement(ExtractorStatement stmt) {
92         _stmt = stmt;
93     }
94
95     public void setBaseURI(String JavaDoc baseURI) {
96         _baseURI = baseURI;
97     }
98
99     public String JavaDoc getBaseURI() {
100         return _baseURI;
101     }
102
103     protected void createParser() throws ParseException, TypeException {
104         _parser = new XQueryParser(new StringReader JavaDoc("dummy"));
105         _parser.setFactory("org.xquark.xquery.parser.ParserFactory");
106     }
107
108     abstract protected void createVisitors();
109
110
111     public List JavaDoc compileQuery(XQueryModule module) throws XMLDBCException {
112         List JavaDoc exprList = module.getExpressions();
113         List JavaDoc cExpressions = new ArrayList JavaDoc();
114
115         if (exprList != null)
116             for (int i = 0; i < exprList.size(); i++) {
117                 cExpressions.add(compileQuery((XQueryExpression) exprList.get(i)));
118             }
119         return cExpressions;
120     }
121
122     protected Query.CompiledExpression compileQuery(XQueryExpression xExpr) throws XMLDBCException {
123         Query.CompiledExpression retVal = null;
124
125         try {
126             /* transforms XQueryExpression */
127
128             TransformXQueryExpression transformExpr = xExpr.getParentModule().canonize(xExpr, _parser.getTypeVisitor());
129
130             // NOTES:
131
// 1. normalization (no typing considered) AW,
132
// 2. typing (for the case it is lost...),
133
// 3. restructuration (=normalization considering types) LS,
134
// 4. canonization (separates Qmem & Qdb) LS,
135
// 5. typing Qdb (will be removed by LS ?),
136
// 6. get Bound vars on QMem,
137
// 7. patches on Qdb for specific needs of end modules (no agreement could be found).
138

139             // Outcoming Qdbs: Flat, without tags but with let (correlation).
140
// Multiple unrelated queries are not really processed (1 expression for 1 unit for 1 file).
141
// Anyway, has changed in the new version of specs.
142

143             ArrayList JavaDoc idVarList = transformExpr.getIdVarList();
144             List JavaDoc Qdb = transformExpr.getQDB();
145
146             if (log.isDebugEnabled()) {
147                 log.debug("=================< QMEM >=================");
148                 log.debug(transformExpr.getQMEM().toString(true, false, true));
149                 log.debug("=================< QDBs >=================");
150                 for (int i = 0; i < Qdb.size(); i++)
151                     log.debug(((Variable) Qdb.get(i)).getExpression().toString(true, false, true));
152             }
153
154             Query.SQLExecutionInfo jdbcExecInfo = null;
155             ArrayList JavaDoc root = transformExpr.getDependMap();
156
157             if (Qdb.size() > 1) {
158                 if (root != null) { // Multiple expressions imbricated in return with dependant variables.
159
if (root.size() == 1)
160                         jdbcExecInfo = compileSOU((DependNode) root.get(0), idVarList);
161                     else {
162                         // Count the number of id variables for Qdb
163
// Assuming id vars are sorted in the Qdb order...
164
// TODO: put it in the front-end.
165
FLWRExpression xQuery = null;
166                         ArrayList JavaDoc idVarLists = new ArrayList JavaDoc(root.size());
167
168                         int rootIndex = -1;
169                         int idIndex = 0;
170                         ArrayList JavaDoc tmpList = new ArrayList JavaDoc();
171                         for (int i = 0; i < Qdb.size() || idIndex < idVarList.size(); i++) {
172                             xQuery = (FLWRExpression) ((Variable) Qdb.get(i)).getExpression();
173                             if (rootIndex + 1 < root.size() && ((DependNode) root.get(rootIndex + 1)).getExpression() == xQuery) {
174                                 rootIndex++;
175                                 tmpList = new ArrayList JavaDoc();
176                                 idVarLists.add(tmpList);
177                             }
178                             while (idIndex < idVarList.size() && xQuery.getVariables().contains(idVarList.get(idIndex)) && !tmpList.contains(idVarList.get(idIndex))) {
179                                 tmpList.add(idVarList.get(idIndex));
180                                 idIndex++;
181                             }
182                         }
183
184                         jdbcExecInfo = new Query.SQLExecutionInfo();
185                         Query.SQLExecutionInfo subQuery = null;
186                         for (int m = 0; m < root.size(); m++) {
187                             xQuery = (FLWRExpression) ((Variable) Qdb.get(m)).getExpression();
188                             subQuery = compileSOU((DependNode) root.get(m), (ArrayList JavaDoc) idVarLists.get(m));
189                             subQuery.idCount = ((ArrayList JavaDoc) idVarLists.get(m)).size();
190                             jdbcExecInfo.addChild(subQuery);
191                         }
192                     }
193                 } else { // For instance, 2 FLWORs side-by-side in an element constructor.
194

195                     // Count the number of id variables for Qdb
196
// Assuming id vars are sorted in the Qdb order...
197
// TODO: put it in the front-end.
198
FLWRExpression xQuery = null;
199                     int[] idCounts = new int[Qdb.size()];
200                     int idCount = idVarList.size();
201                     int wQdb = 0;
202
203                     for (int i = 0; i < idCount; i++) {
204                         xQuery = (FLWRExpression) ((Variable) Qdb.get(wQdb)).getExpression();
205                         if (xQuery.getVariables().contains(idVarList.get(i)))
206                             idCounts[wQdb]++;
207                         else {
208                             wQdb++;
209                             i--;
210                         }
211                     }
212
213                     jdbcExecInfo = new Query.SQLExecutionInfo();
214                     Query.SQLExecutionInfo subQuery = null;
215                     for (int m = 0; m < Qdb.size(); m++) {
216                         xQuery = (FLWRExpression) ((Variable) Qdb.get(m)).getExpression();
217                         subQuery = compileSingleQDB(xQuery, true);
218                         subQuery.idCount = idCounts[m];
219                         jdbcExecInfo.addChild(subQuery);
220                     }
221                 }
222             } else if (Qdb.size() == 1) { // Base single query : expression with potential let (correlation).
223
jdbcExecInfo = compileSingleQDB(((Variable) Qdb.get(0)).getExpression(), false);
224             }
225             retVal = new Query.CompiledExpression(jdbcExecInfo, transformExpr);
226         } catch (NotSupport ex) {
227             throw new XMLDBCNotSupportedException(ex.getMessage(), ex);
228         } catch (SqlWrapperException ex) {
229             throw new XMLDBCException(ex.getMessage(), ex);
230         } catch (AssertionException ex) {
231             throw new XMLDBCException(MessageLibrary.getMessage("G_INT_LOG_ERR", ex.getMessage()), ex);
232         } catch (ParseException ex) {
233             throw new XMLDBCException(ex.getMessage(), ex);
234         } catch (TypeException ex) {
235             throw new XMLDBCException(ex.getMessage(), ex);
236         } catch (XQueryException ex) {
237             throw new XMLDBCException(ex.getMessage(), ex);
238         }
239         return retVal;
240     }
241
242     /**
243      * Performs recursively Qdb (adding the suitable sorts for SOU) following the
244      * dependency tree and build an homothetic result set tree with columns making
245      * row ids positionned in order for reconstruction to synchronize the SOU
246      * execution.
247      * @param node
248      * @param idVarList
249      * @return
250      * @throws Exception
251      */

252     protected Query.SQLExecutionInfo compileSOU(DependNode node, List JavaDoc idVarList) throws XQueryException, XMLDBCException {
253
254         FLWRExpression xQuery = node.getExpression();
255
256         /* rebuild orderby list */
257         ArrayList JavaDoc newSortExprList = new ArrayList JavaDoc();
258         List JavaDoc varLevels = node.varLevels();
259         List JavaDoc varsOfCurrentLevel = null;
260         List JavaDoc sortExprLevels = node.sortExprLevels();
261         List JavaDoc sortExprsOfCurrentLevel = null;
262         int levelNumber = varLevels.size();
263         for (int i = 0; i < levelNumber; i++) {
264             sortExprsOfCurrentLevel = (List JavaDoc) sortExprLevels.get(i);
265             if (sortExprsOfCurrentLevel != null)
266                 newSortExprList.addAll(sortExprsOfCurrentLevel);
267             varsOfCurrentLevel = (List JavaDoc) varLevels.get(i);
268             newSortExprList.add(new PlaceHolder(varsOfCurrentLevel));
269         }
270         xQuery.setOrderBy(newSortExprList);
271
272         Query.SQLExecutionInfo jdbcExecInfo = compileSingleQDB(xQuery, true);
273
274         /* calculate the position put the ids */
275         jdbcExecInfo.idPosition = calculateIdPosition(node.getExpression().getVariables(), idVarList);
276
277         /* Recursive call for dependent queries */
278         List JavaDoc childQueryList = node.getSons();
279         if (null != childQueryList && !childQueryList.isEmpty()) {
280             for (int i = 0; i < childQueryList.size(); i++) {
281                 jdbcExecInfo.addChild(compileSOU((DependNode) childQueryList.get(i), idVarList));
282             }
283         }
284
285         return jdbcExecInfo;
286     }
287
288     protected Query.SQLExecutionInfo compileSingleQDB(XQueryExpression xQuery, boolean keyNeeded) throws XQueryException, XMLDBCException {
289
290         Expression algebraTree = null;
291
292         /* Algebra tree building */
293         _genAlgebraVisitor.reinit();
294
295         /* Reset counters */
296         _attIDProvider.reset();
297         _relIDProvider.reset();
298
299         if (keyNeeded) { // Used when Sorted Outer Union is needed to identify rows
300
List JavaDoc souArgList = new ArrayList JavaDoc();
301             souArgList.add(xQuery);
302             _genAlgebraVisitor.noticSortedOuterUnion(souArgList);
303         }
304         xQuery.accept(_genAlgebraVisitor);
305         algebraTree = _genAlgebraVisitor.getAlgebraTree();
306
307         // INFO : YS types of visitors : GenAlgebraVisitor (a ParserVisitor impl),
308
// AlgebraVisitor, GenSQLVisitor
309
_removeProjectVisitor.reinit();
310         algebraTree.accept(_removeProjectVisitor);
311
312         algebraTree.accept(_brav);
313
314         /* resolve invalid predicates */
315         _apv.reinit();
316         algebraTree.accept(_apv);
317
318         _algebraTypeVisitor.reinit();
319         algebraTree.accept(_algebraTypeVisitor);
320
321         _genSqlVisitor.reinit();
322         SqlExpression sql = algebraTree.accept(_genSqlVisitor);
323
324         /* Generate string to be ready for prepared statements execution */
325         sql.generateRequestList();
326         return new SQLExecutionInfo(sql, algebraTree.getMapper());
327     }
328
329     public XQueryModule parseXQuery(String JavaDoc xquery) throws XMLDBCException {
330
331         _parser.ReInit(new StringReader JavaDoc(xquery));
332         _parser.setBaseURI(_baseURI);
333
334         XQueryModule result = null;
335         try {
336             // parsing request
337
result = _parser.Start(_metadata, _metadata.getSchemaManager(), _metadata.getModuleManager(), new VarCounter());
338             result.normalize(_parser.getTypeVisitor());
339         } catch (ParseException ex) {
340             throw new XMLDBCException(ex.getMessage(), ex);
341         } catch (XQueryException ex) {
342             throw new XMLDBCException(ex.getMessage(), ex);
343         }
344         _parser.ReInit(new StringReader JavaDoc(xquery));
345
346         return result;
347     }
348
349     /**
350      * Retrieves id position in result set by var name.
351      * @param varList
352      * @param idVarList
353      * @return
354      */

355     private int[] calculateIdPosition(List JavaDoc varList, List JavaDoc idVarList) {
356         int[] retVal = new int[idVarList.size()];
357         int idNum = -1;
358         int idPosition = 0;
359         int idVarIndex = -1;
360
361         Object JavaDoc var = null;
362         for (int i = 0; i < varList.size(); i++) {
363             var = varList.get(i);
364             idPosition = (int) idVarList.indexOf(var);
365             if (-1 != idPosition) {
366                 /* there is a identifier on this */
367                 idNum++;
368                 retVal[idNum] = idPosition;
369             }
370         }
371
372         return retVal;
373     }
374
375     protected class AliasIDGenerator implements IDProvider {
376         private int counter = 0;
377
378         public String JavaDoc getID() {
379             return String.valueOf(counter++);
380         }
381
382         public void reset() {
383             counter = 0;
384         }
385     }
386
387     protected class TempTableIDGenerator implements IDProvider {
388         private int counter = 0;
389
390         public TempTableIDGenerator() {
391         }
392
393         public String JavaDoc getID() {
394             return String.valueOf(_stmt.getStatementId()) + '_' + String.valueOf(counter++);
395         }
396
397         public void reset() {
398             counter = 0;
399         }
400     }
401 }
402
Popular Tags