001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: EjbqlSelectVisitor.java 5665 2004-10-22 11:50:06Z joaninh $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.lib;
025:
026: import java.util.Map;
027: import java.util.Stack;
028:
029: import org.objectweb.jonas_ejb.deployment.ejbql.ASTAggregateSelectExpression;
030: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCmpPathExpression;
031: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEJBQL;
032: import org.objectweb.jonas_ejb.deployment.ejbql.ASTIdentificationVariable;
033: import org.objectweb.jonas_ejb.deployment.ejbql.ASTPath;
034: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSelectClause;
035: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSelectExpression;
036: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSingleValuedCmrPathExpression;
037: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSingleValuedPathExpression;
038: import org.objectweb.jonas_ejb.deployment.ejbql.EJBQLConstants;
039: import org.objectweb.jonas_ejb.deployment.ejbql.SimpleNode;
040: import org.objectweb.jorm.type.api.PType;
041: import org.objectweb.jorm.type.api.PTypeSpace;
042: import org.objectweb.medor.api.Field;
043: import org.objectweb.medor.filter.api.AggregateOperator;
044: import org.objectweb.medor.filter.lib.Avg;
045: import org.objectweb.medor.filter.lib.BasicFieldOperand;
046: import org.objectweb.medor.filter.lib.Count;
047: import org.objectweb.medor.filter.lib.Max;
048: import org.objectweb.medor.filter.lib.Min;
049: import org.objectweb.medor.filter.lib.Sum;
050: import org.objectweb.medor.query.api.QueryTree;
051: import org.objectweb.medor.query.api.QueryTreeField;
052: import org.objectweb.medor.query.lib.Nest;
053: import org.objectweb.medor.query.lib.SelectProject;
054:
055: /**
056: * Implementation of a visitor that creates the selection projection for
057: * corresponding to a given WHERE clause. Created on Sep 6, 2002
058: * @author Christophe Ney [cney@batisseurs.com]: Initial developer
059: * @author Helene Joanin: Take into account the EJBQL version 2.1 syntax.
060: * @author Helene Joanin: Take into account the aggregate select expression.
061: */
062: public class EjbqlSelectVisitor extends EjbqlAbstractVisitor {
063:
064: Map fields;
065: AggregateOperator aggregateOp = null;
066: QueryTree qt;
067:
068: /**
069: * Constructor
070: * @param ejbql root of the lexical tree of the query
071: * @param _fields Map with (identifier,JormExtent) pairs
072: */
073: public EjbqlSelectVisitor(ASTEJBQL ejbql, Map _fields,
074: SelectProject sp) throws Exception {
075: this .qt = sp;
076: fields = _fields;
077: visit(ejbql);
078: }
079:
080: /**
081: * get the query tree that was built from visiting the lexical tree. This is
082: * a nest if there is an aggregate function or a select projet otherwise.
083: */
084: public QueryTree getQueryTree() {
085: return qt;
086: }
087:
088: /**
089: * Visit child node. SELECT [ DISTINCT ] {select_expression | OBJECT
090: * (identification_variable)}
091: */
092: public Object visit(ASTSelectClause node, Object data) {
093: visit((SimpleNode) node, data);
094: try {
095: boolean distinct = node.distinct;
096: qt.setDistinct(distinct);
097: SelectProject sp = (SelectProject) qt;
098: QueryTreeField qtf = (QueryTreeField) fields
099: .get((String) ((Stack) data).pop());
100: QueryTreeField qtf2 = sp.addPropagatedField(qtf.getName(),
101: qtf.getType(), new QueryTreeField[] { qtf });
102: //TraceEjb.query.log(BasicLevel.DEBUG, "The SelectProjectQueryTree: ");
103: //QueryTreePrinter.printQueryTree(sp, TraceEjb.query, BasicLevel.DEBUG);
104: if (aggregateOp != null) {
105: Nest n = new Nest(new QueryTreeField[] { qtf2 },
106: "grouped_fields", new QueryTreeField[0],
107: "aggregate_node");
108: PType type = null;
109: if (aggregateOp instanceof Sum) {
110: if (qtf.getType().equals(PTypeSpace.FLOAT)
111: || qtf.getType().equals(PTypeSpace.DOUBLE)) {
112: type = PTypeSpace.DOUBLE;
113: } else if (qtf.getType().equals(
114: PTypeSpace.BIGINTEGER)) {
115: type = PTypeSpace.BIGINTEGER;
116: } else if (qtf.getType().equals(
117: PTypeSpace.BIGDECIMAL)) {
118: type = PTypeSpace.BIGDECIMAL;
119: } else {
120: type = PTypeSpace.LONG;
121: }
122: } else if ((aggregateOp instanceof Max)
123: || (aggregateOp instanceof Min)) {
124: type = qtf.getType();
125: } else if (aggregateOp instanceof Avg) {
126: type = PTypeSpace.DOUBLE;
127: } else if (aggregateOp instanceof Count) {
128: type = PTypeSpace.LONG;
129: }
130: //replace the field in the aggregateOp by the propagated field
131: aggregateOp.setExpression(0,
132: new BasicFieldOperand(qtf2));
133: n.addCalculatedField("calculed_field", type,
134: aggregateOp);
135: qt = n;
136: }
137: } catch (Exception e) {
138: throw new VisitorException(e);
139: }
140: return null;
141: }
142:
143: /**
144: * Visit child node
145: */
146: public Object visit(ASTSelectExpression node, Object data) {
147: return visit((SimpleNode) node, data);
148: }
149:
150: /**
151: * Visit child node
152: */
153: public Object visit(ASTAggregateSelectExpression node, Object data) {
154: visit((SimpleNode) node, data);
155: Stack s = (Stack) data;
156: int operator = ((Integer) node.ops.get(0)).intValue();
157: boolean distinct = node.distinct;
158: Field field = (Field) fields.get((String) s.peek());
159: BasicFieldOperand fieldOp = new BasicFieldOperand(field);
160: switch (operator) {
161: case EJBQLConstants.AVG:
162: aggregateOp = new Avg(fieldOp, distinct);
163: break;
164: case EJBQLConstants.COUNT:
165: aggregateOp = new Count(fieldOp, distinct);
166: break;
167: case EJBQLConstants.MAX:
168: aggregateOp = new Max(fieldOp, distinct);
169: break;
170: case EJBQLConstants.MIN:
171: aggregateOp = new Min(fieldOp, distinct);
172: break;
173: case EJBQLConstants.SUM:
174: aggregateOp = new Sum(fieldOp, distinct);
175: break;
176: default:
177: throw new Error("AggregateOperator '" + operator
178: + "' unknown");
179: }
180: return null;
181: }
182:
183: /**
184: * Visit child node
185: */
186: public Object visit(ASTCmpPathExpression node, Object data) {
187: return visit((SimpleNode) node, data);
188: }
189:
190: /**
191: * Visit child node
192: */
193: public Object visit(ASTSingleValuedCmrPathExpression node,
194: Object data) {
195: return visit((SimpleNode) node, data);
196: }
197:
198: /**
199: * Visit child node
200: */
201: public Object visit(ASTSingleValuedPathExpression node, Object data) {
202: return visit((SimpleNode) node, data);
203: }
204:
205: /**
206: * Push the Node to the stack
207: */
208: public Object visit(ASTIdentificationVariable node, Object data) {
209: ((Stack) data)
210: .push((String) node.value + "." + Field.PNAMENAME);
211: return null;
212: }
213:
214: /**
215: * Push the Node to the stack
216: */
217: public Object visit(ASTPath node, Object data) {
218: ((Stack) data).push(node.value);
219: return null;
220: }
221: }
|