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: EjbqlQueryFilterVisitor.java 6140 2005-01-22 01:42:53Z rhs $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.lib;
025:
026: import java.util.ArrayList;
027: import java.util.Map;
028: import java.util.Stack;
029:
030: import javax.ejb.EJBObject;
031:
032: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticExpression;
033: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticFactor;
034: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticLiteral;
035: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticTerm;
036: import org.objectweb.jonas_ejb.deployment.ejbql.ASTBetweenExpression;
037: import org.objectweb.jonas_ejb.deployment.ejbql.ASTBooleanExpression;
038: import org.objectweb.jonas_ejb.deployment.ejbql.ASTBooleanLiteral;
039: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCmpPathExpression;
040: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCollectionMemberExpression;
041: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCollectionValuedPathExpression;
042: import org.objectweb.jonas_ejb.deployment.ejbql.ASTComparisonExpression;
043: import org.objectweb.jonas_ejb.deployment.ejbql.ASTConditionalExpression;
044: import org.objectweb.jonas_ejb.deployment.ejbql.ASTConditionalFactor;
045: import org.objectweb.jonas_ejb.deployment.ejbql.ASTConditionalTerm;
046: import org.objectweb.jonas_ejb.deployment.ejbql.ASTDatetimeExpression;
047: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEJBQL;
048: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEmptyCollectionComparisonExpression;
049: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEntityBeanExpression;
050: import org.objectweb.jonas_ejb.deployment.ejbql.ASTFloatingPointLiteral;
051: import org.objectweb.jonas_ejb.deployment.ejbql.ASTFunctionsReturningNumerics;
052: import org.objectweb.jonas_ejb.deployment.ejbql.ASTFunctionsReturningStrings;
053: import org.objectweb.jonas_ejb.deployment.ejbql.ASTIdentificationVariable;
054: import org.objectweb.jonas_ejb.deployment.ejbql.ASTInExpression;
055: import org.objectweb.jonas_ejb.deployment.ejbql.ASTInputParameter;
056: import org.objectweb.jonas_ejb.deployment.ejbql.ASTIntegerLiteral;
057: import org.objectweb.jonas_ejb.deployment.ejbql.ASTLikeExpression;
058: import org.objectweb.jonas_ejb.deployment.ejbql.ASTLiteral;
059: import org.objectweb.jonas_ejb.deployment.ejbql.ASTNullComparisonExpression;
060: import org.objectweb.jonas_ejb.deployment.ejbql.ASTPath;
061: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSingleValuedCmrPathExpression;
062: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSingleValuedPathExpression;
063: import org.objectweb.jonas_ejb.deployment.ejbql.ASTStringExpression;
064: import org.objectweb.jonas_ejb.deployment.ejbql.ASTStringLiteral;
065: import org.objectweb.jonas_ejb.deployment.ejbql.ASTWhereClause;
066: import org.objectweb.jonas_ejb.deployment.ejbql.EJBQLConstants;
067: import org.objectweb.jonas_ejb.deployment.ejbql.ParseException;
068: import org.objectweb.jonas_ejb.deployment.ejbql.SimpleNode;
069: import org.objectweb.jorm.api.PMapper;
070: import org.objectweb.jorm.lib.JormPathHelper;
071: import org.objectweb.jorm.naming.api.PName;
072: import org.objectweb.jorm.type.api.PType;
073: import org.objectweb.medor.api.Field;
074: import org.objectweb.medor.expression.api.MalformedExpressionException;
075: import org.objectweb.medor.expression.api.Expression;
076: import org.objectweb.medor.filter.api.FieldOperand;
077: import org.objectweb.medor.expression.api.Operand;
078: import org.objectweb.medor.filter.jorm.lib.IsNullPName;
079: import org.objectweb.medor.expression.lib.Abs;
080: import org.objectweb.medor.expression.lib.And;
081: import org.objectweb.medor.filter.lib.BasicFieldOperand;
082: import org.objectweb.medor.expression.lib.BasicOperand;
083: import org.objectweb.medor.expression.lib.BasicParameterOperand;
084: import org.objectweb.medor.filter.lib.CollectionOperand;
085: import org.objectweb.medor.expression.lib.Concat;
086: import org.objectweb.medor.expression.lib.DivideBy;
087: import org.objectweb.medor.expression.lib.Equal;
088: import org.objectweb.medor.expression.lib.FirstLocate;
089: import org.objectweb.medor.expression.lib.Greater;
090: import org.objectweb.medor.expression.lib.GreaterEqual;
091: import org.objectweb.medor.filter.lib.InCollection;
092: import org.objectweb.medor.expression.lib.IndexedLocate;
093: import org.objectweb.medor.filter.lib.IsEmpty;
094: import org.objectweb.medor.filter.lib.IsNull;
095: import org.objectweb.medor.expression.lib.Length;
096: import org.objectweb.medor.expression.lib.Like;
097: import org.objectweb.medor.expression.lib.Lower;
098: import org.objectweb.medor.expression.lib.LowerEqual;
099: import org.objectweb.medor.filter.lib.MemberOf;
100: import org.objectweb.medor.expression.lib.Minus;
101: import org.objectweb.medor.expression.lib.Mod;
102: import org.objectweb.medor.expression.lib.Mult;
103: import org.objectweb.medor.expression.lib.Not;
104: import org.objectweb.medor.expression.lib.NotEqual;
105: import org.objectweb.medor.expression.lib.Or;
106: import org.objectweb.medor.expression.lib.Plus;
107: import org.objectweb.medor.expression.lib.Sqrt;
108: import org.objectweb.medor.expression.lib.Substring;
109: import org.objectweb.medor.expression.lib.UMinus;
110: import org.objectweb.medor.query.api.PropagatedField;
111: import org.objectweb.medor.query.jorm.lib.PNameField;
112: import org.objectweb.medor.query.jorm.lib.QueryBuilder;
113: import org.objectweb.medor.type.lib.PTypeSpaceMedor;
114: import org.objectweb.medor.type.lib.QType;
115:
116: /**
117: * Implementation of a visitor that creates the filter corresponding
118: * to the WHERE clause.
119: * Created on Sep 6, 2002
120: * @author Christophe Ney [cney@batisseurs.com] : Intial developer
121: * @author Helene Joanin: Take into account the following operators
122: * abs(x), sqrt(x),
123: * length(str), substring(s, start, length),
124: * locate(str1, str2), locate(str1, str2, start).
125: * @author Helene Joanin: EJBLocalObject as parameter of a EJB-QL query.
126: * @author Helene Joanin: Take into account the InExpression (IN operator).
127: * @author Helene Joanin: Take into account the IS NULL operator.
128: * @author Helene Joanin: Fix a bug in the visitor for ASTIdentificationVariable:
129: * push a BasicFieldOperand(field) instead of the field itself.
130: * @author Helene Joanin: add '.element' to the path for CollectionValuedPathExpression.
131: * @author Helene Joanin: Convert IsNull(cmr-field) to Equal(cmr-field, PNameNull).
132: * @author Helene Joanin: Take into account the operators: IS EMPTY / IS NOT EMPTY
133: * @author Helene Joanin: Take into account the CONCAT operator
134: * @author Helene Joanin: Take into account the EJBQL version 2.1 syntax.
135: * @author Helene Joanin: Take into account the operator MOD.
136: * @author Helene Joanin: Take into account the operator ISNULL with a parameter.
137: */
138: public class EjbqlQueryFilterVisitor extends EjbqlAbstractVisitor {
139:
140: Expression qf = null;
141: PMapper mapper = null;
142: Map fields = null;
143: Class[] parameterTypes;
144: QueryBuilder qb;
145:
146: static final String OP_IGNORE = "ignore";
147:
148: /**
149: * Constructor
150: * @param _mapper the mapper of each fields.
151: * Needed to build the expression for the IsNull with a reference as an operand.
152: * This parameter may be null in case of the GenIC phase
153: * @param _fields QueryTreeFields for all defined identifiers and all path expression of the query
154: * @param parameterTypes Type of paramaters of the finder/select method
155: * @param ejbql root of the lexical tree of the query
156: */
157: public EjbqlQueryFilterVisitor(PMapper _mapper, Map _fields,
158: Class[] parameterTypes, ASTEJBQL ejbql, QueryBuilder qb)
159: throws Exception {
160: mapper = _mapper;
161: fields = _fields;
162: this .parameterTypes = parameterTypes;
163: this .qb = qb;
164: visit(ejbql);
165: }
166:
167: /**
168: * get the query filter that was built from visiting the syntaxic tree
169: */
170: public Expression getQueryFilter() {
171: return qf;
172: }
173:
174: /**
175: * If query contains WHERE clause, visit child nodes<br>
176: * where_clause ::= WHERE conditional_expression
177: */
178: public Object visit(ASTWhereClause node, Object data) {
179: visit((SimpleNode) node, data);
180: if (OP_IGNORE.equals(((Stack) data).peek())) {
181: qf = null;
182: } else {
183: qf = (Expression) ((Stack) data).pop();
184: }
185: return null;
186: }
187:
188: /**
189: * Push corresponding MedorField to the stack.<br>
190: * single_valued_path_expression ::= path
191: * was in initial BNF
192: * single_valued_path_expression ::= cmp_path_expression | single_valued_cmr_path_expression
193: */
194: public Object visit(ASTSingleValuedPathExpression node, Object data) {
195: visit((SimpleNode) node, data);
196: try {
197: String path = (String) ((ASTPath) ((Stack) data).pop()).value;
198: Field f = (Field) fields.get(path);
199: // FIXME check type for single valued
200: // test GenClassRef or ClassRef
201: ((Stack) data).push(new BasicFieldOperand(f));
202: } catch (Exception e) {
203: throw new VisitorException(e);
204: }
205: return null;
206: }
207:
208: /**
209: * Push corresponding MedorField to the stack.<br>
210: * cmp_path_expression ::= path
211: * was in initial BNF
212: * cmp_path_expression ::= identification_variable. [ single_valued_cmr_field. ] * cmp_field
213: */
214: public Object visit(ASTCmpPathExpression node, Object data) {
215: visit((SimpleNode) node, data);
216: try {
217: String path = (String) ((ASTPath) ((Stack) data).pop()).value;
218: Field f = (Field) fields.get(path);
219: // FIXME check type for cmp field
220: ((Stack) data).push(new BasicFieldOperand(f));
221: } catch (Exception e) {
222: throw new VisitorException(e);
223: }
224: return null;
225: }
226:
227: /**
228: * Push corresponding MedorField to the stack.<br>
229: * single_valued_cmr_path_expression ::= path
230: * was in initial BNF
231: * single_valued_cmr_path_expression ::= identification_variable. [ single_valued_cmr_field. ] * single_valued_cmr_field
232: */
233: public Object visit(ASTSingleValuedCmrPathExpression node,
234: Object data) {
235: visit((SimpleNode) node, data);
236: try {
237: String path = (String) ((ASTPath) ((Stack) data).pop()).value;
238: Field f = (Field) fields.get(path);
239: // FIXME check type for single valued cmr
240: ((Stack) data).push(new BasicFieldOperand(f));
241: } catch (Exception e) {
242: throw new VisitorException(e);
243: }
244: return null;
245: }
246:
247: /**
248: * Push corresponding MedorField to the stack.<br>
249: * collection_valued_path_expression ::= path
250: * was in initial BNF
251: * collection_valued_path_expression ::= identification_variable. [ single_valued_cmr_field. ] *collection_valued_cmr_field
252: */
253: public Object visit(ASTCollectionValuedPathExpression node,
254: Object data) {
255: visit((SimpleNode) node, data);
256: try {
257: // FIXME check type for collection valued cmr
258: String path = (String) ((ASTPath) ((Stack) data).pop()).value;
259: String[] parts = splitPath(path);
260: String first = parts[0];
261: String rest = mergePath(parts, 1, parts.length - 1);
262: QueryBuilder subquery = new QueryBuilder(qb);
263: subquery.define("", qb.navigate(first));
264: Field f = subquery.project(subquery.navigate(rest));
265: ((Stack) data).push(new BasicFieldOperand(f));
266: } catch (Exception e) {
267: throw new VisitorException(e);
268: }
269: return null;
270: }
271:
272: /**
273: * Push corresponding Expression to the stack.<br>
274: * conditional_expression ::= conditional_term [ OR conditional_term ]*
275: */
276: public Object visit(ASTConditionalExpression node, Object data) {
277: visit((SimpleNode) node, data);
278: Object ret = ((Stack) data).pop();
279: for (int i = 1; i < node.jjtGetNumChildren(); i++) {
280: if (OP_IGNORE.equals(ret)) {
281: ret = ((Stack) data).pop();
282: } else if (OP_IGNORE.equals(((Stack) data).peek())) {
283: ((Stack) data).pop();
284: } else {
285: ret = new Or((Expression) ((Stack) data).pop(),
286: (Expression) ret);
287: }
288: }
289: // push result on Stack
290: ((Stack) data).push(ret);
291: return null;
292: }
293:
294: /**
295: * Push corresponding Expression to the stack.<br>
296: * conditional_term ::= conditional_factor [ AND conditional_factor ]*
297: */
298: public Object visit(ASTConditionalTerm node, Object data) {
299: visit((SimpleNode) node, data);
300: Object ret = ((Stack) data).pop();
301: for (int i = 1; i < node.jjtGetNumChildren(); i++) {
302: if (OP_IGNORE.equals(ret)) {
303: ret = ((Stack) data).pop();
304: } else if (OP_IGNORE.equals(((Stack) data).peek())) {
305: ((Stack) data).pop();
306: } else {
307: ret = new And((Expression) ((Stack) data).pop(),
308: (Expression) ret);
309: }
310: }
311: // push result on Stack
312: ((Stack) data).push(ret);
313: return null;
314: }
315:
316: /**
317: * Push corresponding Expression to the stack.<br>
318: * conditional_factor ::= [ NOT ] conditional_test
319: */
320: public Object visit(ASTConditionalFactor node, Object data) {
321: visit((SimpleNode) node, data);
322: if (node.not) {
323: if (!OP_IGNORE.equals(((Stack) data).peek())) {
324: Expression ret = (Expression) ((Stack) data).pop();
325: // push result on Stack
326: ((Stack) data).push(new Not(ret));
327: }
328: }
329: return null;
330: }
331:
332: /**
333: * Push corresponding Expression to the stack.<br>
334: * between_expression ::= arithmetic_expression [ NOT ] BETWEEN arithmetic_expression AND arithmetic_expression
335: */
336: public Object visit(ASTBetweenExpression node, Object data) {
337: visit((SimpleNode) node, data);
338: Expression[] terms = new Expression[3];
339: terms[2] = (Expression) ((Stack) data).pop();
340: terms[1] = (Expression) ((Stack) data).pop();
341: terms[0] = (Expression) ((Stack) data).pop();
342: if (node.not) {
343: ((Stack) data).push(new Or(new Lower(terms[0], terms[1]),
344: new Greater(terms[0], terms[2])));
345: } else {
346: ((Stack) data).push(new And(new GreaterEqual(terms[0],
347: terms[1]), new LowerEqual(terms[0], terms[2])));
348: }
349: return null;
350: }
351:
352: /**
353: * Push corresponding Expression to the stack.<br>
354: * in_expression ::= cmp_path_expression [ NOT ] IN
355: * {literal|input_parameter} [ , {literal|input_parameter} ] * )
356: */
357: public Object visit(ASTInExpression node, Object data) {
358: visit((SimpleNode) node, data);
359: Stack s = (Stack) data;
360: ArrayList c = new ArrayList();
361: for (int i = 1; i <= node.eltnum; i++) {
362: c.add(s.pop());
363: }
364: CollectionOperand co = new CollectionOperand(c);
365: FieldOperand f = (FieldOperand) s.pop();
366: if (node.not) {
367: s.push(new Not(new InCollection(f, co, f.getField()
368: .getType())));
369: } else {
370: s.push(new InCollection(f, co, f.getField().getType()));
371: }
372: return null;
373: }
374:
375: /**
376: * Push corresponding Expression to the stack.<br>
377: * like_expression ::= cmp_path_expression [ NOT ] LIKE pattern_value
378: * [ ESCAPE escape_character ]
379: */
380: public Object visit(ASTLikeExpression node, Object data) {
381: visit((SimpleNode) node, data);
382: Stack s = (Stack) data;
383: Expression e1 = (Expression) s.pop();
384: Expression e2 = (Expression) s.pop();
385: Expression e3 = null;
386: if (node.third) {
387: //The like operator contains a ESCAPE section.
388: e3 = (Expression) s.pop();
389: }
390: if (e3 == null) {
391: s.push(new Like(e2, e1, node.not));
392: } else {
393: s.push(new Like(e3, e2, e1, node.not));
394: }
395: return null;
396: }
397:
398: /**
399: * Push corresponding Expression to the stack.<br>
400: * null_comparison_expression ::= {single_valued_path_expression|input_parameter} IS [ NOT ] NULL
401: */
402: public Object visit(ASTNullComparisonExpression node, Object data) {
403: visit((SimpleNode) node, data);
404: Stack s = (Stack) data;
405: Expression e1 = (Expression) s.pop();
406: if ((e1 instanceof BasicParameterOperand)
407: && (e1.getType().getTypeCode() == QType.TYPECODE_PNAME)) {
408: // The operand is a bean parameter: use IsNullPName
409: if (node.not) {
410: s.push(new Not(new IsNullPName(
411: ((BasicParameterOperand) e1).getName())));
412: } else {
413: s.push(new IsNullPName(((BasicParameterOperand) e1)
414: .getName()));
415: }
416: } else if (e1.getType().getTypeCode() == PType.TYPECODE_REFERENCE) {
417: // The operand is a cmr field: use the Equal operator with PNameNull as second operand
418: // Warning: The PNameNull value may not be build because the mapper may be null
419: // in case of this expression building is done in the GenIC phase
420: Field f = ((FieldOperand) e1).getField();
421: PNameField pnf = null;
422: if (f instanceof PNameField) {
423: pnf = (PNameField) f;
424: } else if (f instanceof PropagatedField) {
425: pnf = (PNameField) ((PropagatedField) f)
426: .getOriginFields()[0];
427: } else {
428: // error: unmanaged case
429: throw new Error("Operand of IS NULL not valid !?");
430: }
431: Operand op2;
432: if (mapper == null) {
433: // dummy operand2 to be able to build a query even in the GenIC phase
434: op2 = new BasicOperand("pnamenull");
435: } else {
436: // real operand2 PNameNull
437: PName pnamenull = JormPathHelper.getPNameCoder(
438: pnf.getPNamingContextParameter(), mapper)
439: .getNull();
440: op2 = new BasicOperand(pnamenull, PTypeSpaceMedor.PNAME);
441: }
442: if (node.not) {
443: s.push(new Not(new Equal(e1, op2)));
444: } else {
445: s.push(new Equal(e1, op2));
446: }
447: } else {
448: // The operand is a cmp field, or a ...: use the IsNull operator
449: if (node.not) {
450: s.push(new Not(new IsNull(e1)));
451: } else {
452: s.push(new IsNull(e1));
453: }
454: }
455: return null;
456:
457: }
458:
459: /**
460: * Nothing to do:
461: * Already taken into account in EjbqlVariableVisitor at the variables parsing,
462: * so, just push the OP_IGNORE in the stack
463: * empty_collection_comparison_expression ::= collection_valued_path_expression IS [ NOT ] EMPTY
464: */
465: public Object visit(ASTEmptyCollectionComparisonExpression node,
466: Object data) {
467: visit((SimpleNode) node, data);
468: Stack s = (Stack) data;
469: Expression e = (Expression) s.pop();
470: Expression res = new IsEmpty(e);
471: if (node.not) {
472: res = new Not(res);
473: }
474: s.push(res);
475: return null;
476: }
477:
478: /**
479: * Push corresponding Expression to the stack.<br>
480: * collection_member_expression ::= {single_valued_cmr_path_expression | identification_variable | input_parameter}
481: * [ NOT ] MEMBER [ OF ] collection_valued_path_expression
482: */
483: public Object visit(ASTCollectionMemberExpression node, Object data) {
484: visit((SimpleNode) node, data);
485: Stack s = (Stack) data;
486: Expression e2 = (Expression) s.pop();
487: Expression e1 = (Expression) s.pop();
488: ArrayList le2 = new ArrayList();
489: le2.add(e2);
490: ArrayList le1 = new ArrayList();
491: le1.add(e1);
492: Expression res = null;
493: try {
494: res = new MemberOf(le1, le2);
495: } catch (MalformedExpressionException e) {
496: throw new Error(
497: "Operand expression of MEMBER OF malformed: " + e
498: + e.getNestedException());
499: }
500: if (node.not) {
501: s.push(new Not(res));
502: } else {
503: s.push(res);
504: }
505: return null;
506: }
507:
508: /**
509: * Push corresponding Expression to the stack.<br>
510: * comparison_expression ::= string_value { = | > | >= | < | <= | <> } string_expression
511: * | boolean_value { = | <>} boolean_expression
512: * | datetime_value { = | > | >= | < | <= | <> } datetime_expression
513: * | entity_bean_value { = | <> } entity_bean_expression
514: * | arithmetic_value { = | > | >= | < | <= | <> } single_value_designator
515: */
516: public Object visit(ASTComparisonExpression node, Object data) {
517: visit((SimpleNode) node, data);
518: Expression[] terms = new Expression[2];
519: terms[1] = (Expression) ((Stack) data).pop();
520: terms[0] = (Expression) ((Stack) data).pop();
521: int op = ((Integer) node.ops.get(0)).intValue();
522: switch (op) {
523: case EJBQLConstants.EQ:
524: ((Stack) data).push(new Equal(terms[0], terms[1]));
525: break;
526: case EJBQLConstants.NE:
527: ((Stack) data).push(new NotEqual(terms[0], terms[1]));
528: break;
529: case EJBQLConstants.GT:
530: ((Stack) data).push(new Greater(terms[0], terms[1]));
531: break;
532: case EJBQLConstants.GE:
533: ((Stack) data).push(new GreaterEqual(terms[0], terms[1]));
534: break;
535: case EJBQLConstants.LT:
536: ((Stack) data).push(new Lower(terms[0], terms[1]));
537: break;
538: case EJBQLConstants.LE:
539: ((Stack) data).push(new LowerEqual(terms[0], terms[1]));
540: break;
541: }
542: return null;
543: }
544:
545: /**
546: * Push corresponding Expression to the stack.<br>
547: * arithmetic_expression ::= arithmetic_term [ { + | - } arithmetic_term ] *
548: */
549: public Object visit(ASTArithmeticExpression node, Object data) {
550: visit((SimpleNode) node, data);
551: Expression ret = (Expression) ((Stack) data).pop();
552: for (int i = 0; i < node.jjtGetNumChildren() - 1; i++) {
553: switch (((Integer) node.ops.get(node.jjtGetNumChildren()
554: - 2 - i)).intValue()) {
555: case EJBQLConstants.PLUS:
556: ret = new Plus((Expression) ((Stack) data).pop(), ret);
557: break;
558: case EJBQLConstants.MINUS:
559: ret = new Minus((Expression) ((Stack) data).pop(), ret);
560: break;
561: }
562: }
563: // push result to the Stack
564: ((Stack) data).push(ret);
565: return null;
566: }
567:
568: /**
569: * Push corresponding Expression to the stack.<br>
570: * arithmetic_term ::= arithmetic_factor [ { * | / } arithmetic_factor ]*
571: */
572: public Object visit(ASTArithmeticTerm node, Object data) {
573: visit((SimpleNode) node, data);
574: Expression ret = (Expression) ((Stack) data).pop();
575: for (int i = 0; i < node.jjtGetNumChildren() - 1; i++) {
576: switch (((Integer) node.ops.get(node.jjtGetNumChildren()
577: - 2 - i)).intValue()) {
578: case EJBQLConstants.MULT:
579: ret = new Mult((Expression) ((Stack) data).pop(), ret);
580: break;
581: case EJBQLConstants.DIV:
582: ret = new DivideBy((Expression) ((Stack) data).pop(),
583: ret);
584: break;
585: }
586: }
587: // push result to the Stack
588: ((Stack) data).push(ret);
589: return null;
590: }
591:
592: /**
593: * Push corresponding Expression to the stack.<br>
594: * arithmetic_factor ::= [ + |- ] arithmetic_primary
595: */
596: public Object visit(ASTArithmeticFactor node, Object data) {
597: visit((SimpleNode) node, data);
598: Expression ret = (Expression) ((Stack) data).pop();
599: if (node.ops.size() > 0) {
600: if (((Integer) node.ops.get(0)).intValue() == EJBQLConstants.MINUS) {
601: ret = new UMinus((Expression) ret);
602: }
603: }
604: // push result on Stack
605: ((Stack) data).push(ret);
606: return null;
607: }
608:
609: /**
610: * Visit child nodes
611: * string_expression ::= string_primary | input_parameter
612: */
613: public Object visit(ASTStringExpression node, Object data) {
614: visit((SimpleNode) node, data);
615: // FIXME check or convert type?
616: return null;
617: }
618:
619: /**
620: * Visit child nodes
621: * datetime_expression ::= datetime_value | input_parameter
622: */
623: public Object visit(ASTDatetimeExpression node, Object data) {
624: visit((SimpleNode) node, data);
625: // FIXME check or convert type?
626: return null;
627: }
628:
629: /**
630: * Visit child nodes
631: * boolean_expression ::= cmp_path_expression | boolean_literal | input_parameter
632: */
633: public Object visit(ASTBooleanExpression node, Object data) {
634: visit((SimpleNode) node, data);
635: // FIXME check or convert type?
636: return null;
637: }
638:
639: /**
640: * Visit child nodes
641: * entity_bean_expression ::= entity_bean_value | input_parameter
642: */
643: public Object visit(ASTEntityBeanExpression node, Object data) {
644: visit((SimpleNode) node, data);
645: // FIXME check or convert type?
646: return null;
647: }
648:
649: /**
650: * visit child nodes
651: * Push corresponding Expression to the stack.<br>
652: * functions_returning_strings ::= CONCAT (string_expression, string_expression)
653: * | SUBSTRING (string_expression,arithmetic_expression,arithmetic_expression)
654: */
655: public Object visit(ASTFunctionsReturningStrings node, Object data) {
656: visit((SimpleNode) node, data);
657: Stack s = (Stack) data;
658: int op = ((Integer) node.ops.get(0)).intValue();
659: Expression ret = null;
660: Expression e1, e2;
661: switch (op) {
662: case EJBQLConstants.CONCAT:
663: // e1, e2 are in reverse order in the stack
664: e2 = (Expression) s.pop();
665: e1 = (Expression) s.pop();
666: ret = new Concat(e1, e2);
667: break;
668: case EJBQLConstants.SUBSTRING:
669: // e1, e2, e3 are in reverse order in the stack
670: Expression e3 = (Expression) s.pop();
671: e2 = (Expression) s.pop();
672: e1 = (Expression) s.pop();
673: ret = new Substring(e1, e2, e3);
674: break;
675: }
676: // push result to the Stack
677: s.push(ret);
678: return null;
679: }
680:
681: /**
682: * visit child nodes
683: * Push corresponding Expression to the stack.<br>
684: * functions_returning_numerics ::= LENGTH (string_expression)
685: * | LOCATE (string_expression, string_expression
686: * [ , arithmetic_expression ] )
687: * | ABS (arithmetic_expression)
688: * | SQRT (arithmetic_expression)
689: * | MOD (arithmetic_expression , arithmetic_expression)
690: */
691: public Object visit(ASTFunctionsReturningNumerics node, Object data) {
692: visit((SimpleNode) node, data);
693: Stack s = (Stack) data;
694: int op = ((Integer) node.ops.get(0)).intValue();
695: Expression e1, e2;
696: Expression ret = null;
697: switch (op) {
698: case EJBQLConstants.LENGTH:
699: e1 = (Expression) s.pop();
700: ret = new Length(e1);
701: break;
702: case EJBQLConstants.LOCATE:
703: // Operands are in the reverse order in the stack
704: Expression e3 = null;
705: if (node.third) {
706: // The locate operator contains a third operand.
707: e3 = (Expression) s.pop();
708: }
709: e2 = (Expression) s.pop();
710: e1 = (Expression) s.pop();
711: // Warning on the args order for IndexedLocate and FirstLocate.
712: if (node.third) {
713: ret = new IndexedLocate(e2, e1, e3);
714: } else {
715: ret = new FirstLocate(e1, e2);
716: }
717: break;
718: case EJBQLConstants.ABS:
719: e1 = (Expression) s.pop();
720: ret = new Abs(e1);
721: break;
722: case EJBQLConstants.SQRT:
723: e1 = (Expression) s.pop();
724: ret = new Sqrt(e1);
725: break;
726: case EJBQLConstants.MOD:
727: e2 = (Expression) s.pop();
728: e1 = (Expression) s.pop();
729: ret = new Mod(e1, e2);
730: break;
731: }
732: // push result to the Stack
733: s.push(ret);
734: return null;
735: }
736:
737: /**
738: * Node with value set to identification variable string.
739: * Push the Node to the stack
740: */
741: public Object visit(ASTIdentificationVariable node, Object data) {
742: String fieldname = (String) node.value + "." + Field.PNAMENAME;
743: Field f = (Field) fields.get(fieldname);
744: ((Stack) data).push(new BasicFieldOperand(f));
745: return null;
746: }
747:
748: /**
749: * Visit child nodes
750: * literal ::= string_literal | arithmetic_literal | boolean_literal
751: */
752: public Object visit(ASTLiteral node, Object data) {
753: visit((SimpleNode) node, data);
754: return null;
755: }
756:
757: /**
758: * Node with value set to litteral string.
759: * Push the corresponding Operand to the stack
760: */
761: public Object visit(ASTStringLiteral node, Object data) {
762: ((Stack) data).push(new BasicOperand((String) node.value));
763: return null;
764: }
765:
766: /**
767: * Visit child nodes
768: * arithmetic_literal ::= integer_literal | floatingpoint_literal
769: */
770: public Object visit(ASTArithmeticLiteral node, Object data) {
771: visit((SimpleNode) node, data);
772: return null;
773: }
774:
775: /**
776: * Node with value set to integer litteral arithmetic.
777: * Push the corresponding Operand to the stack
778: */
779: public Object visit(ASTIntegerLiteral node, Object data) {
780: ((Stack) data).push(new BasicOperand(((Long) node.value)
781: .longValue()));
782: return null;
783: }
784:
785: /**
786: * Node with value set to integer litteral arithmetic.
787: * Push the corresponding Operand to the stack
788: */
789: public Object visit(ASTFloatingPointLiteral node, Object data) {
790: ((Stack) data).push(new BasicOperand(((Double) node.value)
791: .doubleValue()));
792: return null;
793: }
794:
795: /**
796: * Node with value set to litteral boolean.
797: * Push the corresponding Operand to the stack
798: */
799: public Object visit(ASTBooleanLiteral node, Object data) {
800: ((Stack) data).push(new BasicOperand(((Boolean) node.value)
801: .booleanValue()));
802: return null;
803: }
804:
805: /**
806: * Node with value set to parameter index (1..n) string.
807: * Push the corresponding Operand to the stack
808: */
809: public Object visit(ASTInputParameter node, Object data) {
810: try {
811: int pIndex = ((Integer) node.value).intValue() - 1;
812: if (pIndex >= parameterTypes.length) {
813: throw new ParseException("Parameter ?" + (pIndex + 1)
814: + " is out of range (max = "
815: + parameterTypes.length + ")");
816: }
817: if (EJBObject.class
818: .isAssignableFrom(parameterTypes[pIndex])) {
819: // TODO: Take into account EJBObject as parameter
820: // (Only EJBLocalObject are already taken into account)
821: throw new Error("EJBObject params not implemented");
822: }
823: Operand op = new BasicParameterOperand(JormType.getPType(
824: parameterTypes[pIndex], false), "?" + node.value);
825: ((Stack) data).push(op);
826: return null;
827: } catch (ParseException e) {
828: throw new VisitorException(e);
829: }
830: }
831:
832: /**
833: * Push the Node to the stack
834: */
835: public Object visit(ASTPath node, Object data) {
836: ((Stack) data).push(node);
837: return null;
838: }
839: }
|