<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ ModeShape (http://www.modeshape.org)
  ~
  ~ See the COPYRIGHT.txt file distributed with this work for information
  ~ regarding copyright ownership.  Some portions may be licensed
  ~ to Red Hat, Inc. under one or more contributor license agreements.
  ~ See the AUTHORS.txt file in the distribution for a full listing of 
  ~ individual contributors.
  ~
  ~ ModeShape is free software. Unless otherwise indicated, all code in ModeShape
  ~ is licensed to you under the terms of the GNU Lesser General Public License as
  ~ published by the Free Software Foundation; either version 2.1 of
  ~ the License, or (at your option) any later version.
  ~
  ~ ModeShape is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"	[
<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
%CustomDTD;
]>
<chapter id="jcr-query-and-search">
  <title>Querying and Searching using JCR</title>
  <para>
	  The JCR API defines a way to query a repository for content that meets user-defined criteria. 
	  The JCR 2.0 API actually makes it possible for implementations to support multiple query languages,
	  and the specification requires support for two languages: 
	  <link linkend="jcr-sql2-query-language">JCR-SQL2</link> and <link linkend="jcr-qom-query-language">JCR-QOM</link>.
	  <ulink url="&JSR170;">JCR 1.0</ulink> defined two other languages (<link linkend="jcr-xpath-query-language">XPath</link> 
	  and <link linkend="jcr-sql-query-language">JCR-SQL</link>), though these languages were deprecated in
	  <ulink url="&JSR283;">JCR 2.0</ulink>.
  </para>
	<para>
		At this time, ModeShape supports all of these query languages, plus one search-engine-like language
		called "<link linkend="fulltext-search-expressions">search</link>" that 
		is actually just the <link linkend="jcr-sql2-full-text-search-constraints">full-text search expression grammar</link>
		used in the second parameter of the <code>CONTAINS(...)</code> function of the JCR-SQL2 language.
	</para>
	<para>
		ModeShape handles all of these languages in nearly the same manner, the only difference being whether the query is
		represented as a string or build programmatically using the <code>javax.jcr.query.qom</code> part of the JCR API.
    <orderedlist>
      <listitem>
        <para>
	        A language-independent representation, called the query model, is constructed by parsing the string representation of
	        the query (using a language-specific parser) or the JCR-QOM objects created by the client.
        </para>
      </listitem>
      <listitem>
        <para>
					The language-independent query model is used to create a canonical (relational) query plan.
        </para>
      </listitem>
      <listitem>
        <para>
					The canonical query plan is then validated to ensure that all identifiers in the query are resolvable.
        </para>
      </listitem>
      <listitem>
        <para>
					The canonical query plan is then optimized using a flexible rule-based optimizer. Optimizations include
					(but are not limited to): replace view references; unify handling of aliases; convert right outer joins into left outer
					joins; choose algorithms for each join; raise and lower criteria; push projection of columns as low in the plan
					as possible; duplicate criteria across identity joins; rewrite identity joins involving only columns that form keys;
					remove parts of the plan that (based upon the criteria) will return no rows; determination of the low-level
					"access" queries that will be submitted to the connector layer.
        </para>
      </listitem>
      <listitem>
        <para>
					The optimized query plan is then executed, whereby each access query is pushed down to the connector and the
					results are then processed and combined to produce the desired result set.
        </para>
      </listitem>
    </orderedlist>
		Note that only the parsing step is dependent upon the query language. This means that all of the query languages
		are processed using the same, unified engine.
	</para>
	<para>
		The rest of this chapter describes how your applications can use queries to search
		your repositories, and outlines the specifics of each of the four query languages available in ModeShape.
	</para>
  <sect1 id="jcr-query-api">	
    <title>JCR Query API</title>
    <para>
	    With ModeShape, all query operations can be performed using only the JCR API interfaces. The first step is to
	    obtain the &QueryManager; from your &Session; instance. The QueryManager interface defines methods for creating
	    &Query; objects, executing queries, storing queries (not results) as &Node;s in the repository, and reconstituting 
	    queries that were stored on &Node;s. Thus, querying a repository generally follows this pattern:
		</para>
<programlisting language="JAVA" role="JAVA"><![CDATA[
// Obtain the query manager for the session ...
javax.jcr.query.QueryManager queryManager = session.getWorkspace().getQueryManager();

// Create a query object ...
String language = ...
String expression = ...
javax.jcr.Query query = queryManager.createQuery(expression,language);

// Execute the query and get the results ...
javax.jcr.QueryResult result = query.execute();

// Iterate over the nodes in the results ...
javax.jcr.NodeIterator nodeIter = result.getNodes();
while ( nodeIter.hasNext() ) {
    javax.jcr.Node node = nodeIter.nextNode();
		...
}

// Or iterate over the rows in the results ...
String[] columnNames = result.getColumnNames();
javax.jcr.query.RowIterator rowIter = result.getRows();
while ( rowIter.hasNext() ) {
    javax.jcr.query.Row row = rowIter.nextRow();
    // Iterate over the column values in each row ...
    javax.jcr.Value[] values = row.getValues();
    for ( javax.jcr.Value value : values ) {
				...
    }
    // Or access the column values by name ...
    for ( String columnName : columnNames ) {
        javax.jcr.Value value = row.getValue(columnName);
				...
    }
}

// When finished, close the session ...
session.logout();
]]></programlisting>
		<para>
			For more detail about these methods or about how to use other facets of the JCR query API, please consult chapter 6 of the 
			<ulink url="&JSR283;">JCR 2.0 specification</ulink>.
		</para>
	</sect1>
  <sect1 id="jcr-xpath-query-language">	
    <title>JCR XPath Query Language</title>
	  <para>
		  The <ulink url="&JSR170;">JCR 1.0 specification</ulink> uses the XPath query language because node structures in JCR
		  are very analogous to the structure of an XML document. Thus, XPath provides a useful language for selecting
		  and searching workspace content. And since JCR 1.0 defines a mapping between XML and a workspace view called
		  the "document view", adapting XPath to workspace content is quite natural.
		</para>
		<para>
			A JCR XPath query specifies the subset of nodes in a workspace that satisfy the constraints defined in the query.
			Constraints can limit the nodes in the results to be those nodes with a specific (primary or mixin) node type,
			with properties having particular values, or to be within a specific subtree of the workspace.
			The query also defines how the nodes are to be returned in the result sets using column specifiers
			and ordering specifiers.
		</para>
		<para>
			ModeShape offers a bit more functionality in the "<code>jcr:contains(...)</code>" clauses than required by the specification.
			In particular, the second parameter specifies the search expression, and for these ModeShape accepts
			<link linkend='fulltext-search-expressions'>full-text search language</link> expressions, including wildcard support.
		</para>
		<note>
			<para>
				As an aside, ModeShape actually implements XPath queries by transforming them into the equivalent JCR-SQL2 representation.
				And the JCR-SQL2 language, although often more verbose, is much more capable of representing complex queries with multiple combinations
				of type, property, and path constraints.
			</para>
		</note>
	  <sect2 id="jcr-xpath-column-specifiers">	
	    <title>Column Specifiers</title>
			<para>
				JCR 1.0 specifies that support is required only for returning column values based upon single-valued, non-residual
				properties that are declared on or inherited by the node types specified in the type constraint.
				ModeShape follows this requirement, and does not specifying residual properties. However, ModeShape does allow
				multi-valued properties to be specified as result columns.
				And as per the specification, ModeShape always returns the "<code>jcr:path</code>" and "<code>jcr:score</code>"
				pseudo-columns.
			</para>
			<para>
				ModeShape uses the last location step with an attribute axis to specify the properties that are to be returned
				as result columns. Multiple properties are specified with a union. 
				For example, the following table shows several XPath queries and how they map to JCR-SQL2 queries.
			</para>
			<table frame='all'>
				<title>Specifying result set columns</title>
				<tgroup cols='2' align='left' colsep='1' rowsep='0'>
		      <colspec colname='c1' colwidth="1*"/>
		      <colspec colname='c2' colwidth="1*"/>
					<thead>
						<row>
				  		<entry>XPath</entry>
				  		<entry>JCR-SQL2</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry><code>//*</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base]</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)/@my:title</code></entry>
							<entry><programlisting>SELECT [my:title] FROM [my:type]</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)/(@my:title | @my:text)</code></entry>
							<entry><programlisting>SELECT [my:title], [my:text] FROM [my:type]</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)/(@my:title union @my:text)</code></entry>
							<entry><programlisting>SELECT [my:title], [my:text] FROM [my:type]</programlisting></entry>
						</row>
					</tbody>
				</tgroup>
			</table>
		</sect2>
	  <sect2 id="jcr-xpath-type-constraints">	
	    <title>Type Constraints</title>
			<para>
				JCR 1.0 specifies that support is required only for specifying constraints of one primary type, and it
				is optional to support specifying constraints on one (or more) mixin types.  The specification
				also defines that the XPath <code>element</code> test be used to test against node types,
				and that it is optional to support <code>element</code> tests on location steps other than the last one.
				Type constraints are inherently inheritance-sensitive, in that a constraint against a particular node type
				'X' will be satisfied by nodes explicitly declared to be of type 'X' or of subtypes of 'X'.
			</para>
			<para>
				ModeShape does support using the <code>element</code> test to test against primary or mixin type.
				ModeShape also only supports using an <code>element</code> test on the last location step.
				For example, the following table shows several XPath queries and how they map to JCR-SQL2 queries.
			</para>
			<table frame='all'>
				<title>Specifying type constraints</title>
				<tgroup cols='2' align='left' colsep='1' rowsep='0'>
		      <colspec colname='c1' colwidth="1*"/>
		      <colspec colname='c2' colwidth="1*"/>
					<thead>
						<row>
				  		<entry>XPath</entry>
				  		<entry>JCR-SQL2</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry><code>//*</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base]</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/nodes/element(*,my:type)</code></entry>
							<entry><programlisting>SELECT * FROM [my:type] 
WHERE PATH([my:type])> LIKE '/nodes/%'
 AND DEPTH([my:type]) = CAST(2 AS LONG)</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/nodes//element(*,my:type)</code></entry>
							<entry><programlisting>SELECT * FROM [my:type] 
WHERE PATH([my:type]) LIKE '/nodes/%'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/nodes//element(ex:nodeName,my:type)</code></entry>
							<entry><programlisting>SELECT * FROM [my:type] 
WHERE PATH([my:type]) LIKE '/nodes/%'
 AND NAME([my:type]) = 'ex:nodeName'</programlisting></entry>
						</row>
					</tbody>
				</tgroup>
			</table>
			<para>
				Note that the JCR-SQL2 language supported by ModeShape is far more capable of joining
				multiple sets of nodes with different type, property and path constraints.
			</para>
		</sect2>
	  <sect2 id="jcr-xpath-property-constraints">	
	    <title>Property Constraints</title>
			<para>
				JCR 1.0 specifies that attribute tests on the last location step is required, but that
				predicate tests on any other location steps are optional.
			</para>
			<para>
				ModeShape does support using attribute tests on the last location step to specify
				property constraints, as well as supporting axis and filter predicates on other location steps.
				For example, the following table shows several XPath queries and how they map to JCR-SQL2 queries.
			</para>
			<table frame='all'>
				<title>Specifying property constraints</title>
				<tgroup cols='2' align='left' colsep='1' rowsep='0'>
		      <colspec colname='c1' colwidth="1*"/>
		      <colspec colname='c2' colwidth="1*"/>
					<thead>
						<row>
				  		<entry>XPath</entry>
				  		<entry>JCR-SQL2</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry><code>//*[@prop1]</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base] 
WHERE [nt:base].prop1 IS NOT NULL</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[@prop1]</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE [my:type].prop1 IS NOT NULL</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[@prop1=xs:boolean('true')]</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE [my:type].prop1 = CAST('true' AS BOOLEAN)</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[@id&lt;1 and @name='john']</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE id &lt; 1 AND name = 'john'</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[a/b/@id]</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
JOIN [nt:base] as nodeSet1 
  ON ISCHILDNODE(nodeSet1,[my:type])
JOIN [nt:base] as nodeSet2 
  ON ISCHILDNODE(nodeSet2,nodeSet1)
WHERE (NAME(nodeSet1) = 'a' 
  AND NAME(nodeSet2) = 'b')
  AND nodeSet2.id IS NOT NULL</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[./*/*/@id]</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
JOIN [nt:base] as nodeSet1 
  ON ISCHILDNODE(nodeSet1,[my:type])
JOIN [nt:base] as nodeSet2
  ON ISCHILDNODE(nodeSet2,nodeSet1)
WHERE nodeSet2.id IS NOT NULLL</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[.//@id]</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
JOIN [nt:base] as nodeSet1 
  ON ISDESCENDANTNODE(nodeSet1,[my:type])
WHERE nodeSet2.id IS NOT NULLL</programlisting></entry>
						</row>
					</tbody>
				</tgroup>
			</table>
			<para>
				Section 6.6.3.3 of the JCR 1.0 specification contains an in-depth description of property value constraints using
				various comparison operators.
			</para>
		</sect2>
	  <sect2 id="jcr-xpath-path-constraints">	
	    <title>Path Constraints</title>
			<para>
				JCR 1.0 specifies that exact, child node, and descendants-or-self path constraints be supported
				on the location steps in an XPath query.
			</para>
			<para>
				ModeShape does support the four kinds of path constraints.
				For example, the following table shows several XPath queries and how they map to JCR-SQL2 queries.
			</para>
			<table frame='all'>
				<title>Specifying path constraints</title>
				<tgroup cols='2' align='left' colsep='1' rowsep='0'>
		      <colspec colname='c1' colwidth="1*"/>
		      <colspec colname='c2' colwidth="1*"/>
					<thead>
						<row>
				  		<entry>XPath</entry>
				  		<entry>JCR-SQL2</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry><code>/jcr:root/a[1]/b[2]</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base]
WHERE PATH([nt:base]) = '/a[1]/b[2]'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/a/b[*]</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base]
WHERE PATH([nt:base]) = '/a[%]/b[%]'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/a[1]/b[*]</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base]
WHERE PATH([nt:base]) = '/a[%]/b[%]'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/a[2]/b</code></entry>
							<entry><programlisting>SELECT * FROM [nt:base]
WHERE PATH([nt:base]) = '/a[2]/b[%]'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/a/b[2]//c[4]</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE PATH([nt:base]) = '/a[%]/b[2]/c[4]'
   OR PATH(nodeSet1) LIKE '/a[%]/b[2]/%/c[4]'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/a/b//c//d</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE PATH([nt:base]) = '/a[%]/b[%]/c[%]/d[%]'
   OR PATH([nt:base]) LIKE '/a[%]/b[%]/%/c[%]/d[%]' 
   OR PATH([nt:base]) LIKE '/a[%]/b[%]/c[%]/%/d[%]'
   OR PATH([nt:base]) LIKE '/a[%]/b[%]/%/c[%]/%/d[%]'</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type)[@id&lt;1 and @name='john']</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE id &lt; 1 AND name = 'john'</programlisting></entry>
						</row>
						<row>
							<entry><code>/jcr:root/a/b//element(*,my:type)</code></entry>
							<entry><programlisting>SELECT * FROM [my:type]
WHERE PATH([my:type]) = '/a[%]/b[%]/%'</programlisting></entry>
						</row>
					</tbody>
				</tgroup>
			</table>
			<para>
				Note that the JCR-SQL2 language supported by ModeShape is capable of representing a wider
				combination of path constraints, although the XPath expressions are easier to understand 
				and significantly shorter.
			</para>
			<para>
				Also, path constraints in XPath do not need to specify wildcards for the same-name-sibling (SNS) indexes,
				as XPath should naturally find all nodes regardless of the SNS index, unless
				the SNS index is explicitly specified.
				In other words, any path segment that does not have
				an explicit SNS index (or an SNS index of '[%]' or '[_]') will match <emphasis>all</emphasis> SNS index values. 
				However, any segments in the path expression that have an explicit numeric SNS index will require an exact match.
				Thus this path constraint:
			</para>
			<para><programlisting>/a/b/c[2]/d[%]/%/e[_]</programlisting></para>
			<para>
				will effectively be converted into
			</para>
			<para><programlisting>/a[%]/b[%]/c[2]/d[%]/%/e[_]</programlisting></para>
			<para>
				This behavior is very different than how JCR-SQL and JCR-SQL2 path constraints are handled,
				since these languages interpret a lack of a SNS index as equating to '<code>[1]</code>'.
				To achieve the XPath-like matching, a query written in JCR-SQL or JCR-SQL2 would need
				to explicitly include '<code>[%]</code>' in each path segment where an SNS index literal
				is not already specified.
			</para>
		</sect2>
	  <sect2 id="jcr-xpath-ordering-specifiers">	
	    <title>Ordering Specifiers</title>
			<para>
				JCR 1.0 extends the XPath grammar to add support for ordering the results according to the
				natural ordering of the values of one or more properties on the nodes.
			</para>
			<para>
				ModeShape does support zero or more ordering specifiers, including whether each specifier
				is ascending or descending. If no ordering specifiers are defined, the ordering of the results
				is not predefined and may vary (though ordering by score may be used by default).
				For example, the following table shows several XPath queries and how they map to JCR-SQL2 queries.
			</para>
			<table frame='all'>
				<title>Specifying result ordering</title>
				<tgroup cols='2' align='left' colsep='1' rowsep='0'>
		      <colspec colname='c1' colwidth="1*"/>
		      <colspec colname='c2' colwidth="1*"/>
					<thead>
						<row>
				  		<entry>XPath</entry>
				  		<entry>JCR-SQL2</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry><code>//element(*,*) order by @title</code></entry>
							<entry><programlisting>SELECT nodeSet1.title
FROM [nt:base] AS nodeSet1 
ORDER BY nodeSet1.title</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,*) order by jcr:score()</code></entry>
							<entry><programlisting>SELECT *
FROM [nt:base] AS nodeSet1 
ORDER BY SCORE(nodeSet1)</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,my:type) order by jcr:score(my:type)</code></entry>
							<entry><programlisting>SELECT *
FROM [my:type] AS nodeSet1 
ORDER BY SCORE(nodeSet1)</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,*) order by @jcr:path</code></entry>
							<entry><programlisting>SELECT jcr:path
FROM [nt:base] AS nodeSet1 
ORDER BY PATH(nodeSet1)</programlisting></entry>
						</row>
						<row>
							<entry><code>//element(*,*) order by @title, @jcr:score</code></entry>
							<entry><programlisting>SELECT nodeSet1.title
FROM [nt:base] AS nodeSet1 
ORDER BY nodeSet1.title,
         SCORE(nodeSet1)</programlisting></entry>
						</row>
					</tbody>
				</tgroup>
			</table>
			<para>
				Note that the JCR-SQL2 language supported by ModeShape has a far richer <code>ORDER BY</code> clause,
				allowing the use of any kind of dynamic operand, including ordering upon arithmetic operations
				of multiple dynamic operands.
			</para>
		</sect2>
	  <sect2 id="jcr-xpath-misc">	
	    <title>Miscellaneous</title>
			<para>
				JCR 1.0 defines a number of other optional and required features, and these are summarized in this section.
	      <itemizedlist>
	        <listitem>
		        <para>
			        Only abbreviated XPath syntax is supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        Only the <code>child</code> axis (the default axis, represented by '/' in abbreviated syntax),
							<code>descendant-or-self</code> axis (represented by '//' in abbreviated syntax), 
							<code>self</code> axis (represented by '.' in abbreviated syntax),
							and <code>attribute</code> axis (represent by '@' in abbreviated syntax) are supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        The <code>text()</code> node test is <emphasis>not</emphasis> supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        The <code>element()</code> node test is supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        The <code>jcr:like()</code> function is supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        The <code>jcr:contains()</code> function is supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        The <code>jcr:score()</code> function is supported.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        The <code>jcr:deref()</code> function is <emphasis>not</emphasis> supported.
		        </para>
	        </listitem>
				</itemizedlist>
			</para>
		</sect2>
	</sect1>
  <sect1 id="jcr-sql-query-language">	
    <title>JCR-SQL Query Language</title>
	  <para>
		  The JCR-SQL query language is defined by the <ulink url="&JSR170;">JCR 1.0 specification</ulink> as a way to express
		  queries using strings that are similar to SQL. Support for the language is optional, and in fact this language
		  was deprecated in the <ulink url="&JSR283;">JCR 2.0 specification</ulink> in favor of the improved and more powerful 
		  (and more SQL-like) <link linkend="jcr-sql2-query-language">JCR-SQL2</link> language, which is covered in the next section.
		</para>
		<para>
			The JCR 2.0 specification defines how nodes in a repository are mapped onto relational tables queryable through a
			SQL-like language, including JCR-SQL and <link linkend="jcr-sql-query-language">JCR-SQL2</link>. 
			Basically, each node type is mapped as a relational view with a single column for each
			of the node type's (residual and non-residual) property definitions. Conceptually, each node in the repository then appears as a record inside
			the view corresponding to the node type for which "<code>Node.isNodeType(nodeTypeName)</code>" would return true.
		</para>
		<para>
			Since each node likely returns true from this method for multiple node type (e.g., the primary node type, the mixin types,
			and all supertypes of the primary and mixin node types), all nodes will likely appear as records in multiple views.
			And since each view only exposes those properties defined by (or inherited by) the corresponding node type,
			a full picture of a node will likely require joining the views for multiple node types. This special kind of join,
			where the nodes have the same identity on each side of the join, is referred to as an identity join, and is
			handled very efficiently by ModeShape.
		</para>
		<para>
		  ModeShape includes support for the JCR-SQL language, and adds several extensions to make it even more powerful and useful:
      <itemizedlist>
        <listitem>
          <para>
	          Support for the <code>UNION</code>, <code>INTERSECT</code>, and <code>EXCEPT</code> set operations on multiple result
	          sets to form a single result set. As with standard SQL, the result sets being combined must have the same columns.
	          The <code>UNION</code> operator combines the rows from two result sets, the <code>INTERSECT</code> operator returns
	          the difference between two result sets, and the <code>EXCEPT</code> operator returns the rows that are common to
	          two result sets.  Duplicate rows are removed unless the operator is followed by the <code>ALL</code> keyword.
						For detail, see the <link linkend="jcr-sql-queries">grammar for set queries</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
		        Removal of duplicate rows in the results, using "<code>SELECT DISTINCT ...</code>".
	        </para>
        </listitem>
        <listitem>
	        <para>
		        Limiting the number of rows in the result set with the "<code>LIMIT count</code>" clause, where <code>count</code>
		        is the maximum number of rows that should be returned.  This clause may optionally be followed by the
						"<code>OFFSET number</code>" clause to specify the number of initial rows that should be skipped.
	        </para>
        </listitem>
        <listitem>
	        <para>
						Support for the <code>IN</code> and <code>NOT IN</code> clauses to more easily and concisely supply multiple
						of discrete static operands.
						For example, "<code>WHERE ... prop1 IN (3,5,7,10,11,50) ...</code>".
	        </para>
        </listitem>
        <listitem>
	        <para>
						Support for the <code>BETWEEN</code> clause to more easily and concisely supply a range of discrete operands.
						For example, "<code>WHERE ... prop1 BETWEEN 3 EXCLUSIVE AND 10 ...</code>".
	        </para>
        </listitem>
        <listitem>
	        <para>
						Support for (non-correlated) subqueries in the <code>WHERE</code> clause, wherever a <emphasis>static operand</emphasis> can be used.
						Subqueries can even be used within another subquery. All subqueries must return a single column, and each row's single
						value will be treated as a literal value. If the subquery is used in a clause that expects a single value 
						(e.g., in a comparison), only the subquery's first row will be used. If the subquery is used in a clause that
						allows multiple values (e.g., <code>IN (...)</code>), then all of the subquery's rows will be used.
						For example, this query "<code>WHERE ... prop1 IN ( SELECT my:prop2 FROM my:type2 WHERE my:prop3 &lt; '1000' ) AND ...</code>"
						will use the results of the subquery as the literal values in the <code>IN</code> clause.
	        </para>
        </listitem>
      </itemizedlist>
		</para>
		<para>
			The grammar for the JCR-SQL query language is actually a superset of that defined by the
			<ulink url="&JSR170;">JCR 1.0 specification</ulink>, and as such the complete grammar is included here.
		</para>
		<note>
			<para>
				The grammar is presented using the same EBNF nomenclature as used in the JCR 1.0 specification.
				Terms are surrounded by '[' and ']' denote optional terms that appear zero or one times. 
				Terms surrounded by '{' and '}' denote terms that appear zero or more times.
				Parentheses are used to identify groups, and are often used to surround possible values.
				Literals (or keywords) are denoted by single-quotes. 
			</para>
		</note>
			<sect2 id="jcr-sql-queries">
				<title>Queries</title>
<programlisting><![CDATA[
QueryCommand ::= Query | SetQuery

SetQuery ::= Query ('UNION'|'INTERSECT'|'EXCEPT') ['ALL'] Query
                 { ('UNION'|'INTERSECT'|'EXCEPT') ['ALL'] Query }

Query ::= Select From [Where] [OrderBy] [Limit]

Select ::= 'SELECT' ('*' | Proplist ) 

From ::= 'FROM' NtList 

Where ::= 'WHERE' WhereExp

OrderBy ::= 'ORDER BY' propname [Order] {',' propname [Order]}

Order ::= 'DESC' | 'ASC'

Proplist ::= propname {',' propname}

NtList ::= ntname {',' ntname}

WhereExp ::= propname Op value |
             propname 'IS' ['NOT'] 'NULL' |
             like | 
             contains | 
             whereexp ('AND'|'OR') whereexp | 
             'NOT' whereexp |
             '(' whereexp ')' | 
             joinpropname '=' joinpropname |
             between |
             propname ['NOT'] 'IN' '(' value {',' value } ')'

Op ::= '='|'>'|'<'|'>='|'<='|'<>'

joinpropname ::= quotedjoinpropname | unquotedjoinpropname
quotedjoinpropname ::= ''' unquotedjoinpropname '''
unquotedjoinpropname ::= ntname '.jcr:path'

propname ::= quotedpropname | unquotedpropname
quotedpropname ::= ''' unquotedpropname '''
unquotedpropname ::= /* A property name, possible a pseudo-property: jcr:score or jcr:path */

ntname ::= quotedntname | unquotedntname 
quotedntname ::= ''' unquotedntname ''' 
unquotedntname ::= /* A node type name */ 

value ::= literal | subquery

literal ::= ''' literalvalue ''' | literalvalue
literalvalue ::= /* A property value (in standard string form) */

subquery ::= '(' QueryCommand ')' | QueryCommand

like ::= propname 'LIKE' likepattern [ escape ]
likepattern ::= ''' likechar { likepattern } '''
likechar ::= char | '%' | '_'

escape ::= 'ESCAPE' ''' likechar '''

char ::= /* Any character valid within the string representation of a value
            except for the characters % and _ themselves. These must be escaped */

contains ::= 'CONTAINS(' scope ',' searchexp ')'
scope ::= unquotedpropname | '.'
searchexp ::= ''' exp '''
exp ::= ['-']term {whitespace ['OR'] whitespace ['-']term}
term ::= word | '"' word {whitespace word} '"'
word ::= /* A string containing no whitespace */
whitespace ::= /* A string of only whitespace*/

between ::= propname ['NOT'] 'BETWEEN' lowerBound ['EXCLUSIVE'] 
                                 'AND' upperBound ['EXCLUSIVE']
lowerBound ::= value
upperBound ::= value

Limit ::= 'LIMIT' count [ 'OFFSET' offset ]
count ::= /* Positive integer value */
offset ::= /* Non-negative integer value */
]]></programlisting>
			</sect2>
	</sect1>
  <sect1 id="jcr-sql2-query-language">	
    <title>JCR-SQL2 Query Language</title>
	  <para>
		  The JCR-SQL2 query language is defined by the <ulink url="&JSR283;">JCR 2.0 specification</ulink> as a way to express
		  queries using strings that are similar to SQL. This query language is an improvement over the JCR-SQL language,
		  providing among other things far richer specifications of joins and criteria.
		</para>
		<para>
		  ModeShape includes full support for the complete JCR-SQL2 query language. 
		  However, ModeShape adds several extensions to make it even more powerful:
      <itemizedlist>
        <listitem>
	        <para>
		        Support for the "<code>FULL OUTER JOIN</code>" and "<code>CROSS JOIN</code>" join types, in addition to the
		        "<code>LEFT OUTER JOIN</code>", "<code>RIGHT OUTER JOIN</code>" and "<code>INNER JOIN</code>" types defined by
		  			JCR-SQL2. Note that "<code>JOIN</code>" is a shorthand for "<code>INNER JOIN</code>".
						For detail, see the <link linkend="jcr-sql2-joins">grammar for joins</link>.
	        </para>
        </listitem>
        <listitem>
          <para>
	          Support for the <code>UNION</code>, <code>INTERSECT</code>, and <code>EXCEPT</code> set operations on multiple result
	          sets to form a single result set. As with standard SQL, the result sets being combined must have the same columns.
	          The <code>UNION</code> operator combines the rows from two result sets, the <code>INTERSECT</code> operator returns
	          the difference between two result sets, and the <code>EXCEPT</code> operator returns the rows that are common to
	          two result sets.  Duplicate rows are removed unless the operator is followed by the <code>ALL</code> keyword.
						For detail, see the <link linkend="jcr-sql2-queries">grammar for set queries</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
		        Removal of duplicate rows in the results, using "<code>SELECT DISTINCT ...</code>".
						For detail, see the <link linkend="jcr-sql2-queries">grammar for queries</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
		        Limiting the number of rows in the result set with the "<code>LIMIT count</code>" clause, where <code>count</code>
		        is the maximum number of rows that should be returned.  This clause may optionally be followed by the
						"<code>OFFSET number</code>" clause to specify the number of initial rows that should be skipped.
						For detail, see the <link linkend="jcr-sql2-limits">grammar for limits and offsets</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
						Additional dynamic operands "<code>DEPTH([&lt;selectorName>])</code>" and "<code>PATH([&lt;selectorName>])</code>"
						that enable placing constraints on the node depth and path, respectively.  These dynamic operands 
						can be used in a manner similar to "<code>NAME([&lt;selectorName>])</code>" and "<code>LOCALNAME([&lt;selectorName>])</code>"
						that are defined by JCR-SQL2.  Note in each of these cases, the selector name is optional if there is only one
						selector in the query.
						For detail, see the <link linkend="jcr-sql2-dynamic-operands">grammar for dynamic operands</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
						Additional dynamic operand "<code>REFERENCE([&lt;selectorName>.]&lt;propertyName>)</code>" and
						"<code>REFERENCE([&lt;selectorName>])</code>" that
						enables placing constraints on one or any of the reference properties, respectively, and which can be used in a manner similar to "
						<code>PropertyValue([&lt;selectorName>.]&lt;propertyName>)</code>". Note in each of these cases, the
						selector name is optional if there is only one selector in the query, and that the property name can be excluded
						if the constraint should apply to all reference properties.
						For detail, see the <link linkend="jcr-sql2-dynamic-operands">grammar for dynamic operands</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
						Support for the <code>IN</code> and <code>NOT IN</code> clauses to more easily and concisely supply multiple
						of discrete static operands.
						For example, "<code>WHERE ... [my:type].[prop1] IN (3,5,7,10,11,50) ...</code>".
						For detail, see the <link linkend="jcr-sql2-set-constraints">grammar for set constraints</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
						Support for the <code>BETWEEN</code> clause to more easily and concisely supply a range of discrete operands.
						For example, "<code>WHERE ... [my:type].[prop1] BETWEEN 3 EXCLUSIVE AND 10 ...</code>".
						For detail, see the <link linkend="jcr-sql2-between-constraints">grammar for between constraints</link>.
	        </para>
        </listitem>
        <listitem>
	        <para>
						Support for simple arithmetic in numeric-based criteria and order-by clauses.  For example, 
						"<code>... WHERE</code> <code>SCORE(type1) +</code> <code>SCORE(type2) > 1.0</code>" or 
						"<code>... ORDER BY</code> <code>(SCORE(type1) * SCORE(type2)) ASC,</code> <code>LENGTH(type2.property1) DESC</code>".
						For detail, see the <link linkend="jcr-sql2-ordering">grammar for order-by clauses</link>.
					</para>
        </listitem>
        <listitem>
	        <para>
						Support for (non-correlated) subqueries in the <code>WHERE</code> clause, wherever a <emphasis>static operand</emphasis> can be used.
						Subqueries can even be used within another subquery. All subqueries must return a single column, and each row's single
						value will be treated as a literal value. If the subquery is used in a clause that expects a single value 
						(e.g., in a comparison), only the subquery's first row will be used. If the subquery is used in a clause that
						allows multiple values (e.g., <code>IN (...)</code>), then all of the subquery's rows will be used.
						For example, this query "<code>WHERE ... [my:type].[prop1] IN (</code> <code>SELECT [my:prop2] FROM [my:type2]</code> <code> WHERE [my:prop3] &lt; '1000' ) AND ...</code>"
						will use the results of the subquery as the literal values in the <code>IN</code> clause.
	        </para>
        </listitem>
        <listitem>
	        <para>
		        Support for several pseudo-columns ("<code>jcr:path</code>", "<code>jcr:score</code>", "<code>jcr:name</code>",
						"<code>mode:localName</code>", and "<code>mode:depth</code>") that can be used in the <code>SELECT</code>,
						<link linkend="jcr-sql2-equijoin">equijoin</link>, and <code>WHERE</code> clauses. These pseudo-columns
						make it possible to return location-related and score information within the &QueryResult;'s rows.
						They also make queries look more like SQL, and thus may be more friendly and easier to use in existing
						SQL-aware client applications. See the <link linkend="jcr-sql2-pseudo-columns">detailed description</link>
						for more information.
	        </para>
        </listitem>
      </itemizedlist>
		</para>
		<para>
			The grammar for the JCR-SQL2 query language is actually a superset of that defined by the
			<ulink url="&JSR283;">JCR 2.0 specification</ulink>, and as such the complete grammar is included here.
		</para>
		<note>
			<para>
				The grammar is presented using the same EBNF nomenclature as used in the JCR 2.0 specification.
				Terms are surrounded by '[' and ']' denote optional terms that appear zero or one times. 
				Terms surrounded by '{' and '}' denote terms that appear zero or more times.
				Parentheses are used to identify groups, and are often used to surround possible values.
				Literals (or keywords) are denoted by single-quotes. 
			</para>
		</note>
			<sect2 id="jcr-sql2-queries">
				<title>Queries</title>
<programlisting><![CDATA[
QueryCommand ::= Query | SetQuery

SetQuery ::= Query ('UNION'|'INTERSECT'|'EXCEPT') ['ALL'] Query
                 { ('UNION'|'INTERSECT'|'EXCEPT') ['ALL'] Query }

Query ::= 'SELECT' ['DISTINCT'] columns
          'FROM' Source
          ['WHERE' Constraint]
          ['ORDER BY' orderings]
          [Limit]
]]></programlisting>
			</sect2>
			<sect2>
				<title>Sources</title>
<programlisting><![CDATA[
Source ::= Selector | Join

Selector ::= nodeTypeName ['AS' selectorName]

nodeTypeName ::= Name

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-joins">
				<title>Joins</title>
<programlisting><![CDATA[
	
Join ::= left [JoinType] 'JOIN' right 'ON' JoinCondition
         // If JoinType is omitted INNER is assumed.

left ::= Source
right ::= Source

JoinType ::= Inner | LeftOuter | RightOuter | FullOuter | Cross

Inner ::= 'INNER' ['JOIN']

LeftOuter ::= 'LEFT JOIN' | 'OUTER JOIN' | 'LEFT OUTER JOIN'

RightOuter ::= 'RIGHT OUTER' ['JOIN']

RightOuter ::= 'FULL OUTER' ['JOIN']

RightOuter ::= 'CROSS' ['JOIN']

JoinCondition ::= EquiJoinCondition | SameNodeJoinCondition | 
                  ChildNodeJoinCondition | DescendantNodeJoinCondition

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-equijoin">
				<title>Equi-Join Conditions</title>
<programlisting><![CDATA[
	
EquiJoinCondition ::= selector1Name'.'property1Name '=' selector2Name'.'property2Name

selector1Name ::= selectorName
selector2Name ::= selectorName
property1Name ::= propertyName
property2Name ::= propertyName

]]></programlisting>
			</sect2>
			<sect2>
				<title>Same-Node Join Conditions</title>
<programlisting><![CDATA[
	
SameNodeJoinCondition ::= 'ISSAMENODE(' selector1Name ',' selector2Name [',' selector2Path] ')'

selector2Path ::= Path

]]></programlisting>
			</sect2>
			<sect2>
				<title>Child-Node Join Conditions</title>
<programlisting><![CDATA[
	
ChildNodeJoinCondition ::= 'ISCHILDNODE(' childSelectorName ',' parentSelectorName ')'

childSelectorName ::= selectorName
parentSelectorName ::= selectorName

]]></programlisting>
			</sect2>
			<sect2>
				<title>Descendant-Node Join Conditions</title>
<programlisting><![CDATA[
	
DescendantNodeJoinCondition ::= 'ISDESCENDANTNODE(' descendantSelectorName 
                                                ',' ancestorSelectorName ')'
descendantSelectorName ::= selectorName
ancestorSelectorName ::= selectorName

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-constraints">
				<title>Constraints</title>
<programlisting><![CDATA[
	
Constraint ::= ConstraintItem | '(' ConstraintItem ')'

ConstraintItem ::= And | Or | Not | Comparison | Between | PropertyExistence | 
                   SetConstraint | FullTextSearch | SameNode | ChildNode | DescendantNode

]]></programlisting>
			</sect2>
			<sect2>
				<title>And Constraints</title>
<programlisting><![CDATA[

And ::= constraint1 'AND' constraint2

constraint1 ::= Constraint
constraint2 ::= Constraint

]]></programlisting>
			</sect2>
			<sect2>
				<title>Or Constraints</title>
<programlisting><![CDATA[
	
Or ::= constraint1 'OR' constraint2

]]></programlisting>
			</sect2>
			<sect2>
				<title>Not Constraints</title>
<programlisting><![CDATA[
	
Not ::= 'NOT' Constraint

]]></programlisting>
			</sect2>
			<sect2>
				<title>Comparison Constraints</title>
<programlisting><![CDATA[
	
Comparison ::= DynamicOperand Operator StaticOperand

Operator ::= '=' | '!=' | '<' | '<=' | '>' | '>=' | 'LIKE'

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-between-constraints">
				<title>Between Constraints</title>
<programlisting><![CDATA[
	
Between ::= DynamicOperand ['NOT'] 'BETWEEN' lowerBound ['EXCLUSIVE'] 
                                   'AND' upperBound ['EXCLUSIVE']

lowerBound ::= StaticOperand
upperBound ::= StaticOperand

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-property-existence-constraints">
				<title>Property Existence Constraints</title>
<programlisting><![CDATA[
	
PropertyExistence ::= selectorName'.'propertyName 'IS' ['NOT'] 'NULL' | 
                      propertyName 'IS' ['NOT'] 'NULL' /* If only one selector exists in this query */

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-set-constraints">
				<title>Set Constraints</title>
<programlisting><![CDATA[

SetConstraint ::= selectorName'.'propertyName ['NOT'] 'IN' | 
                      propertyName ['NOT'] 'IN' /* If only one selector exists in this query */
                      '(' firstStaticOperand {',' additionalStaticOperand } ')'
firstStaticOperand ::= StaticOperand
additionalStaticOperand ::= StaticOperand

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-full-text-search-constraints">
				<title>Full-text Search Constraints</title>
<programlisting><![CDATA[
	
FullTextSearch ::= 'CONTAINS(' ([selectorName'.']propertyName | selectorName'.*') 
                           ',' ''' fullTextSearchExpression''' ')'
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the propertyName is optional */

fullTextSearchExpression ::= FulltextSearch

]]></programlisting>
			<para> where <code>FulltextSearch</code> is defined by the following, and is the same as the
			  <link linkend='fulltext-search-expressions'>full-text search language</link> supported by ModeShape:
			</para>
<programlisting><![CDATA[

FulltextSearch ::= Disjunct {Space 'OR' Space Disjunct}

Disjunct ::= Term {Space Term}

Term ::= ['-'] SimpleTerm

SimpleTerm ::= Word | '"' Word {Space Word} '"'

Word ::= NonSpaceChar {NonSpaceChar}

Space ::= SpaceChar {SpaceChar}

NonSpaceChar ::= Char - SpaceChar /* Any Char except SpaceChar */

SpaceChar ::= ' '

Char ::= /* Any character */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Same-Node Constraint</title>
<programlisting><![CDATA[
	
SameNode ::= 'ISSAMENODE(' [selectorName ','] Path ')' 
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the path is optional */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Child-Node Constraints</title>
<programlisting><![CDATA[

ChildNode ::= 'ISCHILDNODE(' [selectorName ','] Path ')' 
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the path is optional */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Descendant-Node Constraints</title>
<programlisting><![CDATA[

DescendantNode ::= 'ISDESCENDANTNODE(' [selectorName ','] Path ')' 
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the propertyName is optional */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Paths and Names</title>
<programlisting><![CDATA[

Name ::= '[' quotedName ']' | '[' simpleName ']' | simpleName

quotedName ::= /* A JCR Name (see the JCR specification) */
simpleName ::= /* A JCR Name that contains only SQL-legal 
                  characters (namely letters, digits, and underscore) */

Path ::= '[' quotedPath ']' | '[' simplePath ']' | simplePath

quotedPath ::= /* A JCR Path that contains non-SQL-legal characters */
simplePath ::= /* A JCR Path (rather Name) that contains only SQL-legal 
                    characters (namely letters, digits, and underscore) */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Static Operands</title>
<programlisting><![CDATA[
	
StaticOperand ::= Literal | BindVariableValue | Subquery

Literal
Literal ::= CastLiteral | UncastLiteral

CastLiteral ::= 'CAST(' UncastLiteral ' AS ' PropertyType ')'

PropertyType ::= 'STRING' | 'BINARY' | 'DATE' | 'LONG' | 'DOUBLE' | 'DECIMAL' | 
                 'BOOLEAN' | 'NAME' | 'PATH' | 'REFERENCE' | 'WEAKREFERENCE' | 'URI'
                 /* 'WEAKREFERENCE' is not currently supported in JCR 1.0 */

UncastLiteral ::= UnquotedLiteral | ''' UnquotedLiteral ''' | '"' UnquotedLiteral '"'

UnquotedLiteral ::= /* String form of a JCR Value, as defined in the JCR specification */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Bind Variables</title>
<programlisting><![CDATA[
	
BindVariableValue ::= '$'bindVariableName

bindVariableName ::= /* A string that conforms to the JCR Name syntax, though the prefix
                        does not need to be a registered namespace prefix. */

]]></programlisting>
			</sect2>
			<sect2>
				<title>Subqueries</title>
<programlisting><![CDATA[

Subquery ::= '(' QueryCommand  ')' |
             QueryCommand

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-dynamic-operands">
				<title>Dynamic Operands</title>
<programlisting><![CDATA[
	
DynamicOperand ::= PropertyValue | ReferenceValue | Length | NodeName | NodeLocalName | NodePath |
                   NodeDepth | FullTextSearchScore | LowerCase | UpperCase | Arithmetic | 
                   '(' DynamicOperand ')'

PropertyValue ::= [selectorName'.'] propertyName
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the propertyName is optional */

ReferenceValue ::= 'REFERENCE(' selectorName '.' propertyName ')' |
                   'REFERENCE(' selectorName ')' |
                   'REFERENCE()' |
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the propertyName is optional. Also, the property name may be excluded 
                      if the constraint should apply to any reference property. *&#47;

Length ::= 'LENGTH(' PropertyValue ')'

NodeName ::= 'NAME(' [selectorName] ')'
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      is optional */

NodeLocalName ::= 'LOCALNAME(' [selectorName] ')'
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      is optional */

NodePath ::= 'PATH(' [selectorName] ')'
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      is optional */

NodeDepth ::= 'DEPTH(' [selectorName] ')'
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      is optional */

FullTextSearchScore ::= 'SCORE(' [selectorName] ')'
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      is optional */

LowerCase ::= 'LOWER(' DynamicOperand ')'

UpperCase ::= 'UPPER(' DynamicOperand ')'

Arithmetic ::= DynamicOperand ('+'|'-'|'*'|'/') DynamicOperand

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-ordering">
				<title>Ordering</title>
<programlisting><![CDATA[
	
orderings ::= Ordering {',' Ordering}

Ordering ::= DynamicOperand [Order]

Order ::= 'ASC' | 'DESC'

]]></programlisting>
			</sect2>
			<sect2>
				<title>Columns</title>
<programlisting><![CDATA[
	
columns ::= (Column ',' {Column}) | '*'

Column ::= ([selectorName'.']propertyName ['AS' columnName]) | (selectorName'.*')
                   /* If only one selector exists in this query, explicit specification of the selectorName
                      preceding the propertyName is optional */
selectorName ::= Name
propertyName ::= Name
columnName ::= Name

]]></programlisting>
			</sect2>
			<sect2 id="jcr-sql2-limits">
				<title>Limit and Offset</title>
<programlisting><![CDATA[
	
Limit ::= 'LIMIT' count [ 'OFFSET' offset ]
count ::= /* Positive integer value */
offset ::= /* Non-negative integer value */
]]></programlisting>
		</sect2>
		<sect2 id="jcr-sql2-pseudo-columns">
			<title>Pseudo-columns</title>
      <para>
				The design of the JCR-SQL2 query language makes fairly heavy use of functions, including 
				<code>SCORE()</code>, <code>NAME()</code>, and <code>LOCALNAME()</code>. ModeShape adds several
				more useful functions, including <code>PATH()</code> and <code>DEPTH()</code>, that follow the
				same patterns.
			</para>
			<para>
				However, there are several disadvantages of these functions. First, they make the JCR-SQL2 language
				less "SQL-like", since SQL-92 and -99 don't define these kinds of functions. (There are aggregate
				functions, like <code>COUNT</code>, <code>SUM</code>, etc., but they are not terribly analogous.)
				This means that applications that use SQL and SQL-like query languages are less likely to be
				able to build and issue JCR-SQL2 queries.
			</para>
			<para>
				A second disadvantage of these functions is that JCR-SQL2 does not allow them to be used within
				the <code>SELECT</code> clause. As a result, the location-related and score information cannot
				be included as columns of values in the &QueryResult; rows. Instead, a client can <emphasis>only</emphasis>
				access this information by obtaining the &Node; object(s) for each row. Relying upon both the result
				set and additional Java objects makes it difficult to use.
			</para>
			<para>
				For example, ModeShape's JDBC driver is designed to enable JDBC-aware applications to query
				repository content using JCR-SQL2 queries. The standard JDBC API cannot expose the &Node; objects,
				so the only way to return the path-related and score information is through additional columns
				in the result. While such columns could "magically" appear in the result set, doing this is
				not compatible with JDBC applications that dynamically build queries based upon database metadata.
				Such applications require the columns to be properly described in database metadata, and the
				columns need to be used within queries.
			</para>
			<para>
				ModeShape attempts to solve these issues by directly supporting a number of "pseudo-columns"
				within JCR-SQL2 queries, wherever columns can be used. These "pseudo-columns" include:
				<itemizedlist>
	        <listitem>
		        <para>
			        <emphasis mode="strong"><code>jcr:score</code></emphasis> is a column of type DOUBLE that
							represents the full-text search score of the node, which is a measure of the node's
							relevance to the full-text search expression. ModeShape does compute the scores for all
							queries, though the score for rows in queries that do not include a full-text search
							criteria may not be reliable.
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        <emphasis mode="strong"><code>jcr:path</code></emphasis> is a column of type PATH that
							represents the normalized path of a node, including same-name siblings. This is the same 
							as what would be returned by the <code>getPath()</code> method of &Node;. 
							Examples of paths include "/jcr:system" and "/foo/bar[3]".
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        <emphasis mode="strong"><code>jcr:name</code></emphasis> is a column of type NAME that
			 				represents the node name in its namespace-qualified form using namespace prefixes and 
							excluding same-name-sibling indexes. 
			        Examples of node names include "jcr:system", "jcr:content", "ex:UserData", and "bar".
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        <emphasis mode="strong"><code>mode:localName</code></emphasis> is a column of type STRING that
							represents the local name of the node, which excludes the namespace prefix and same-name-sibling index. 
							As an example, the local name of the "jcr:system" node is "system", while the local name 
							of the "ex:UserData[3]" node is "UserData".
		        </para>
	        </listitem>
	        <listitem>
		        <para>
			        <emphasis mode="strong"><code>mode:depth</code></emphasis> is a column  of type LONG that
							represents the depth of a node, which corresponds exactly to the number of path segments within the path. 
							For example, the depth of the root node is 0, whereas the depth of the "/jcr:system/jcr:nodeTypes" node is 2.
		        </para>
	        </listitem>
	      </itemizedlist>
			</para>
			<para>
				All of these pseudo-columns can be used in the <code>SELECT</code> clause of any JCR-SQL2 query, and their
				use defines whether such columns appear in the result set. In fact, all of these pseudo-columns will be included
				when "<code>SELECT *</code>" clauses in JCR-SQL2 queries are expanded by the query engine. 
				This means that every node type (even mixin node types that have no properties and are essentially markers) 
				are represented by a queryable table.
			</para>
			<para>
				Like any other column, all of these pseudo-columns can be also be used in the <code>WHERE</code> clause of any JCR-SQL2 query, even
				if they are not included in the <code>SELECT</code> clause. They can be used anywhere that a regular column
				can be used, including within <link linkend="jcr-sql2-constraints">constraints</link> and 
				<link linkend="jcr-sql2-dynamic-operands">dynamic operands</link>. ModeShape will automatically rewrite
				queries that use pseudo-columns in the dynamic operands to use the corresponding function, such as
				<code>SCORE()</code>, <code>PATH()</code>, <code>NAME()</code>, <code>LOCALNAME()</code>, and <code>DEPTH()</code>.
				Additionally, any <link linkend="jcr-sql2-property-existence-constraints">property existence constraint</link> using
				these pseudo-columns will always evaluate to 'true'	(and will thus be removed by the optimizer).
			</para>
			<para>
				The <code>jcr:path</code> pseudo-column may also be used on both sides of an <link linkend="jcr-sql2-equijoin">equijoin constraint</link>
				clause. For example:
			</para>
			<programlisting><![CDATA[ ... selector1.[jcr:path] = selector2.[jcr:path] ... ]]></programlisting>
			<para>
				Equijoins of this form will be automatically rewritten by the optimizer to the following form:
			</para>
			<programlisting><![CDATA[ ... ISSAMENODE(selector1,selector2) ... ]]></programlisting>
			<para>
				As with regular columns, the pseudo-columns must be qualified with the selector name if the query
				contains more than one selector.
			</para>
			<note>
				<para>
					Note that the <code>jcr:path</code> and <code>jcr:score</code> pseudo-columns are consistent with
					the pseudo-columns of the same names used in <link linkend="jcr-sql-query-language">JCR-SQL</link>
					query language. However, unlike in JCR-SQL, in JCR-SQL2 these columns are not automatically included
					in the results unless explicitly included in the <code>SELECT</code> clause or implicitly included 
					via "<code>SELECT *</code>"
				</para>
			</note>
		</sect2>
		<sect2 id="jcr-sql2-examples">
			<title>Example JCR-SQL2 queries</title>
      <para>
				One of the simplest JCR-SQL2 queries finds all nodes in the current workspace of the repository:
      </para>
			<programlisting><![CDATA[ SELECT * FROM [nt:base] ]]></programlisting>
      <para>
				This query will return a result set containing the "<code>jcr:primaryType</code>" column, since the <code>nt:base</code> defines only
				one single-valued property called "<code>jcr:primaryType</code>". (As allowed by the JCR 2.0 Specification, ModeShape does not 
				currently support returning multi-valued columns in result sets, and thus the above query does not include a column for the
				<code>jcr:mixinTypes</code> multi-valued property.) 
      </para>
      <para>
				Since our query used "<code>SELECT *</code>", ModeShape also includes the non-standard pseudo-columns mentioned above: 
				"<code>jcr:path</code>", "<code>jcr:score</code>", "<code>jcr:name</code>", "<code>mode:localName</code>", and "<code>mode:depth</code>".
				These columns are very convenient to have in the results, but also make certain criteria much easier than with the corresponding
				standard or ModeShape-specific functions.
      </para>
      <para>
				Queries can explicitly specify the columns that are to be returned in the results. The following query is very similar to the
				previous query and will return the same rows, but the result set will have only a single column:
      </para>
			<programlisting><![CDATA[ SELECT [jcr:primaryType] FROM [nt:base] ]]></programlisting>
      <para>
			  The following query will return the same rows as in the previous two queries, but the SELECT clause explicitly includes only
			  two of the pseudo-columns for the path and depth (which are computed from the nodes' locations):
      </para>
			<programlisting><![CDATA[ SELECT [jcr:primaryType], [jcr:path], [mode:depth] FROM [nt:base] ]]></programlisting>
      <para>
				In JCR-SQL2, a table representing a particular node type will have a column for each of the node type's property definitions,
				including those inherited from supertypes. For example, the <code>nt:file</code> node type, its <code>nt:hierarchyNode</code>
				supertype, and the <code>mix:created</code> mixin type are defined using the CND notation as follows:
			</para>	
			<programlisting><![CDATA[
[mix:created] mixin 
  - jcr:created (date) protected  
  - jcr:createdBy (string) protected

[nt:hierarchyNode] > mix:created abstract 

[nt:file] > nt:hierarchyNode 
  + jcr:content (nt:base) primary mandatory
]]></programlisting>
			<para>
				Therefore, the table representing the <code>nt:file</code> node type will have two three columns: the <code>jcr:created</code>
				and <code>jcr:createdBy</code> columns inherited from the <code>mix:created</code> mixin node type (via the <code>nt:hierarchyNode</code> node type),
				and the <code>jcr:primaryType</code> column inherited from the <code>nt:base</code> node type, which is the implicit supertype
				of the <code>nt:hierarchyNode</code>. 
			</para>
			<para>
			  ModeShape adheres to this behavior with the exception that a "<code>SELECT *</code>" will result in the additional pseudo-columns.
				Thus, this next query:
			</para>
			<programlisting><![CDATA[ SELECT * FROM [nt:file] ]]></programlisting>
			<para>
				is equivalent to this query:
			</para>
			<programlisting><![CDATA[
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], 
       [jcr:path], [jcr:name], [jcr:score], [mode:localName], [mode:depth] 
FROM [nt:file] ]]></programlisting>
			<para>
				Here is an example query that selects some of the available columns from the <code>nt:file</code> table and uses a constraint
				to ensure the resulting file nodes have names that end in '.txt':
			</para>
			<programlisting><![CDATA[
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:file] 
WHERE LOCALNAME() LIKE '%.txt'
]]></programlisting>
		  <para>
				This query is JCR-SQL2, but ModeShape supports placing criteria against the <code>mode:localName</code> pseudo-column instead of 
				using the <code>LOCALNAME()</code> function. Such a query is equivalent to the previous query and will produce the exact same results:
			</para>
			<programlisting><![CDATA[
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:file] 
WHERE [mode:localName] LIKE '%.txt'
]]></programlisting>
		  <para>
				Although this query looks much more like SQL, the use of the '[' and ']' characters to quote the identifiers is not typical of
				a SQL dialect. ModeShape actually supports the using double-quote characters and square braces interchangeably around identifiers
				(although they must match around any single identifier). Again, this next query,
				which looks remarkably like any SQL-92 or -99 dialect, is functionally identical to the previous two queries:
			</para>
			<programlisting><![CDATA[
SELECT "jcr:primaryType", "jcr:created", "jcr:createdBy", "jcr:path" FROM "nt:file" 
WHERE "mode:localName" LIKE '%.txt'
]]></programlisting>
		  <para>
				In JCR-SQL2, a node will appear as a row in each table that corresponds to the node types defined by that node's
				primary type or mixin types, or any supertypes of these node types. In other words, a node will appear in the table
				corresponding to each node type for which <code>Node.isNodeType(...)</code> returns true.
			</para>
			<para>
				For example, consider a node that has a primary	type of <code>nt:file</code> but has an explicit mixin of <code>mix:referenceable</code>. 
				This node will appear as a row in the all of these tables: <code>nt:file</code>, <code>mix:referenceable</code>, <code>nt:hierarchyNode</code>, 
				<code>mix:created</code>, and <code>nt:base</code>. However, the columns in each of these tables will differ.
				The <code>nt:file</code> node type has the <code>nt:hierarchyNode</code>, <code>mix:created</code>, and <code>nt:base</code> for supertypes,
				and therefore the table for <code>nt:file</code> contains columns for the property definitions on all of these types.
				But because <code>mix:referenceable</code> is <emphasis>not</emphasis> a supertype of <code>nt:file</code>, the
				table for <code>nt:file</code> will not contain a <code>jcr:uuid</code> column. To obtain a single result set that contains
				columns for all the properties of our node, we need to perform an <emphasis>identity</emphasis> join. The next
				query shows how this is done to return all properties for <code>nt:file</code> nodes that are
				also <code>mix:referenceable</code>:
			</para>
			<programlisting><![CDATA[
SELECT file.*, ref.* FROM [nt:file] AS file JOIN [mix:referenceable] AS ref
JOIN ON ISSAMENODE(file,ref)
]]></programlisting>
			<para>
				ModeShape expands the SELECT clause to include the columns for all (explicit and inherited) property definitions of each type
				plus pseudo-columns for each type:
			</para>
			<programlisting><![CDATA[
SELECT file.[jcr:primaryType], file.[jcr:created], file.[jcr:createdBy], ref.[jcr:uuid],
       file.[jcr:path], file.[jcr:name], file.[jcr:score], file.[mode:localName], file.[mode:depth],
       ref.[jcr:path], ref.[jcr:name], ref.[jcr:score], ref.[mode:localName], ref.[mode:depth] 
FROM [nt:file] AS file JOIN [mix:referenceable] AS ref
JOIN ON ISSAMENODE(file,ref)
]]></programlisting>
			<para>
			  Note because we are using an identity join, the "<code>file.[jcr:path]</code>" column will contain the same value as the
			  "<code>ref.[jcr:path]</code>". Therefore, as is typical with standard SQL and relational databases, with JCR-SQL2
			  you will probably want to fully expand the SELECT clause to be exactly what you want. Here is a query that does this
			  by eliminating columns with duplicate values and using aliases that are simpler than the namespace-qualified names:
			</para>
			<programlisting><![CDATA[
SELECT file.[jcr:primaryType] AS primaryType, 
       file.[jcr:created] AS created, 
       file.[jcr:createdBy] AS createdBy, 
       ref.[jcr:uuid] AS uuid,
       file.[jcr:path] AS path,
       file.[jcr:name] AS name,
       file.[jcr:score] AS score,
       file.[mode:localName] AS localName, 
       file.[mode:depth] AS depth
FROM [nt:file] AS file JOIN [mix:referenceable] AS ref
JOIN ON ISSAMENODE(file,ref)
]]></programlisting>
			<para>
			  Although this query looks much more like SQL, JCR-SQL2's use of the '[' and ']' characters to quote the identifiers is not typical
			  of a SQL dialect. ModeShape actually supports the using double-quote characters and square braces interchangeably around identifiers 
			  (although they must match around any single identifier). This makes it easier for existing SQL-oriented tools and applications to
			  work more readily with ModeShape, including applications that use ModeShape's JDBC driver to query a ModeShape JCR repository.
			</para>
			<para>
			  Again, this next query, which looks remarkably like any SQL-92 or -99 dialect, is functionally identical to the previous query, except
			  that it uses double quotes and a pseudo-column identity constraint on "<code>jcr:path</code>"
			  (which is identical in semantics and performance as the "<code>ISSAMENODE(...)</code>" constraint):
			</para>
			<programlisting><![CDATA[
SELECT file."jcr:primaryType" AS primaryType, 
       file."jcr:created" AS created, 
       file."jcr:createdBy" AS createdBy, 
       ref."jcr:uuid" AS uuid,
       file."jcr:path" AS path,
       file."jcr:name" AS name,
       file."jcr:score" AS score,
       file."mode:localName" AS localName, 
       file."mode:depth" AS depth
FROM "nt:file" AS file JOIN "mix:referenceable" AS ref
JOIN ON file."jcr:path" = ref."jcr:path"
]]></programlisting>
			<para>
				These are examples of two-way inner joins, but ModeShape supports joining multiple tables together
				in a single query. ModeShape also supports a variety of joins, including <code>INNER JOIN</code> (or just <code>JOIN</code>), 
				<code>LEFT OUTER JOIN</code>, <code>RIGHT OUTER JOIN</code>, <code>FULL OUTER JOIN</code>, and <code>CROSS JOIN</code>.
			</para>
			<para>
				ModeShape also supports several other query features beyond JCR-SQL2. One of these is support for <code>UNION</code>,
				<code>INTERSECT</code>, <code>EXCEPT</code>, <code>UNION ALL</code>,
				<code>INTERSECT ALL</code> and <code>EXCEPT ALL</code>. Here is an example of a union:
			</para>
			<programlisting><![CDATA[
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:file]
UNION
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:folder]
]]></programlisting>
			<para>
				ModeShape also supports using (non-correlated) subqueries within the <code>WHERE</code> clause, wherever a
				<link linkend="jcr-sql2-static-operand">static operand</link> can be used. Subqueries can even be used within 
				another subquery. All subqueries, though, should return a single column (all other columns will be ignored), 
				and each row's single value will be treated as a literal value. 
				If the subquery is used in a clause that expects a single value (e.g., in a comparison), 
				only the subquery's first row will be used.
			</para>
			<para>
				Subqueries in ModeShape are a powerful and easy way to use more complex criteria that is a function of the content
				in the repository, without having to resort to multiple queries (take the results of one query and dynamically
				generate the criteria of another query).
			</para>
			<para>
				Here's an example of a query that finds all <code>nt:file</code> nodes in the repository whose paths are referenced
				in the value of the <code>vdb:originalFile</code> property of the <code>vdb:virtualDatabase</code> nodes. (This query
				also uses the "<code>$maxVersion</code>" bind variables in the subquery.)
			</para>
			<programlisting><![CDATA[
SELECT [jcr:primaryType], [jcr:created], [jcr:createdBy], [jcr:path] FROM [nt:file] 
WHERE PATH() IN ( 
   SELECT [vdb:originalFile] FROM [vdb:virtualDatabase]
   WHERE [vdb:version] <= $maxVersion AND CONTAINS([vdb:description],'xml OR xml maybe')
) ]]></programlisting>
			<para>
				Without subqueries, this query would need to be broken into two separate queries: the first would find all of the
				paths referenced by the <code>vdb:virtualDatabase</code> nodes matching the version and description criteria,
				followed by one (or more) subsequent queries to find the <code>nt:file</code> nodes with the paths expressed
				as literal values (or bind variables). Using a subquery is not only easier to implement and understand, it is actually
				more efficient.
			</para>
			<para>
				The examples shown in this section hopefully begin to show the power and flexibility of JCR-SQL2 and the ModeShape extensions.
      </para>
		</sect2>
	</sect1>
  <sect1 id="fulltext-search-query-language">	
    <title>Full-Text Search Language</title>
	  <para>
		  There are times when a formal structured query language is overkill, and the easiest way to find the right content
		  is to perform a search, like you would with a search engine such as Google or Yahoo! 
		  This is where ModeShape's <emphasis role="strong">full-text search language</emphasis> comes in, because it allows
		  you to use the JCR query API but with a far simpler, Google-style search grammar.
		</para>
		<para>
			This query language is actually defined by the <ulink url="&JSR283;">JCR 2.0 specification</ulink> as the 
			<link linkend="jcr-sql2-full-text-search-constraints">full-text search expression grammar</link>
			used in the second parameter of the <code>CONTAINS(...)</code> function of the JCR-SQL2 language.
			We just pulled it out and made it available as a first-class query language, such that a full-text
			search query supplied by the user, <emphasis>full-text-query</emphasis>, is equivalent to executing this JCR-SQL2:
		</para>
<programlisting><![CDATA[ SELECT * FROM [nt:base] WHERE CONTAINS([nt:base],'full-text-query') ]]></programlisting>
		<para>
			This language allows a JCR client to construct a query to find nodes with property values that match
			the supplied terms. Nodes that "best" match the terms are returned before nodes that have a lesser match.
			Of course, ModeShape uses a complex system to analyze the node content and the query terms, and may perform
			a number of optimizations, such as (but not limited to) eliminating stop words (e.g., "the", "a", "and", etc.), treating terms
			independent of case, and converting words to base forms using a process called <emphasis>stemming</emphasis> (e.g., "running"
			into "run", "customers" into "customer").
		</para>
		<para>
			Search terms can also include phrases by simply wrapping the phrase with double-quotes.  For example, 
			the search term '<code>table "customer invoice"</code>' would rank higher those nodes with properties containing
			the phrase "customer invoice" than nodes with properties containing just "customer" or "invoice".
		</para>
		<para>
			Term in the query are implicitly AND-ed together, meaning that the matches occur when a node has property values
			that match <emphasis>all</emphasis> of the terms. However, it is also possible to put an "OR" in between two terms
			where either of those terms may occur.
		</para>
		<para>
			By default, all terms are assumed to be positive terms, in the sense that the occurrence of the term will increase
			the rank of any nodes containing the value.
			However, it is possible to specify that terms should <emphasis>not</emphasis> appear in the results. This is called
			a <emphasis>negative term</emphasis>, and it reduces the rank of any node whose property values contain the
			the value. To specify a negative term, simply prefix the term with a hyphen ('-').
		</para>
		<para>
			Each term may also contain wildcards to specify the pattern to be matched (or negated). ModeShape supports
			two different sets of wildcards:
      <itemizedlist>
        <listitem>
	        <para>
					 	'*' matches zero or more characters, and '?' matches any single character; and
					</para>
				</listitem>
        <listitem>
	        <para>
					 	'%' matches zero or more characters, and '_' matches any single character.
					</para>
				</listitem>
			</itemizedlist>
			The former are wildcards that are more commonly used in various systems (including older JCR repository implementations), 
			while the latter are the wildcards used in LIKE expressions in both JCR-SQL and JCR-SQL2. Both families are supported
			for convenience, and you can also mix and match	and combine the various wildcards, such as 
			'<code>ta**bl_</code>' and '<code>ta__ble%*</code>'. (Of course, placing multiple '*' or '%' characters next to each other 
			offers no real benefit, as it is equivalent to a single '*' or '%'.)
		</para>
		<para>
			If you want to use these characters literally in a term and do not want them to be treated as wildcards, they
			must be escaped by prefixing them with a '\' character. 
			For example, this full text search expression:
		</para>
<programlisting><![CDATA[ table\* 'customer invoice\?' ]]></programlisting>
		<para>
			will would rank higher those nodes with properties containing 'table*' (including the asterisk)
			and those containing the phrase "customer invoice?" (including the question mark).
			To use a literal backslash character, simply escape it as well.
		</para>
		<para>
			The grammar for this full-text search language is specified in Section 6.7.19 of the 
			<ulink url="&JSR283;">JCR 2.0 specification</ulink>, but it is also included here as a convenience.
			<note>
				<para>
					The grammar is presented using the same EBNF nomenclature as used in the JCR 2.0 specification.
					Terms are surrounded by '[' and ']' denote optional terms that appear zero or one times. 
					Terms surrounded by '{' and '}' denote terms that appear zero or more times.
					Parentheses are used to identify groups, and are often used to surround possible values. 
				</para>
			</note>
		</para>
		<sect2 id="fulltext-search-expressions">
			<title>Full-text Search Language</title>
<programlisting><![CDATA[

FulltextSearch ::= Disjunct {Space 'OR' Space Disjunct}

Disjunct ::= Term {Space Term}

Term ::= ['-'] SimpleTerm

SimpleTerm ::= Word | '"' Word {Space Word} '"'

Word ::= NonSpaceChar {NonSpaceChar}

Space ::= SpaceChar {SpaceChar}

NonSpaceChar ::= Char - SpaceChar /* Any Char except SpaceChar */

SpaceChar ::= ' '

Char ::= /* Any character */

]]></programlisting>
			<para>
			  As you can see, this is a pretty simple and straightforward query language. But this language makes it extremely
			  easy to find all the nodes in the repository that match a set of terms.
 		 	</para>
		 	<para>
			  When using this query language, the &QueryResult; always contains the "jcr:path" and "jcr:score" columns.
 		 	</para>
		</sect2>
	</sect1>
	  <sect1 id="jcr-qom-query-language">	
	    <title>JCR Query Object Model (JCR-QOM) API</title>
	    <para>
		 		JCR 2.0 introduces a new API for programmatically constructing a query. This API allows the client to construct the lower-level
		    objects for each part of the query, and is a great fit for applications that would otherwise generate fairly complicated
		    query expressions. Using this API is a matter of getting the &QueryObjectModelFactory; from the session's &QueryManager;,
		    and using the factory to create the various components, starting with the lowest-level components.  Then, these lower-level
		    components can be passed to other factory methods to create the higher-level components, and so on, until finally
		    the <code>createQuery(...)</code> method is called to return the &QueryObjectModel;.
		  </para>
			<para>
				Here is a simple example that shows how this is done for the simple query "<code>SELECT * FROM [nt:unstructured] AS unstructNodes</code>":
			</para>
<programlisting language="JAVA" role="JAVA"><![CDATA[
// Obtain the query manager for the session ...
javax.jcr.query.QueryManager queryManager = session.getWorkspace().getQueryManager();

// Create a query object model factory ...
QueryObjectModelFactory factory = queryManager.getQOMFactory();

// Create the FROM clause: a selector for the [nt:unstructured] nodes ...
Selector source = factory.selector("nt:unstructured","unstructNodes");

// Create the SELECT clause (we want all columns defined on the node type) ...
Column[] columns = null;

// Create the WHERE clause (we have none for this query) ...
Constraint constraint = null;

// Define the orderings (we have none for this query)...
Ordering[] orderings = null;

// Create the query ...
QueryObjectModel query = factory.createQuery(source,constraint,orderings,columns);
 
// Execute the query and get the results ...
// (This is the same as before.)
javax.jcr.QueryResult result = query.execute();

]]></programlisting>
     <para>
			From this point on, processing the results is the same as when using the <link linkend="jcr-query-api">JCR Query API</link>:
		</para>
<programlisting language="JAVA" role="JAVA"><![CDATA[

// Iterate over the nodes in the results ...
javax.jcr.NodeIterator nodeIter = result.getNodes();
while ( nodeIter.hasNext() ) {
    javax.jcr.Node node = nodeIter.nextNode();
		...
}

// Or iterate over the rows in the results ...
String[] columnNames = result.getColumnNames();
javax.jcr.query.RowIterator rowIter = result.getRows();
while ( rowIter.hasNext() ) {
    javax.jcr.query.Row row = rowIter.nextRow();
    // Iterate over the column values in each row ...
    javax.jcr.Value[] values = row.getValues();
    for ( javax.jcr.Value value : values ) {
				...
    }
    // Or access the column values by name ...
    for ( String columnName : columnNames ) {
        javax.jcr.Value value = row.getValue(columnName);
				...
    }
}

// When finished, close the session ...
session.logout();
]]></programlisting>
			<para>
				Of course, most queries will create the columns, orderings, and constraints using the &QueryObjectModelFactory;,
				whereas the example above just assumes all of the columns, no orderings, and no constraints.
			</para>
		</sect1>
</chapter>
