001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.ejb.ql;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.util.CharBuffer;
033:
034: /**
035: * A binary expression
036: */
037: class BinaryExpr extends Expr {
038: // binary operation
039: private int _op;
040: // left expression
041: private Expr _left;
042: // right expression
043: private Expr _right;
044:
045: /**
046: * Creates a binary expression.
047: *
048: * @param op the operation
049: * @param left the left expression
050: * @param right the right expression
051: */
052: BinaryExpr(Query query, int op, Expr left, Expr right)
053: throws ConfigException {
054: _query = query;
055: _op = op;
056: _left = left;
057: _right = right;
058:
059: evalTypes();
060: }
061:
062: Expr getLeft() {
063: return _left;
064: }
065:
066: /**
067: * Evaluates the types for the expression
068: */
069: void evalTypes() throws ConfigException {
070: /*
071: if (_left.getComponentCount() != _right.getComponentCount()) {
072: throw error(L.l("'{0}' has mismatched types '{1}' != '{2}'",
073: this, _left.getJavaType().getName(),
074: _right.getJavaType().getName()));
075: }
076: */
077:
078: switch (_op) {
079: case Query.EQ:
080: case Query.NE:
081: if (!_left.getJavaType().equals(_right.getJavaType())
082: && _left.isNumeric() != _right.isNumeric()
083: && !(_left.isDate() && _right.isDate()))
084: throw error(L.l(
085: "'{0}' has mismatched types '{1}' != '{2}'",
086: this , _left.getJavaType().getName(), _right
087: .getJavaType().getName()));
088: setJavaType(boolean.class);
089: break;
090:
091: case Query.LT:
092: case Query.GT:
093: case Query.LE:
094: case Query.GE:
095: if (_left.isDate() && _right.isDate()) {
096: } else if (!_left.isNumeric())
097: throw error(L
098: .l(
099: "'{0}' expects a numeric value at {1}. Less-than and greater-than comparisons only make sense with numbers and dates.",
100: this , _left.getJavaType().getName()));
101: else if (!_right.isNumeric())
102: throw error(L
103: .l(
104: "'{0}' expects a numeric value at {1}. Less-than and greater-than comparisons only make sense with numbers and dates.",
105: this , _right.getJavaType().getName()));
106:
107: setJavaType(boolean.class);
108: break;
109:
110: case Query.AND:
111: case Query.OR:
112: if (!_left.isBoolean())
113: throw error(L.l("'{0}' expects a boolean value at {1}",
114: _left, _left.getJavaType().getName()));
115: if (!_right.isBoolean())
116: throw error(L.l("'{0}' expects a boolean value at {1}",
117: _right, _right.getJavaType().getName()));
118:
119: setJavaType(boolean.class);
120: break;
121:
122: case '+':
123: case '-':
124: case '*':
125: case '/':
126: if (!_left.isNumeric())
127: throw error(L.l("'{0}' expects a numeric value at {1}",
128: _left, _left.getJavaType().getName()));
129: if (!_right.isNumeric())
130: throw error(L.l("'{0}' expects a numeric value at {1}",
131: _right, _right.getJavaType().getName()));
132:
133: /*
134: if (int.class.isAssignableFrom(_left.getJavaType()) &&
135: int.class.isAssignableFrom(_right.getJavaType()))
136: setJavaType(int.class);
137: else if (long.class.isAssignableFrom(_left.getJavaType()) &&
138: long.class.isAssignableFrom(_right.getJavaType()))
139: setJavaType(long.class);
140: else
141: setJavaType(double.class);
142: */
143: if (isInteger(_left.getJavaType())
144: && isInteger(_right.getJavaType()))
145: setJavaType(long.class);
146: else
147: setJavaType(double.class);
148: break;
149:
150: default:
151: throw new RuntimeException("unknown binary op:" + _op + " "
152: + (char) _op);
153: }
154: }
155:
156: /**
157: * Prints the where SQL for this expression
158: *
159: * @param gen the java code generator
160: */
161: void generateWhere(CharBuffer cb) {
162: if (_left.isKey()) {
163: int componentCount = _left.getComponentCount();
164:
165: generateWhereComponents(cb, componentCount);
166:
167: return;
168: } else if (_right.isKey()) {
169: int componentCount = _right.getComponentCount();
170:
171: generateWhereComponents(cb, componentCount);
172:
173: return;
174: }
175:
176: //_left.generateWhereSubExpr(cb);
177: _left.generateComponent(cb, 0);
178:
179: switch (_op) {
180: case Query.EQ:
181: cb.append(" = ");
182: break;
183: case Query.NE:
184: cb.append(" <> ");
185: break;
186: case Query.LT:
187: cb.append(" < ");
188: break;
189: case Query.GT:
190: cb.append(" > ");
191: break;
192: case Query.LE:
193: cb.append(" <= ");
194: break;
195: case Query.GE:
196: cb.append(" >= ");
197: break;
198:
199: case Query.AND:
200: cb.append(" AND ");
201: break;
202: case Query.OR:
203: cb.append(" OR ");
204: break;
205:
206: default:
207: cb.append(" " + ((char) _op) + " ");
208: break;
209: }
210:
211: //_right.generateWhereSubExpr(cb);
212: _right.generateComponent(cb, 0);
213: }
214:
215: private void generateWhereComponents(CharBuffer cb,
216: int componentCount) {
217: for (int i = 0; i < componentCount; i++) {
218: if (i != 0)
219: cb.append(" AND ");
220:
221: _left.generateComponent(cb, i);
222:
223: if (_op == Query.EQ)
224: cb.append(" = ");
225: else if (_op == Query.NE)
226: cb.append(" <> ");
227:
228: _right.generateComponent(cb, i);
229: }
230: }
231:
232: /**
233: * Generates the where SQL for this expression
234: */
235: void generateWhereSubExpr(CharBuffer cb) {
236: cb.append("(");
237: generateWhere(cb);
238: cb.append(")");
239: }
240:
241: void generateSelect(CharBuffer cb) {
242: cb.append("(");
243: generateWhere(cb);
244: cb.append(")");
245: }
246:
247: public String toString() {
248: CharBuffer value = CharBuffer.allocate();
249:
250: if (_left instanceof BinaryExpr) {
251: value.append("(");
252: value.append(_left.toString());
253: value.append(")");
254: } else
255: value.append(_left.toString());
256:
257: switch (_op) {
258: case Query.EQ:
259: value.append(" = ");
260: break;
261: case Query.NE:
262: value.append(" <> ");
263: break;
264: case Query.LT:
265: value.append(" < ");
266: break;
267: case Query.GT:
268: value.append(" > ");
269: break;
270: case Query.LE:
271: value.append(" <= ");
272: break;
273: case Query.GE:
274: value.append(" >= ");
275: break;
276:
277: case Query.AND:
278: value.append(" AND ");
279: break;
280: case Query.OR:
281: value.append(" OR ");
282: break;
283:
284: default:
285: value.append(" " + ((char) _op) + " ");
286: break;
287: }
288:
289: if (_right instanceof BinaryExpr) {
290: value.append("(");
291: value.append(_right.toString());
292: value.append(")");
293: } else
294: value.append(_right.toString());
295:
296: return value.close();
297: }
298: }
|