001: // $Id: IndexNode.java 7460 2005-07-12 20:27:29Z steveebersole $
002: package org.hibernate.hql.ast.tree;
003:
004: import org.hibernate.QueryException;
005: import org.hibernate.engine.JoinSequence;
006: import org.hibernate.hql.ast.SqlGenerator;
007: import org.hibernate.hql.ast.util.SessionFactoryHelper;
008: import org.hibernate.persister.collection.QueryableCollection;
009: import org.hibernate.type.CollectionType;
010: import org.hibernate.type.Type;
011:
012: import antlr.RecognitionException;
013: import antlr.SemanticException;
014: import antlr.collections.AST;
015:
016: import org.apache.commons.logging.Log;
017: import org.apache.commons.logging.LogFactory;
018:
019: /**
020: * Represents the [] operator and provides it's semantics.
021: *
022: * @author josh Aug 14, 2004 7:07:10 AM
023: */
024: public class IndexNode extends FromReferenceNode {
025:
026: private static final Log log = LogFactory.getLog(IndexNode.class);
027:
028: public void setScalarColumnText(int i) throws SemanticException {
029: throw new UnsupportedOperationException(
030: "An IndexNode cannot generate column text!");
031: }
032:
033: public void prepareForDot(String propertyName)
034: throws SemanticException {
035: FromElement fromElement = getFromElement();
036: if (fromElement == null) {
037: throw new IllegalStateException(
038: "No FROM element for index operator!");
039: }
040: QueryableCollection queryableCollection = fromElement
041: .getQueryableCollection();
042: if (queryableCollection != null
043: && !queryableCollection.isOneToMany()) {
044:
045: FromReferenceNode collectionNode = (FromReferenceNode) getFirstChild();
046: String path = collectionNode.getPath() + "[]."
047: + propertyName;
048: if (log.isDebugEnabled()) {
049: log
050: .debug("Creating join for many-to-many elements for "
051: + path);
052: }
053: FromElementFactory factory = new FromElementFactory(
054: fromElement.getFromClause(), fromElement, path);
055: // This will add the new from element to the origin.
056: FromElement elementJoin = factory
057: .createElementJoin(queryableCollection);
058: setFromElement(elementJoin);
059: }
060: }
061:
062: public void resolveIndex(AST parent) throws SemanticException {
063: throw new UnsupportedOperationException();
064: }
065:
066: public void resolve(boolean generateJoin, boolean implicitJoin,
067: String classAlias, AST parent) throws SemanticException {
068: if (isResolved()) {
069: return;
070: }
071: FromReferenceNode collectionNode = (FromReferenceNode) getFirstChild();
072: SessionFactoryHelper sessionFactoryHelper = getSessionFactoryHelper();
073: collectionNode.resolveIndex(this ); // Fully resolve the map reference, create implicit joins.
074:
075: Type type = collectionNode.getDataType();
076: if (!type.isCollectionType()) {
077: throw new SemanticException(
078: "The [] operator cannot be applied to type "
079: + type.toString());
080: }
081: String collectionRole = ((CollectionType) type).getRole();
082: QueryableCollection queryableCollection = sessionFactoryHelper
083: .requireQueryableCollection(collectionRole);
084: if (!queryableCollection.hasIndex()) {
085: throw new QueryException(
086: "unindexed fromElement before []: "
087: + collectionNode.getPath());
088: }
089:
090: // Generate the inner join -- The elements need to be joined to the collection they are in.
091: FromElement fromElement = collectionNode.getFromElement();
092: String elementTable = fromElement.getTableAlias();
093: FromClause fromClause = fromElement.getFromClause();
094: String path = collectionNode.getPath();
095:
096: FromElement elem = fromClause.findCollectionJoin(path);
097: if (elem == null) {
098: FromElementFactory factory = new FromElementFactory(
099: fromClause, fromElement, path);
100: elem = factory.createCollectionElementsJoin(
101: queryableCollection, elementTable);
102: if (log.isDebugEnabled()) {
103: log
104: .debug("No FROM element found for the elements of collection join path "
105: + path + ", created " + elem);
106: }
107: } else {
108: if (log.isDebugEnabled()) {
109: log
110: .debug("FROM element found for collection join path "
111: + path);
112: }
113: }
114:
115: // Add the condition to the join sequence that qualifies the indexed element.
116: AST index = collectionNode.getNextSibling(); // The index should be a constant, which will have been processed already.
117: if (index == null) {
118: throw new QueryException("No index value!");
119: }
120:
121: setFromElement(fromElement); // The 'from element' that represents the elements of the collection.
122:
123: // Sometimes use the element table alias, sometimes use the... umm... collection table alias (many to many)
124: String collectionTableAlias = elementTable;
125: if (elem.getCollectionTableAlias() != null) {
126: collectionTableAlias = elem.getCollectionTableAlias();
127: }
128:
129: // TODO: get SQL rendering out of here, create an AST for the join expressions.
130: // Use the SQL generator grammar to generate the SQL text for the index expression.
131: JoinSequence joinSequence = fromElement.getJoinSequence();
132: String[] indexCols = queryableCollection.getIndexColumnNames();
133: if (indexCols.length != 1) {
134: throw new QueryException("composite-index appears in []: "
135: + collectionNode.getPath());
136: }
137: SqlGenerator gen = new SqlGenerator(getSessionFactoryHelper()
138: .getFactory());
139: try {
140: gen.simpleExpr(index); //TODO: used to be exprNoParens! was this needed?
141: } catch (RecognitionException e) {
142: throw new QueryException(e.getMessage(), e);
143: }
144: String expression = gen.getSQL();
145: joinSequence.addCondition(collectionTableAlias + '.'
146: + indexCols[0] + " = " + expression);
147:
148: // Now, set the text for this node. It should be the element columns.
149: String[] elementColumns = queryableCollection
150: .getElementColumnNames(elementTable);
151: setText(elementColumns[0]);
152: setResolved();
153: }
154:
155: }
|