View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.jcr;
25  
26  import java.math.BigDecimal;
27  import java.util.Comparator;
28  import java.util.Map;
29  import java.util.Set;
30  import javax.jcr.AccessDeniedException;
31  import javax.jcr.Node;
32  import javax.jcr.NodeIterator;
33  import javax.jcr.PropertyType;
34  import javax.jcr.RepositoryException;
35  import javax.jcr.Value;
36  import javax.jcr.ValueFactory;
37  import javax.jcr.query.InvalidQueryException;
38  import javax.jcr.query.Query;
39  import javax.jcr.query.QueryManager;
40  import javax.jcr.version.VersionException;
41  import net.jcip.annotations.Immutable;
42  import org.modeshape.common.text.ParsingException;
43  import org.modeshape.common.util.CheckArg;
44  import org.modeshape.graph.ExecutionContext;
45  import org.modeshape.graph.Location;
46  import org.modeshape.graph.property.Name;
47  import org.modeshape.graph.property.NamespaceRegistry;
48  import org.modeshape.graph.property.Path;
49  import org.modeshape.graph.property.ValueFactories;
50  import org.modeshape.graph.query.QueryResults;
51  import org.modeshape.graph.query.model.QueryCommand;
52  import org.modeshape.graph.query.model.TypeSystem;
53  import org.modeshape.graph.query.model.Visitors;
54  import org.modeshape.graph.query.parse.QueryParser;
55  import org.modeshape.graph.query.plan.PlanHints;
56  import org.modeshape.graph.query.validate.Schemata;
57  import org.modeshape.jcr.JcrRepository.QueryLanguage;
58  import org.modeshape.jcr.api.query.qom.QueryObjectModelFactory;
59  import org.modeshape.jcr.query.JcrQuery;
60  import org.modeshape.jcr.query.JcrQueryContext;
61  import org.modeshape.jcr.query.JcrSearch;
62  import org.modeshape.jcr.query.JcrTypeSystem;
63  import org.modeshape.jcr.query.qom.JcrQueryObjectModel;
64  import org.modeshape.jcr.query.qom.JcrQueryObjectModelFactory;
65  import org.modeshape.jcr.query.qom.JcrSelectQuery;
66  import org.modeshape.jcr.query.qom.JcrSetQuery;
67  import org.modeshape.jcr.query.qom.JcrSetQueryObjectModel;
68  
69  /**
70   * Place-holder implementation of {@link QueryManager} interface.
71   */
72  @Immutable
73  class JcrQueryManager implements QueryManager {
74  
75      public static final int MAXIMUM_RESULTS_FOR_FULL_TEXT_SEARCH_QUERIES = Integer.MAX_VALUE;
76  
77      private final JcrSession session;
78      private final JcrQueryContext context;
79      private final JcrTypeSystem typeSystem;
80      private final QueryObjectModelFactory factory;
81  
82      JcrQueryManager( JcrSession session ) {
83          this.session = session;
84          this.context = new SessionQueryContext(this.session);
85          this.typeSystem = new SessionTypeSystem(this.session);
86          this.factory = new JcrQueryObjectModelFactory(this.context);
87      }
88  
89      /**
90       * {@inheritDoc}
91       * 
92       * @see javax.jcr.query.QueryManager#getQOMFactory()
93       */
94      @Override
95      public javax.jcr.query.qom.QueryObjectModelFactory getQOMFactory() {
96          return factory;
97      }
98  
99      /**
100      * {@inheritDoc}
101      * 
102      * @see javax.jcr.query.QueryManager#createQuery(java.lang.String, java.lang.String)
103      */
104     public Query createQuery( String statement,
105                               String language ) throws InvalidQueryException, RepositoryException {
106         CheckArg.isNotNull(statement, "statement");
107         CheckArg.isNotNull(language, "language");
108         return createQuery(statement, language, null);
109     }
110 
111     /**
112      * Creates a new JCR {@link Query} by specifying the query expression itself, the language in which the query is stated, the
113      * {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be a
114      * string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
115      * 
116      * @param expression the original query expression as supplied by the client; may not be null
117      * @param language the language in which the expression is represented; may not be null
118      * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
119      * @return query the JCR query object; never null
120      * @throws InvalidQueryException if expression is invalid or language is unsupported
121      * @throws RepositoryException if the session is no longer live
122      */
123     @SuppressWarnings( "deprecation" )
124     public Query createQuery( String expression,
125                               String language,
126                               Path storedAtPath ) throws InvalidQueryException, RepositoryException {
127         session.checkLive();
128         // Look for a parser for the specified language ...
129         QueryParser parser = session.repository().queryParsers().getParserFor(language);
130         if (parser == null) {
131             Set<String> languages = session.repository().queryParsers().getLanguages();
132             throw new InvalidQueryException(JcrI18n.invalidQueryLanguage.text(language, languages));
133         }
134         if (parser.getLanguage().equals(FullTextSearchParser.LANGUAGE)) {
135             // This is a full-text search ...
136             return new JcrSearch(this.context, expression, parser.getLanguage(), storedAtPath);
137         }
138         try {
139             // Parsing must be done now ...
140             QueryCommand command = parser.parseQuery(expression, typeSystem);
141             if (command == null) {
142                 // The query is not well-formed and cannot be parsed ...
143                 throw new InvalidQueryException(JcrI18n.queryCannotBeParsedUsingLanguage.text(language, expression));
144             }
145             PlanHints hints = new PlanHints();
146             hints.showPlan = true;
147             hints.hasFullTextSearch = true; // always include the score
148             if (Query.XPATH.equals(language)) {
149                 hints.validateColumnExistance = false;
150             }
151             return resultWith(expression, parser.getLanguage(), command, hints, storedAtPath);
152         } catch (ParsingException e) {
153             // The query is not well-formed and cannot be parsed ...
154             String reason = e.getMessage();
155             throw new InvalidQueryException(JcrI18n.queryCannotBeParsedUsingLanguage.text(language, expression, reason));
156         } catch (org.modeshape.graph.query.parse.InvalidQueryException e) {
157             // The query was parsed, but there is an error in the query
158             String reason = e.getMessage();
159             throw new InvalidQueryException(JcrI18n.queryInLanguageIsNotValid.text(language, expression, reason));
160         }
161     }
162 
163     /**
164      * Creates a new JCR {@link Query} by specifying the query expression itself, the language in which the query is stated, the
165      * {@link QueryCommand} representation. This method is more efficient than {@link #createQuery(String, String, Path)} if the
166      * QueryCommand is created directly.
167      * 
168      * @param command the query command; may not be null
169      * @return query the JCR query object; never null
170      * @throws InvalidQueryException if expression is invalid or language is unsupported
171      * @throws RepositoryException if the session is no longer live
172      */
173     public Query createQuery( QueryCommand command ) throws InvalidQueryException, RepositoryException {
174         session.checkLive();
175         if (command == null) {
176             // The query is not well-formed and cannot be parsed ...
177             throw new InvalidQueryException(JcrI18n.queryInLanguageIsNotValid.text(QueryLanguage.JCR_SQL2, command));
178         }
179         // Produce the expression string ...
180         String expression = Visitors.readable(command);
181         try {
182             // Parsing must be done now ...
183             PlanHints hints = new PlanHints();
184             hints.showPlan = true;
185             hints.hasFullTextSearch = true; // always include the score
186             return resultWith(expression, QueryLanguage.JCR_SQL2, command, hints, null);
187         } catch (org.modeshape.graph.query.parse.InvalidQueryException e) {
188             // The query was parsed, but there is an error in the query
189             String reason = e.getMessage();
190             throw new InvalidQueryException(JcrI18n.queryInLanguageIsNotValid.text(QueryLanguage.JCR_SQL2, expression, reason));
191         }
192     }
193 
194     /**
195      * {@inheritDoc}
196      * 
197      * @see javax.jcr.query.QueryManager#getQuery(javax.jcr.Node)
198      */
199     public Query getQuery( Node node ) throws InvalidQueryException, RepositoryException {
200         AbstractJcrNode jcrNode = CheckArg.getInstanceOf(node, AbstractJcrNode.class, "node");
201 
202         // Check the type of the node ...
203         JcrNodeType nodeType = jcrNode.getPrimaryNodeType();
204         if (!nodeType.getInternalName().equals(JcrNtLexicon.QUERY)) {
205             NamespaceRegistry registry = session.getExecutionContext().getNamespaceRegistry();
206             throw new InvalidQueryException(JcrI18n.notStoredQuery.text(jcrNode.path().getString(registry)));
207         }
208 
209         // These are both mandatory properties for nodes of nt:query
210         String statement = jcrNode.getProperty(JcrLexicon.STATEMENT).getString();
211         String language = jcrNode.getProperty(JcrLexicon.LANGUAGE).getString();
212 
213         return createQuery(statement, language, jcrNode.path());
214     }
215 
216     /**
217      * {@inheritDoc}
218      * 
219      * @see javax.jcr.query.QueryManager#getSupportedQueryLanguages()
220      */
221     public String[] getSupportedQueryLanguages() {
222         // Make a defensive copy ...
223         Set<String> languages = session.repository().queryParsers().getLanguages();
224         return languages.toArray(new String[languages.size()]);
225     }
226 
227     protected Query resultWith( String expression,
228                                 String language,
229                                 QueryCommand command,
230                                 PlanHints hints,
231                                 Path storedAtPath ) {
232         if (command instanceof JcrSelectQuery) {
233             JcrSelectQuery query = (JcrSelectQuery)command;
234             return new JcrQueryObjectModel(context, expression, language, query, hints, storedAtPath);
235         }
236         if (command instanceof JcrSetQuery) {
237             JcrSetQuery query = (JcrSetQuery)command;
238             return new JcrSetQueryObjectModel(this.context, expression, language, query, hints, storedAtPath);
239         }
240         return new JcrQuery(context, expression, language, command, hints, storedAtPath);
241     }
242 
243     // protected void checkForProblems( Problems problems ) throws RepositoryException {
244     // if (problems.hasErrors()) {
245     // // Build a message with the problems ...
246     // StringBuilder msg = new StringBuilder();
247     // for (Problem problem : problems) {
248     // if (problem.getStatus() != Status.ERROR) continue;
249     // msg.append(problem.getMessageString()).append("\n");
250     // }
251     // throw new RepositoryException(msg.toString());
252     // }
253     // }
254     //
255     // @NotThreadSafe
256     // protected static abstract class AbstractQuery implements Query {
257     // protected final JcrSession session;
258     // protected final String language;
259     // protected final String statement;
260     // private Path storedAtPath;
261     //
262     // /**
263     // * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated,
264     // * the {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be
265     // * a string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
266     // *
267     // * @param session the session that was used to create this query and that will be used to execute this query; may not be
268     // * null
269     // * @param statement the original statement as supplied by the client; may not be null
270     // * @param language the language obtained from the {@link QueryParser}; may not be null
271     // * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
272     // */
273     // protected AbstractQuery( JcrSession session,
274     // String statement,
275     // String language,
276     // Path storedAtPath ) {
277     // assert session != null;
278     // assert statement != null;
279     // assert language != null;
280     // this.session = session;
281     // this.language = language;
282     // this.statement = statement;
283     // this.storedAtPath = storedAtPath;
284     // }
285     //
286     // protected final JcrSession session() {
287     // return this.session;
288     // }
289     //
290     // /**
291     // * {@inheritDoc}
292     // *
293     // * @see javax.jcr.query.Query#getLanguage()
294     // */
295     // public String getLanguage() {
296     // return language;
297     // }
298     //
299     // /**
300     // * {@inheritDoc}
301     // *
302     // * @see javax.jcr.query.Query#getStatement()
303     // */
304     // public String getStatement() {
305     // return statement;
306     // }
307     //
308     // /**
309     // * {@inheritDoc}
310     // *
311     // * @see javax.jcr.query.Query#getStoredQueryPath()
312     // */
313     // public String getStoredQueryPath() throws ItemNotFoundException {
314     // if (storedAtPath == null) {
315     // throw new ItemNotFoundException(JcrI18n.notStoredQuery.text());
316     // }
317     // return storedAtPath.getString(session.getExecutionContext().getNamespaceRegistry());
318     // }
319     //
320     // /**
321     // * {@inheritDoc}
322     // *
323     // * @see javax.jcr.query.Query#storeAsNode(java.lang.String)
324     // */
325     // public Node storeAsNode( String absPath ) throws PathNotFoundException, ConstraintViolationException, RepositoryException {
326     // session.checkLive();
327     // NamespaceRegistry namespaces = this.session.namespaces();
328     //
329     // Path path;
330     // try {
331     // path = session.getExecutionContext().getValueFactories().getPathFactory().create(absPath);
332     // } catch (IllegalArgumentException iae) {
333     // throw new RepositoryException(JcrI18n.invalidPathParameter.text("absPath", absPath));
334     // }
335     // Path parentPath = path.getParent();
336     //
337     // Node parentNode = session.getNode(parentPath);
338     //
339     // if (!parentNode.isCheckedOut()) {
340     // throw new VersionException(JcrI18n.nodeIsCheckedIn.text(parentNode.getPath()));
341     // }
342     //
343     // Node queryNode = parentNode.addNode(path.relativeTo(parentPath).getString(namespaces),
344     // JcrNtLexicon.QUERY.getString(namespaces));
345     //
346     // queryNode.setProperty(JcrLexicon.LANGUAGE.getString(namespaces), this.language);
347     // queryNode.setProperty(JcrLexicon.STATEMENT.getString(namespaces), this.statement);
348     //
349     // this.storedAtPath = path;
350     //
351     // return queryNode;
352     // }
353     //
354     // protected void checkForProblems( Problems problems ) throws RepositoryException {
355     // if (problems.hasErrors()) {
356     // // Build a message with the problems ...
357     // StringBuilder msg = new StringBuilder();
358     // for (Problem problem : problems) {
359     // if (problem.getStatus() != Status.ERROR) continue;
360     // msg.append(problem.getMessageString()).append("\n");
361     // }
362     // throw new RepositoryException(msg.toString());
363     // }
364     // }
365     // }
366     //
367     // /**
368     // * Implementation of {@link Query} that represents a {@link QueryCommand} query.
369     // */
370     // @NotThreadSafe
371     // protected static class JcrQuery extends AbstractQuery {
372     // private final QueryCommand query;
373     // private final PlanHints hints;
374     // private final Map<String, Object> variables;
375     //
376     // /**
377     // * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated,
378     // * the {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be
379     // * a string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
380     // *
381     // * @param session the session that was used to create this query and that will be used to execute this query; may not be
382     // * null
383     // * @param statement the original statement as supplied by the client; may not be null
384     // * @param language the language obtained from the {@link QueryParser}; may not be null
385     // * @param query the parsed query representation; may not be null
386     // * @param hints any hints that are to be used; may be null if there are no hints
387     // * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
388     // */
389     // protected JcrQuery( JcrSession session,
390     // String statement,
391     // String language,
392     // QueryCommand query,
393     // PlanHints hints,
394     // Path storedAtPath ) {
395     // super(session, statement, language, storedAtPath);
396     // assert query != null;
397     // this.query = query;
398     // this.hints = hints;
399     // this.variables = null;
400     // }
401     //
402     // /**
403     // * Get the underlying and immutable Abstract Query Model representation of this query.
404     // *
405     // * @return the AQM representation; never null
406     // */
407     // public QueryCommand getAbstractQueryModel() {
408     // return query;
409     // }
410     //
411     // /**
412     // * {@inheritDoc}
413     // *
414     // * @see javax.jcr.query.Query#execute()
415     // */
416     // public QueryResult execute() throws RepositoryException {
417     // session.checkLive();
418     // // Submit immediately to the workspace graph ...
419     // Schemata schemata = session.workspace().nodeTypeManager().schemata();
420     // QueryResults result = session.repository().queryManager().query(session.workspace().getName(),
421     // query,
422     // schemata,
423     // hints,
424     // variables);
425     // checkForProblems(result.getProblems());
426     // if (Query.XPATH.equals(language)) {
427     // return new XPathQueryResult(session, statement, result, schemata);
428     // } else if (Query.SQL.equals(language)) {
429     // return new JcrSqlQueryResult(session, statement, result, schemata);
430     // }
431     // return new JcrQueryResult(session, statement, result, schemata);
432     // }
433     //
434     // /**
435     // * {@inheritDoc}
436     // *
437     // * @see java.lang.Object#toString()
438     // */
439     // @Override
440     // public String toString() {
441     // return language + " -> " + statement + "\n" + StringUtil.createString(' ', Math.min(language.length() - 3, 0))
442     // + "AQM -> " + query;
443     // }
444     //
445     // @Override
446     // public void bindValue( String varName,
447     // Value value ) throws IllegalArgumentException, RepositoryException {
448     // throw new UnsupportedRepositoryOperationException();
449     // }
450     //
451     // @Override
452     // public String[] getBindVariableNames() throws RepositoryException {
453     // throw new UnsupportedRepositoryOperationException();
454     // }
455     //
456     // @Override
457     // public void setLimit( long limit ) {
458     // throw new IllegalStateException();
459     // }
460     //
461     // @Override
462     // public void setOffset( long offset ) {
463     // throw new IllegalStateException();
464     // }
465     // }
466     //
467     // @NotThreadSafe
468     // protected static class JcrSearch extends AbstractQuery {
469     //
470     // /**
471     // * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated,
472     // * the {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be
473     // * a string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
474     // *
475     // * @param session the session that was used to create this query and that will be used to execute this query; may not be
476     // * null
477     // * @param statement the original statement as supplied by the client; may not be null
478     // * @param language the language obtained from the {@link QueryParser}; may not be null
479     // * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
480     // */
481     // protected JcrSearch( JcrSession session,
482     // String statement,
483     // String language,
484     // Path storedAtPath ) {
485     // super(session, statement, language, storedAtPath);
486     // }
487     //
488     // /**
489     // * {@inheritDoc}
490     // *
491     // * @see javax.jcr.query.Query#execute()
492     // */
493     // public QueryResult execute() throws RepositoryException {
494     // // Submit immediately to the workspace graph ...
495     // Schemata schemata = session.workspace().nodeTypeManager().schemata();
496     // QueryResults result = session.repository().queryManager().search(session.workspace().getName(),
497     // statement,
498     // MAXIMUM_RESULTS_FOR_FULL_TEXT_SEARCH_QUERIES,
499     // 0);
500     // checkForProblems(result.getProblems());
501     // return new JcrQueryResult(session, statement, result, schemata);
502     // }
503     //
504     // /**
505     // * {@inheritDoc}
506     // *
507     // * @see java.lang.Object#toString()
508     // */
509     // @Override
510     // public String toString() {
511     // return language + " -> " + statement;
512     // }
513     //
514     // @Override
515     // public void bindValue( String varName,
516     // Value value ) throws IllegalArgumentException, RepositoryException {
517     // throw new UnsupportedRepositoryOperationException();
518     // }
519     //
520     // @Override
521     // public String[] getBindVariableNames() throws RepositoryException {
522     // throw new UnsupportedRepositoryOperationException();
523     // }
524     //
525     // @Override
526     // public void setLimit( long limit ) {
527     // throw new IllegalStateException();
528     // }
529     //
530     // @Override
531     // public void setOffset( long offset ) {
532     // throw new IllegalStateException();
533     // }
534     // }
535     //
536     // protected static final String JCR_SCORE_COLUMN_NAME = "jcr:score";
537     // protected static final String JCR_PATH_COLUMN_NAME = "jcr:path";
538     //
539     // /**
540     // * The results of a query. This is not thread-safe because it relies upon JcrSession, which is not thread-safe. Also,
541     // although
542     // * the results of a query never change, the objects returned by the iterators may vary if the session information changes.
543     // */
544     // @NotThreadSafe
545     // public static class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query.QueryResult {
546     // protected final JcrSession session;
547     // protected final QueryResults results;
548     // protected final Schemata schemata;
549     // protected final String queryStatement;
550     // private List<String> columnTypes;
551     // private List<String> columnTables;
552     //
553     // protected JcrQueryResult( JcrSession session,
554     // String query,
555     // QueryResults graphResults,
556     // Schemata schemata ) {
557     // this.session = session;
558     // this.results = graphResults;
559     // this.schemata = schemata;
560     // this.queryStatement = query;
561     // assert this.session != null;
562     // assert this.results != null;
563     // assert this.schemata != null;
564     // assert this.queryStatement != null;
565     // }
566     //
567     // protected QueryResults results() {
568     // return results;
569     // }
570     //
571     // public List<String> getColumnNameList() {
572     // return results.getColumns().getColumnNames();
573     // }
574     //
575     // /**
576     // * {@inheritDoc}
577     // *
578     // * @see javax.jcr.query.QueryResult#getColumnNames()
579     // */
580     // public String[] getColumnNames() /*throws RepositoryException*/{
581     // List<String> names = getColumnNameList();
582     // return names.toArray(new String[names.size()]); // make a defensive copy ...
583     // }
584     //
585     // /**
586     // * {@inheritDoc}
587     // *
588     // * @see org.modeshape.jcr.api.query.QueryResult#getColumnTypes()
589     // */
590     // @Override
591     // public String[] getColumnTypes() {
592     // if (columnTypes == null) {
593     // // Discover the types ...
594     // columnTypes = loadColumnTypes(results.getColumns());
595     // }
596     // return columnTypes.toArray(new String[columnTypes.size()]);
597     // }
598     //
599     // protected List<String> loadColumnTypes( Columns columns ) {
600     // List<String> types = new ArrayList<String>(columns.getColumnCount());
601     // for (Column column : columns) {
602     // String typeName = null;
603     // Table table = schemata.getTable(column.selectorName());
604     // if (table != null) {
605     // Schemata.Column typedColumn = table.getColumn(column.propertyName());
606     // typeName = typedColumn.getPropertyType();
607     // }
608     // if (typeName == null) {
609     // // Might be fabricated column, so just assume string ...
610     // typeName = PropertyType.nameFromValue(PropertyType.STRING);
611     // }
612     // types.add(typeName);
613     // }
614     //
615     // return types;
616     // }
617     //
618     // /**
619     // * {@inheritDoc}
620     // *
621     // * @see org.modeshape.jcr.api.query.QueryResult#getSelectorNames()
622     // */
623     // @Override
624     // public String[] getSelectorNames() {
625     // if (columnTables == null) {
626     // // Discover the types ...
627     // Columns columns = results.getColumns();
628     // List<String> tables = new ArrayList<String>(columns.getColumnCount());
629     // for (Column column : columns) {
630     // String tableName = "";
631     // Table table = schemata.getTable(column.selectorName());
632     // if (table != null) tableName = table.getName().name();
633     // tables.add(tableName);
634     // }
635     // columnTables = tables;
636     // }
637     // return columnTables.toArray(new String[columnTables.size()]);
638     // }
639     //
640     // /**
641     // * {@inheritDoc}
642     // *
643     // * @see javax.jcr.query.QueryResult#getNodes()
644     // */
645     // public NodeIterator getNodes() throws RepositoryException {
646     // // Find all of the nodes in the results. We have to do this pre-emptively, since this
647     // // is the only method to throw RepositoryException ...
648     // final int numRows = results.getRowCount();
649     // if (numRows == 0) return new JcrEmptyNodeIterator();
650     //
651     // final List<AbstractJcrNode> nodes = new ArrayList<AbstractJcrNode>(numRows);
652     // final String selectorName = results.getColumns().getSelectorNames().get(0);
653     // final int locationIndex = results.getColumns().getLocationIndex(selectorName);
654     // for (Object[] tuple : results.getTuples()) {
655     // Location location = (Location)tuple[locationIndex];
656     // if (!session.wasRemovedInSession(location)) {
657     // nodes.add(session.getNode(location.getPath()));
658     // }
659     // }
660     // return new QueryResultNodeIterator(nodes);
661     // }
662     //
663     // /**
664     // * {@inheritDoc}
665     // *
666     // * @see javax.jcr.query.QueryResult#getRows()
667     // */
668     // public RowIterator getRows() /*throws RepositoryException*/{
669     // // We can actually delay the loading of the nodes until the rows are accessed ...
670     // final int numRows = results.getRowCount();
671     // final List<Object[]> tuples = results.getTuples();
672     // if (results.getColumns().getLocationCount() == 1) {
673     // return new SingleSelectorQueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
674     // }
675     // return new QueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
676     // }
677     //
678     // /**
679     // * Get a description of the query plan, if requested.
680     // *
681     // * @return the query plan, or null if the plan was not requested
682     // */
683     // public String getPlan() {
684     // return results.getPlan();
685     // }
686     //
687     // /**
688     // * {@inheritDoc}
689     // *
690     // * @see java.lang.Object#toString()
691     // */
692     // @Override
693     // public String toString() {
694     // return results.toString();
695     // }
696     // }
697     //
698     // /**
699     // * The {@link NodeIterator} implementation returned by the {@link JcrQueryResult}.
700     // *
701     // * @see JcrQueryResult#getNodes()
702     // */
703     // @NotThreadSafe
704     // protected static class QueryResultNodeIterator implements NodeIterator {
705     // private final Iterator<? extends Node> nodes;
706     // private final int size;
707     // private long position = 0L;
708     //
709     // protected QueryResultNodeIterator( List<? extends Node> nodes ) {
710     // this.nodes = nodes.iterator();
711     // this.size = nodes.size();
712     // }
713     //
714     // /**
715     // * {@inheritDoc}
716     // *
717     // * @see javax.jcr.NodeIterator#nextNode()
718     // */
719     // public Node nextNode() {
720     // Node node = nodes.next();
721     // ++position;
722     // return node;
723     // }
724     //
725     // /**
726     // * {@inheritDoc}
727     // *
728     // * @see javax.jcr.RangeIterator#getPosition()
729     // */
730     // public long getPosition() {
731     // return position;
732     // }
733     //
734     // /**
735     // * {@inheritDoc}
736     // *
737     // * @see javax.jcr.RangeIterator#getSize()
738     // */
739     // public long getSize() {
740     // return size;
741     // }
742     //
743     // /**
744     // * {@inheritDoc}
745     // *
746     // * @see javax.jcr.RangeIterator#skip(long)
747     // */
748     // public void skip( long skipNum ) {
749     // for (long i = 0L; i != skipNum; ++i)
750     // nextNode();
751     // }
752     //
753     // /**
754     // * {@inheritDoc}
755     // *
756     // * @see java.util.Iterator#hasNext()
757     // */
758     // public boolean hasNext() {
759     // return nodes.hasNext();
760     // }
761     //
762     // /**
763     // * {@inheritDoc}
764     // *
765     // * @see java.util.Iterator#next()
766     // */
767     // public Object next() {
768     // return nextNode();
769     // }
770     //
771     // /**
772     // * {@inheritDoc}
773     // *
774     // * @see java.util.Iterator#remove()
775     // */
776     // public void remove() {
777     // throw new UnsupportedOperationException();
778     // }
779     // }
780     //
781     // /**
782     // * The {@link RowIterator} implementation returned by the {@link JcrQueryResult}.
783     // *
784     // * @see JcrQueryResult#getRows()
785     // */
786     // @NotThreadSafe
787     // protected static class QueryResultRowIterator implements RowIterator {
788     // protected final List<String> columnNames;
789     // private final Iterator<Object[]> tuples;
790     // private final Set<String> selectorNames;
791     // protected final JcrSession session;
792     // protected final Columns columns;
793     // protected final String query;
794     // private int[] locationIndexes;
795     // private long position = 0L;
796     // private long numRows;
797     // private Row nextRow;
798     //
799     // protected QueryResultRowIterator( JcrSession session,
800     // String query,
801     // QueryResults results,
802     // Iterator<Object[]> tuples,
803     // long numRows ) {
804     // this.tuples = tuples;
805     // this.query = query;
806     // this.columns = results.getColumns();
807     // this.columnNames = this.columns.getColumnNames();
808     // this.session = session;
809     // this.numRows = numRows;
810     // this.selectorNames = new HashSet<String>(columns.getSelectorNames());
811     // int i = 0;
812     // locationIndexes = new int[selectorNames.size()];
813     // for (String selectorName : selectorNames) {
814     // locationIndexes[i++] = columns.getLocationIndex(selectorName);
815     // }
816     // }
817     //
818     // public boolean hasSelector( String selectorName ) {
819     // return this.selectorNames.contains(selectorName);
820     // }
821     //
822     // /**
823     // * {@inheritDoc}
824     // *
825     // * @see javax.jcr.query.RowIterator#nextRow()
826     // */
827     // public Row nextRow() {
828     // if (nextRow == null) {
829     // // Didn't call 'hasNext()' ...
830     // if (!hasNext()) {
831     // throw new NoSuchElementException();
832     // }
833     // }
834     // assert nextRow != null;
835     // Row result = nextRow;
836     // nextRow = null;
837     // return result;
838     // }
839     //
840     // /**
841     // * {@inheritDoc}
842     // *
843     // * @see javax.jcr.RangeIterator#getPosition()
844     // */
845     // public long getPosition() {
846     // return position;
847     // }
848     //
849     // /**
850     // * {@inheritDoc}
851     // *
852     // * @see javax.jcr.RangeIterator#getSize()
853     // */
854     // public long getSize() {
855     // return numRows;
856     // }
857     //
858     // /**
859     // * {@inheritDoc}
860     // *
861     // * @see javax.jcr.RangeIterator#skip(long)
862     // */
863     // public void skip( long skipNum ) {
864     // for (long i = 0L; i != skipNum; ++i) {
865     // tuples.next();
866     // }
867     // position += skipNum;
868     // }
869     //
870     // /**
871     // * {@inheritDoc}
872     // *
873     // * @see java.util.Iterator#hasNext()
874     // */
875     // public boolean hasNext() {
876     // if (nextRow != null) {
877     // return true;
878     // }
879     // while (tuples.hasNext()) {
880     // final Object[] tuple = tuples.next();
881     // ++position;
882     // try {
883     // // Get the next row ...
884     // nextRow = getNextRow(tuple);
885     // if (nextRow != null) return true;
886     // } catch (RepositoryException e) {
887     // // The node could not be found in this session, so skip it ...
888     // }
889     // --numRows;
890     // }
891     // return false;
892     // }
893     //
894     // protected Row getNextRow( Object[] tuple ) throws RepositoryException {
895     // // Make sure that each node referenced by the tuple exists and is accessible ...
896     // Node[] nodes = new Node[locationIndexes.length];
897     // int index = 0;
898     // for (int locationIndex : locationIndexes) {
899     // Location location = (Location)tuple[locationIndex];
900     // if (session.wasRemovedInSession(location)) {
901     // // Skip this record because one of the nodes no longer exists ...
902     // return null;
903     // }
904     // try {
905     // nodes[index++] = session.getNode(location.getPath());
906     // } catch (AccessDeniedException e) {
907     // // No access to this node, so skip the record ...
908     // return null;
909     // }
910     // }
911     // return new MultiSelectorQueryResultRow(this, nodes, locationIndexes, tuple);
912     // }
913     //
914     // /**
915     // * {@inheritDoc}
916     // *
917     // * @see java.util.Iterator#next()
918     // */
919     // public Object next() {
920     // return nextRow();
921     // }
922     //
923     // /**
924     // * {@inheritDoc}
925     // *
926     // * @see java.util.Iterator#remove()
927     // */
928     // public void remove() {
929     // throw new UnsupportedOperationException();
930     // }
931     // }
932     //
933     // /**
934     // * The {@link RowIterator} implementation returned by the {@link JcrQueryResult}.
935     // *
936     // * @see JcrQueryResult#getRows()
937     // */
938     // @NotThreadSafe
939     // protected static class SingleSelectorQueryResultRowIterator extends QueryResultRowIterator {
940     // protected final int locationIndex;
941     // protected final int scoreIndex;
942     //
943     // protected SingleSelectorQueryResultRowIterator( JcrSession session,
944     // String query,
945     // QueryResults results,
946     // Iterator<Object[]> tuples,
947     // long numRows ) {
948     // super(session, query, results, tuples, numRows);
949     // String selectorName = columns.getSelectorNames().get(0);
950     // locationIndex = columns.getLocationIndex(selectorName);
951     // scoreIndex = columns.getFullTextSearchScoreIndexFor(selectorName);
952     // }
953     //
954     // /**
955     // * {@inheritDoc}
956     // *
957     // * @see org.modeshape.jcr.JcrQueryManager.QueryResultRowIterator#getNextRow(java.lang.Object[])
958     // */
959     // @Override
960     // protected Row getNextRow( Object[] tuple ) throws RepositoryException {
961     // Location location = (Location)tuple[locationIndex];
962     // if (!session.wasRemovedInSession(location)) {
963     // Node node = session.getNode(location.getPath());
964     // return createRow(node, tuple);
965     // }
966     // return null;
967     // }
968     //
969     // protected Row createRow( Node node,
970     // Object[] tuple ) {
971     // return new SingleSelectorQueryResultRow(this, node, tuple);
972     // }
973     // }
974     //
975     // protected static class SingleSelectorQueryResultRow implements Row, org.modeshape.jcr.api.query.Row {
976     // protected final SingleSelectorQueryResultRowIterator iterator;
977     // protected final Node node;
978     // protected final Object[] tuple;
979     // private Value[] values = null;
980     //
981     // protected SingleSelectorQueryResultRow( SingleSelectorQueryResultRowIterator iterator,
982     // Node node,
983     // Object[] tuple ) {
984     // this.iterator = iterator;
985     // this.node = node;
986     // this.tuple = tuple;
987     // assert this.iterator != null;
988     // assert this.node != null;
989     // assert this.tuple != null;
990     // }
991     //
992     // /**
993     // * {@inheritDoc}
994     // *
995     // * @see org.modeshape.jcr.api.query.Row#getNode(java.lang.String)
996     // */
997     // @Override
998     // public Node getNode( String selectorName ) throws RepositoryException {
999     // if (iterator.hasSelector(selectorName)) {
1000     // throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query));
1001     // }
1002     // return node;
1003     // }
1004     //
1005     // /**
1006     // * {@inheritDoc}
1007     // *
1008     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1009     // */
1010     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1011     // return node.getProperty(columnName).getValue();
1012     // }
1013     //
1014     // /**
1015     // * {@inheritDoc}
1016     // *
1017     // * @see javax.jcr.query.Row#getValues()
1018     // */
1019     // public Value[] getValues() throws RepositoryException {
1020     // if (values == null) {
1021     // int i = 0;
1022     // values = new Value[iterator.columnNames.size()];
1023     // for (String columnName : iterator.columnNames) {
1024     // values[i++] = getValue(columnName);
1025     // }
1026     // }
1027     // return values;
1028     // }
1029     //
1030     // @Override
1031     // public Node getNode() throws RepositoryException {
1032     // throw new UnsupportedRepositoryOperationException();
1033     // }
1034     //
1035     // @Override
1036     // public String getPath() throws RepositoryException {
1037     // throw new UnsupportedRepositoryOperationException();
1038     // }
1039     //
1040     // @Override
1041     // public String getPath( String selectorName ) throws RepositoryException {
1042     // throw new UnsupportedRepositoryOperationException();
1043     // }
1044     //
1045     // @Override
1046     // public double getScore() throws RepositoryException {
1047     // throw new UnsupportedRepositoryOperationException();
1048     // }
1049     //
1050     // @Override
1051     // public double getScore( String selectorName ) throws RepositoryException {
1052     // throw new UnsupportedRepositoryOperationException();
1053     // }
1054     // }
1055     //
1056     // protected static class MultiSelectorQueryResultRow implements Row, org.modeshape.jcr.api.query.Row {
1057     // protected final QueryResultRowIterator iterator;
1058     // protected final Object[] tuple;
1059     // private Value[] values = null;
1060     // private Node[] nodes;
1061     // private int[] locationIndexes;
1062     //
1063     // protected MultiSelectorQueryResultRow( QueryResultRowIterator iterator,
1064     // Node[] nodes,
1065     // int[] locationIndexes,
1066     // Object[] tuple ) {
1067     // this.iterator = iterator;
1068     // this.tuple = tuple;
1069     // this.nodes = nodes;
1070     // this.locationIndexes = locationIndexes;
1071     // assert this.iterator != null;
1072     // assert this.tuple != null;
1073     // }
1074     //
1075     // /**
1076     // * {@inheritDoc}
1077     // *
1078     // * @see org.modeshape.jcr.api.query.Row#getNode(java.lang.String)
1079     // */
1080     // @Override
1081     // public Node getNode( String selectorName ) throws RepositoryException {
1082     // try {
1083     // int locationIndex = iterator.columns.getLocationIndex(selectorName);
1084     // for (int i = 0; i != this.locationIndexes.length; ++i) {
1085     // if (this.locationIndexes[i] == locationIndex) {
1086     // return nodes[i];
1087     // }
1088     // }
1089     // } catch (NoSuchElementException e) {
1090     // throw new RepositoryException(e.getLocalizedMessage(), e);
1091     // }
1092     // assert false;
1093     // return null;
1094     // }
1095     //
1096     // /**
1097     // * {@inheritDoc}
1098     // *
1099     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1100     // */
1101     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1102     // try {
1103     // int locationIndex = iterator.columns.getLocationIndexForColumn(columnName);
1104     // for (int i = 0; i != this.locationIndexes.length; ++i) {
1105     // if (this.locationIndexes[i] == locationIndex) {
1106     // Node node = nodes[i];
1107     // return node != null ? node.getProperty(columnName).getValue() : null;
1108     // }
1109     // }
1110     // } catch (NoSuchElementException e) {
1111     // throw new RepositoryException(e.getLocalizedMessage(), e);
1112     // }
1113     // assert false;
1114     // return null;
1115     // }
1116     //
1117     // /**
1118     // * {@inheritDoc}
1119     // *
1120     // * @see javax.jcr.query.Row#getValues()
1121     // */
1122     // public Value[] getValues() throws RepositoryException {
1123     // if (values == null) {
1124     // int i = 0;
1125     // values = new Value[iterator.columnNames.size()];
1126     // for (String columnName : iterator.columnNames) {
1127     // values[i++] = getValue(columnName);
1128     // }
1129     // }
1130     // return values;
1131     // }
1132     //
1133     // @Override
1134     // public Node getNode() throws RepositoryException {
1135     // throw new UnsupportedRepositoryOperationException();
1136     // }
1137     //
1138     // @Override
1139     // public String getPath() throws RepositoryException {
1140     // throw new UnsupportedRepositoryOperationException();
1141     // }
1142     //
1143     // @Override
1144     // public String getPath( String selectorName ) throws RepositoryException {
1145     // throw new UnsupportedRepositoryOperationException();
1146     // }
1147     //
1148     // @Override
1149     // public double getScore() throws RepositoryException {
1150     // throw new UnsupportedRepositoryOperationException();
1151     // }
1152     //
1153     // @Override
1154     // public double getScore( String selectorName ) throws RepositoryException {
1155     // throw new UnsupportedRepositoryOperationException();
1156     // }
1157     // }
1158     //
1159     // protected static class XPathQueryResult extends JcrQueryResult {
1160     // private final List<String> columnNames;
1161     //
1162     // protected XPathQueryResult( JcrSession session,
1163     // String query,
1164     // QueryResults graphResults,
1165     // Schemata schemata ) {
1166     // super(session, query, graphResults, schemata);
1167     // List<String> columnNames = new LinkedList<String>(graphResults.getColumns().getColumnNames());
1168     // if (graphResults.getColumns().hasFullTextSearchScores() && !columnNames.contains(JCR_SCORE_COLUMN_NAME)) {
1169     // columnNames.add(0, JCR_SCORE_COLUMN_NAME);
1170     // }
1171     // columnNames.add(0, JCR_PATH_COLUMN_NAME);
1172     // this.columnNames = Collections.unmodifiableList(columnNames);
1173     // }
1174     //
1175     // /**
1176     // * {@inheritDoc}
1177     // *
1178     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getColumnNameList()
1179     // */
1180     // @Override
1181     // public List<String> getColumnNameList() {
1182     // return columnNames;
1183     // }
1184     //
1185     // /**
1186     // * {@inheritDoc}
1187     // *
1188     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getRows()
1189     // */
1190     // @Override
1191     // public RowIterator getRows() {
1192     // final int numRows = results.getRowCount();
1193     // final List<Object[]> tuples = results.getTuples();
1194     // return new XPathQueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
1195     // }
1196     // }
1197     //
1198     // protected static class XPathQueryResultRowIterator extends SingleSelectorQueryResultRowIterator {
1199     // private final ValueFactories factories;
1200     // private final SessionCache cache;
1201     //
1202     // protected XPathQueryResultRowIterator( JcrSession session,
1203     // String query,
1204     // QueryResults results,
1205     // Iterator<Object[]> tuples,
1206     // long numRows ) {
1207     // super(session, query, results, tuples, numRows);
1208     // factories = session.executionContext.getValueFactories();
1209     // cache = session.cache();
1210     // }
1211     //
1212     // @Override
1213     // protected Row createRow( Node node,
1214     // Object[] tuple ) {
1215     // return new XPathQueryResultRow(this, node, tuple);
1216     // }
1217     //
1218     // protected Value jcrPath( Path path ) {
1219     // return new JcrValue(factories, cache, PropertyType.PATH, path);
1220     // }
1221     //
1222     // protected Value jcrScore( Float score ) {
1223     // return new JcrValue(factories, cache, PropertyType.DOUBLE, score);
1224     // }
1225     // }
1226     //
1227     // protected static class XPathQueryResultRow extends SingleSelectorQueryResultRow {
1228     // protected XPathQueryResultRow( SingleSelectorQueryResultRowIterator iterator,
1229     // Node node,
1230     // Object[] tuple ) {
1231     // super(iterator, node, tuple);
1232     // }
1233     //
1234     // /**
1235     // * {@inheritDoc}
1236     // *
1237     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1238     // */
1239     // @Override
1240     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1241     // if (JCR_PATH_COLUMN_NAME.equals(columnName)) {
1242     // Location location = (Location)tuple[iterator.locationIndex];
1243     // return ((XPathQueryResultRowIterator)iterator).jcrPath(location.getPath());
1244     // }
1245     // if (JCR_SCORE_COLUMN_NAME.equals(columnName)) {
1246     // Float score = (Float)tuple[iterator.scoreIndex];
1247     // return ((XPathQueryResultRowIterator)iterator).jcrScore(score);
1248     // }
1249     // return super.getValue(columnName);
1250     // }
1251     // }
1252     //
1253     // protected static class JcrSqlQueryResult extends JcrQueryResult {
1254     //
1255     // private final List<String> columnNames;
1256     // private boolean addedScoreColumn;
1257     // private boolean addedPathColumn;
1258     //
1259     // protected JcrSqlQueryResult( JcrSession session,
1260     // String query,
1261     // QueryResults graphResults,
1262     // Schemata schemata ) {
1263     // super(session, query, graphResults, schemata);
1264     // List<String> columnNames = new LinkedList<String>(graphResults.getColumns().getColumnNames());
1265     // if (!columnNames.contains(JCR_SCORE_COLUMN_NAME)) {
1266     // columnNames.add(0, JCR_SCORE_COLUMN_NAME);
1267     // addedScoreColumn = true;
1268     // }
1269     // if (!columnNames.contains(JCR_PATH_COLUMN_NAME)) {
1270     // columnNames.add(0, JCR_PATH_COLUMN_NAME);
1271     // addedPathColumn = true;
1272     // }
1273     // this.columnNames = Collections.unmodifiableList(columnNames);
1274     // }
1275     //
1276     // /**
1277     // * {@inheritDoc}
1278     // *
1279     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getColumnNameList()
1280     // */
1281     // @Override
1282     // public List<String> getColumnNameList() {
1283     // return columnNames;
1284     // }
1285     //
1286     // @Override
1287     // protected List<String> loadColumnTypes( Columns columns ) {
1288     // List<String> types = new ArrayList<String>(columns.getColumnCount() + (addedScoreColumn ? 1 : 0)
1289     // + (addedPathColumn ? 1 : 0));
1290     // String stringtype = PropertyType.nameFromValue(PropertyType.STRING);
1291     // if (addedScoreColumn) types.add(0, stringtype);
1292     // if (addedPathColumn) types.add(0, stringtype);
1293     //
1294     // for (Column column : columns) {
1295     // String typeName = null;
1296     // Table table = schemata.getTable(column.selectorName());
1297     // if (table != null) {
1298     // Schemata.Column typedColumn = table.getColumn(column.propertyName());
1299     // typeName = typedColumn.getPropertyType();
1300     // }
1301     // if (typeName == null) {
1302     // // Might be fabricated column, so just assume string ...
1303     // typeName = stringtype;
1304     // }
1305     // types.add(typeName);
1306     // }
1307     //
1308     // return types;
1309     // }
1310     //
1311     // /**
1312     // * {@inheritDoc}
1313     // *
1314     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getRows()
1315     // */
1316     // @Override
1317     // public RowIterator getRows() {
1318     // final int numRows = results.getRowCount();
1319     // final List<Object[]> tuples = results.getTuples();
1320     // return new JcrSqlQueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
1321     // }
1322     // }
1323     //
1324     // protected static class JcrSqlQueryResultRowIterator extends SingleSelectorQueryResultRowIterator {
1325     // private final ValueFactories factories;
1326     // private final SessionCache cache;
1327     //
1328     // protected JcrSqlQueryResultRowIterator( JcrSession session,
1329     // String query,
1330     // QueryResults results,
1331     // Iterator<Object[]> tuples,
1332     // long numRows ) {
1333     // super(session, query, results, tuples, numRows);
1334     // factories = session.executionContext.getValueFactories();
1335     // cache = session.cache();
1336     // }
1337     //
1338     // @Override
1339     // protected Row createRow( Node node,
1340     // Object[] tuple ) {
1341     // return new JcrSqlQueryResultRow(this, node, tuple);
1342     // }
1343     //
1344     // protected Value jcrPath( Path path ) {
1345     // return new JcrValue(factories, cache, PropertyType.PATH, path);
1346     // }
1347     //
1348     // protected Value jcrScore( Float score ) {
1349     // return new JcrValue(factories, cache, PropertyType.DOUBLE, score);
1350     // }
1351     // }
1352     //
1353     // protected static class JcrSqlQueryResultRow extends SingleSelectorQueryResultRow {
1354     // protected JcrSqlQueryResultRow( SingleSelectorQueryResultRowIterator iterator,
1355     // Node node,
1356     // Object[] tuple ) {
1357     // super(iterator, node, tuple);
1358     // }
1359     //
1360     // /**
1361     // * {@inheritDoc}
1362     // *
1363     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1364     // */
1365     // @Override
1366     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1367     // if (JCR_PATH_COLUMN_NAME.equals(columnName)) {
1368     // Location location = (Location)tuple[iterator.locationIndex];
1369     // return ((JcrSqlQueryResultRowIterator)iterator).jcrPath(location.getPath());
1370     // }
1371     // if (JCR_SCORE_COLUMN_NAME.equals(columnName)) {
1372     // Float score = (Float)tuple[iterator.scoreIndex];
1373     // return ((JcrSqlQueryResultRowIterator)iterator).jcrScore(score);
1374     // }
1375     // return super.getValue(columnName);
1376     // }
1377     // }
1378     //
1379     // @Override
1380     // public QueryObjectModelFactory getQOMFactory() {
1381     // throw new IllegalStateException();
1382     // }
1383 
1384     protected static class SessionQueryContext implements JcrQueryContext {
1385         private final JcrSession session;
1386         private final ValueFactories factories;
1387         private final SessionCache cache;
1388 
1389         protected SessionQueryContext( JcrSession session ) {
1390             this.session = session;
1391             this.factories = session.getExecutionContext().getValueFactories();
1392             this.cache = session.cache();
1393         }
1394 
1395         /**
1396          * {@inheritDoc}
1397          * 
1398          * @see org.modeshape.jcr.query.JcrQueryContext#createValue(int, java.lang.Object)
1399          */
1400         @Override
1401         public Value createValue( int propertyType,
1402                                   Object value ) {
1403             return new JcrValue(factories, cache, PropertyType.PATH, value);
1404         }
1405 
1406         /**
1407          * {@inheritDoc}
1408          * 
1409          * @see org.modeshape.jcr.query.JcrQueryContext#emptyNodeIterator()
1410          */
1411         @Override
1412         public NodeIterator emptyNodeIterator() {
1413             return new JcrEmptyNodeIterator();
1414         }
1415 
1416         /**
1417          * {@inheritDoc}
1418          * 
1419          * @see org.modeshape.jcr.query.JcrQueryContext#execute(org.modeshape.graph.query.model.QueryCommand,
1420          *      org.modeshape.graph.query.plan.PlanHints, java.util.Map)
1421          */
1422         @Override
1423         public QueryResults execute( QueryCommand query,
1424                                      PlanHints hints,
1425                                      Map<String, Object> variables ) throws RepositoryException {
1426             session.checkLive();
1427             // Submit immediately to the workspace graph ...
1428             Schemata schemata = session.workspace().nodeTypeManager().schemata();
1429             return session.repository().queryManager().query(session.workspace().getName(), query, schemata, hints, variables);
1430         }
1431 
1432         /**
1433          * {@inheritDoc}
1434          * 
1435          * @see org.modeshape.jcr.query.JcrQueryContext#getExecutionContext()
1436          */
1437         @Override
1438         public ExecutionContext getExecutionContext() {
1439             return session.getExecutionContext();
1440         }
1441 
1442         /**
1443          * {@inheritDoc}
1444          * 
1445          * @see org.modeshape.jcr.query.JcrQueryContext#getNode(Location)
1446          */
1447         @Override
1448         public Node getNode( Location location ) throws AccessDeniedException, RepositoryException {
1449             if (!session.wasRemovedInSession(location)) {
1450                 return session.getNode(location.getPath());
1451             }
1452             return null;
1453         }
1454 
1455         /**
1456          * {@inheritDoc}
1457          * 
1458          * @see org.modeshape.jcr.query.JcrQueryContext#getSchemata()
1459          */
1460         @Override
1461         public Schemata getSchemata() {
1462             return session.nodeTypeManager().schemata();
1463         }
1464 
1465         /**
1466          * {@inheritDoc}
1467          * 
1468          * @see org.modeshape.jcr.query.JcrQueryContext#isLive()
1469          */
1470         @Override
1471         public boolean isLive() {
1472             return session.isLive();
1473         }
1474 
1475         /**
1476          * {@inheritDoc}
1477          * 
1478          * @see org.modeshape.jcr.query.JcrQueryContext#search(java.lang.String, int, int)
1479          */
1480         @Override
1481         public QueryResults search( String searchExpression,
1482                                     int maxRowCount,
1483                                     int offset ) throws RepositoryException {
1484             return session.repository().queryManager().search(session.workspace().getName(),
1485                                                               searchExpression,
1486                                                               maxRowCount,
1487                                                               offset);
1488         }
1489 
1490         /**
1491          * {@inheritDoc}
1492          * 
1493          * @see org.modeshape.jcr.query.JcrQueryContext#store(java.lang.String, org.modeshape.graph.property.Name,
1494          *      java.lang.String, java.lang.String)
1495          */
1496         @Override
1497         public Node store( String absolutePath,
1498                            Name nodeType,
1499                            String language,
1500                            String statement ) throws RepositoryException {
1501             session.checkLive();
1502             NamespaceRegistry namespaces = session.namespaces();
1503 
1504             Path path;
1505             try {
1506                 path = session.getExecutionContext().getValueFactories().getPathFactory().create(absolutePath);
1507             } catch (IllegalArgumentException iae) {
1508                 throw new RepositoryException(JcrI18n.invalidPathParameter.text("absolutePath", absolutePath));
1509             }
1510             Path parentPath = path.getParent();
1511 
1512             Node parentNode = session.getNode(parentPath);
1513 
1514             if (!parentNode.isCheckedOut()) {
1515                 throw new VersionException(JcrI18n.nodeIsCheckedIn.text(parentNode.getPath()));
1516             }
1517 
1518             Node queryNode = parentNode.addNode(path.relativeTo(parentPath).getString(namespaces),
1519                                                 JcrNtLexicon.QUERY.getString(namespaces));
1520 
1521             queryNode.setProperty(JcrLexicon.LANGUAGE.getString(namespaces), language);
1522             queryNode.setProperty(JcrLexicon.STATEMENT.getString(namespaces), statement);
1523 
1524             return queryNode;
1525         }
1526 
1527     }
1528 
1529     protected static class SessionTypeSystem implements JcrTypeSystem {
1530         protected final JcrSession session;
1531         protected final TypeSystem delegate;
1532 
1533         protected SessionTypeSystem( JcrSession session ) {
1534             this.session = session;
1535             this.delegate = session.getExecutionContext().getValueFactories().getTypeSystem();
1536         }
1537 
1538         @Override
1539         public Set<String> getTypeNames() {
1540             return delegate.getTypeNames();
1541         }
1542 
1543         @Override
1544         public TypeFactory<?> getTypeFactory( Object prototype ) {
1545             return delegate.getTypeFactory(prototype);
1546         }
1547 
1548         @Override
1549         public TypeFactory<?> getTypeFactory( String typeName ) {
1550             return delegate.getTypeFactory(typeName);
1551         }
1552 
1553         @Override
1554         public TypeFactory<String> getStringFactory() {
1555             return delegate.getStringFactory();
1556         }
1557 
1558         @Override
1559         public TypeFactory<?> getReferenceFactory() {
1560             return delegate.getReferenceFactory();
1561         }
1562 
1563         @Override
1564         public TypeFactory<?> getPathFactory() {
1565             return delegate.getPathFactory();
1566         }
1567 
1568         @Override
1569         public TypeFactory<Long> getLongFactory() {
1570             return delegate.getLongFactory();
1571         }
1572 
1573         @Override
1574         public TypeFactory<Double> getDoubleFactory() {
1575             return delegate.getDoubleFactory();
1576         }
1577 
1578         @Override
1579         public String getDefaultType() {
1580             return delegate.getDefaultType();
1581         }
1582 
1583         @Override
1584         public Comparator<Object> getDefaultComparator() {
1585             return delegate.getDefaultComparator();
1586         }
1587 
1588         @Override
1589         public TypeFactory<BigDecimal> getDecimalFactory() {
1590             return delegate.getDecimalFactory();
1591         }
1592 
1593         @Override
1594         public TypeFactory<?> getDateTimeFactory() {
1595             return delegate.getDateTimeFactory();
1596         }
1597 
1598         @Override
1599         public String getCompatibleType( String type1,
1600                                          String type2 ) {
1601             return delegate.getCompatibleType(type1, type2);
1602         }
1603 
1604         @Override
1605         public TypeFactory<Boolean> getBooleanFactory() {
1606             return delegate.getBooleanFactory();
1607         }
1608 
1609         @Override
1610         public TypeFactory<?> getBinaryFactory() {
1611             return delegate.getBinaryFactory();
1612         }
1613 
1614         @Override
1615         public String asString( Object value ) {
1616             return delegate.asString(value);
1617         }
1618 
1619         @Override
1620         public ValueFactory getValueFactory() {
1621             return session.getValueFactory();
1622         }
1623     }
1624 }