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 Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.amber.expr;
030:
031: import com.caucho.amber.query.FromItem;
032: import com.caucho.amber.query.QueryParser;
033: import com.caucho.amber.type.EnumType;
034: import com.caucho.amber.type.Type;
035: import com.caucho.util.CharBuffer;
036: import com.caucho.util.L10N;
037:
038: /**
039: * Bound identifier expression.
040: */
041: public class BinaryExpr extends AbstractAmberExpr {
042: private static final L10N L = new L10N(BinaryExpr.class);
043:
044: private AmberExpr _left;
045: private AmberExpr _right;
046: private int _token;
047:
048: /**
049: * Creates a new cmp expression
050: */
051: public BinaryExpr(int token, AmberExpr left, AmberExpr right) {
052: _token = token;
053: _left = left;
054: _right = right;
055: }
056:
057: /**
058: * Returns true if this expr has any relationship.
059: */
060: public boolean hasRelationship() {
061: // jpa/1235
062: return _left.hasRelationship() || _right.hasRelationship();
063: }
064:
065: /**
066: * Returns true for a boolean expr.
067: */
068: public boolean isBoolean() {
069: switch (_token) {
070: case QueryParser.EQ:
071: case QueryParser.NE:
072: case QueryParser.LT:
073: case QueryParser.LE:
074: case QueryParser.GT:
075: case QueryParser.GE:
076: return true;
077: default:
078: return false;
079: }
080: }
081:
082: /**
083: * Returns the java type.
084: */
085: public Class getJavaType() {
086: switch (_token) {
087: case QueryParser.EQ:
088: case QueryParser.NE:
089: case QueryParser.LT:
090: case QueryParser.LE:
091: case QueryParser.GT:
092: case QueryParser.GE:
093: return boolean.class;
094: default:
095: return double.class;
096: }
097: }
098:
099: /**
100: * Binds the expression as a select item.
101: */
102: public AmberExpr bindSelect(QueryParser parser) {
103: _left = _left.bindSelect(parser);
104: _right = _right.bindSelect(parser);
105:
106: bindTypes(_left, _right);
107: bindTypes(_right, _left);
108:
109: return this ;
110: }
111:
112: /**
113: * Returns true if the expression uses the from item.
114: */
115: public boolean usesFrom(FromItem from, int type, boolean isNot) {
116: return (_left.usesFrom(from, type) || _right.usesFrom(from,
117: type));
118: }
119:
120: /**
121: * Returns true if the expression uses the from item.
122: */
123: @Override
124: public boolean exists(FromItem from) {
125: if (_token == QueryParser.EQ) {
126: if (_left instanceof KeyColumnExpr
127: && _left.usesFrom(from, AmberExpr.IS_INNER_JOIN,
128: false) && _right.exists())
129: return true;
130: else if (_right instanceof KeyColumnExpr
131: && _right.usesFrom(from, AmberExpr.IS_INNER_JOIN,
132: false) && _right.exists(from)
133: && _left.exists())
134: return true;
135: else
136: return false;
137: } else
138: return false;
139: }
140:
141: /**
142: * Returns true if the expression uses the from item.
143: */
144: public AmberExpr replaceJoin(JoinExpr join) {
145: _left = _left.replaceJoin(join);
146: _right = _right.replaceJoin(join);
147:
148: return this ;
149: }
150:
151: /**
152: * Generates the where expression.
153: */
154: public void generateWhere(CharBuffer cb) {
155: generateInternalWhere(cb, true);
156: }
157:
158: /**
159: * Generates the (update) where expression.
160: */
161: public void generateUpdateWhere(CharBuffer cb) {
162: generateInternalWhere(cb, false);
163: }
164:
165: /**
166: * Generates the having expression.
167: */
168: public void generateHaving(CharBuffer cb) {
169: generateWhere(cb);
170: }
171:
172: public String toString() {
173: String str = "(" + _left;
174:
175: switch (_token) {
176: case QueryParser.EQ:
177: str += " = ";
178: break;
179: case QueryParser.NE:
180: str += " <> ";
181: break;
182: case QueryParser.LT:
183: str += " < ";
184: break;
185: case QueryParser.LE:
186: str += " <= ";
187: break;
188: case QueryParser.GT:
189: str += " > ";
190: break;
191: case QueryParser.GE:
192: str += " >= ";
193: break;
194: case '+':
195: str += " + ";
196: break;
197: case '-':
198: str += " - ";
199: break;
200: case '*':
201: str += " * ";
202: break;
203: case '/':
204: str += " / ";
205: break;
206: case '%':
207: str += " % ";
208: break;
209: }
210:
211: return str + _right + ")";
212: }
213:
214: //
215: // private
216:
217: private static void bindTypes(AmberExpr left, AmberExpr right) {
218: // jpa/141d
219:
220: Type leftType = left.getType();
221: Type rightType = right.getType();
222:
223: if (left instanceof EnumExpr) {
224: EnumExpr enumExpr = (EnumExpr) left;
225: enumExpr.setOrdinal(rightType.isNumeric());
226: } else if (left instanceof ArgExpr) {
227: if (rightType instanceof EnumType) {
228: ((ArgExpr) left).setType(rightType);
229: }
230: }
231: }
232:
233: private void generateInternalWhere(CharBuffer cb, boolean select) {
234: cb.append('(');
235:
236: if ((QueryParser.EQ <= _token) && (QueryParser.GE >= _token)) {
237: // jpa/10e7
238: _left.setInternalArgType(_right);
239: _right.setInternalArgType(_left);
240: }
241:
242: if (select)
243: _left.generateWhere(cb);
244: else
245: _left.generateUpdateWhere(cb);
246:
247: switch (_token) {
248: case QueryParser.EQ:
249: cb.append(" = ");
250: break;
251: case QueryParser.NE:
252: cb.append(" <> ");
253: break;
254: case QueryParser.LT:
255: cb.append(" < ");
256: break;
257: case QueryParser.LE:
258: cb.append(" <= ");
259: break;
260: case QueryParser.GT:
261: cb.append(" > ");
262: break;
263: case QueryParser.GE:
264: cb.append(" >= ");
265: break;
266: case '+':
267: cb.append(" + ");
268: break;
269: case '-':
270: cb.append(" - ");
271: break;
272: case '*':
273: cb.append(" * ");
274: break;
275: case '/':
276: cb.append(" / ");
277: break;
278: case '%':
279: cb.append(" % ");
280: break;
281: default:
282: throw new IllegalStateException();
283: }
284:
285: if (select)
286: _right.generateWhere(cb);
287: else
288: _right.generateUpdateWhere(cb);
289:
290: cb.append(')');
291: }
292: }
|