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.ejb.cfg.FunctionSignature;
033: import com.caucho.util.CharBuffer;
034:
035: import java.util.ArrayList;
036:
037: /**
038: * A builtin SQL function expression
039: */
040: public class FunExpr extends Expr {
041: static ArrayList<FunctionSignature> _standardFunctions;
042:
043: // function name
044: private String _name;
045: // arguments
046: private ArrayList<Expr> _args;
047:
048: private ArrayList<FunctionSignature> _functions;
049:
050: private FunctionSignature _sig;
051:
052: /**
053: * Creates a function expression.
054: *
055: * @param name the function name
056: * @param args the function arguments
057: */
058: FunExpr(String name, ArrayList<Expr> args,
059: ArrayList<FunctionSignature> functions)
060: throws ConfigException {
061: _name = name;
062: _args = args;
063: _functions = functions;
064:
065: evalTypes();
066: }
067:
068: /**
069: * Evaluates the types for the expression
070: */
071: void evalTypes() throws ConfigException {
072: Class[] argTypes = getArgTypes();
073:
074: _sig = null;
075:
076: for (int i = 0; i < _functions.size(); i++) {
077: FunctionSignature sig = _functions.get(i);
078:
079: if (!_name.equalsIgnoreCase(sig.getName()))
080: continue;
081:
082: _sig = sig;
083:
084: Class[] funArgs = sig.getParameterTypes();
085:
086: if (funArgs.length != argTypes.length)
087: continue;
088:
089: boolean isMatch = true;
090: for (int j = 0; isMatch && j < funArgs.length; j++) {
091: if (argTypes[j].equals(funArgs[j]))
092: continue;
093: else if (Object.class.equals(funArgs[j]))
094: continue;
095: else if ((double.class.equals(funArgs[j]) || int.class
096: .equals(funArgs[j]))
097: && (double.class.equals(argTypes[j]) || int.class
098: .equals(argTypes[j])))
099: continue;
100: else
101: isMatch = false;
102: }
103:
104: if (!isMatch)
105: continue;
106:
107: _sig = sig;
108: setJavaType(sig.getReturnType());
109: return;
110: }
111:
112: if (_sig != null)
113: throw error(L.l("`{0}' signature does not match `{1}'",
114: _name, _sig.getSignature()));
115: else
116: throw error(L.l("unknown function `{0}'", _name));
117: }
118:
119: /**
120: * Calculate the argument types.
121: */
122: private Class[] getArgTypes() {
123: ArrayList<Class> argTypes = new ArrayList<Class>();
124:
125: for (int i = 0; i < _args.size(); i++) {
126: Expr expr = _args.get(i);
127:
128: if (expr.isBoolean())
129: argTypes.add(boolean.class);
130: else if (expr.isInteger())
131: argTypes.add(int.class);
132: else if (expr.isNumeric())
133: argTypes.add(double.class);
134: else if (expr.isDate())
135: argTypes.add(java.util.Date.class);
136: else if (expr.isString())
137: argTypes.add(String.class);
138: else
139: argTypes.add(Object.class);
140: }
141:
142: return argTypes.toArray(new Class[argTypes.size()]);
143: }
144:
145: /**
146: * Prints the where SQL for this expression
147: *
148: * @param gen the java code generator
149: */
150: void generateWhere(CharBuffer cb) {
151: if (_sig != null && _sig.getSQL() != null)
152: generateWhereSQL(cb, _sig.getSQL());
153: else {
154: cb.append(_name);
155:
156: cb.append("(");
157: for (int i = 0; i < _args.size(); i++) {
158: if (i != 0)
159: cb.append(", ");
160:
161: Expr expr = _args.get(i);
162:
163: expr.generateWhere(cb);
164: }
165:
166: cb.append(")");
167: }
168: }
169:
170: /**
171: * Prints the where SQL for this expression
172: *
173: * @param gen the java code generator
174: */
175: void generateWhereSQL(CharBuffer cb, String sql) {
176: for (int i = 0; i < sql.length(); i++) {
177: char ch = sql.charAt(i);
178: char ch1;
179:
180: if (ch == '?' && i + 1 < sql.length()
181: && (ch1 = sql.charAt(i + 1)) >= '1' && ch1 <= '9') {
182: int index = ch1 - '0';
183: i++;
184:
185: if (index <= 0 || _args.size() < index)
186: throw new IllegalStateException(L.l(
187: "illegal argument for sql `{0}'", sql));
188:
189: _args.get(index - 1).generateWhere(cb);
190: } else
191: cb.append(ch);
192: }
193: }
194:
195: /**
196: * Prints the select SQL for this expression
197: *
198: * @param gen the java code generator
199: */
200: void generateSelect(CharBuffer cb) {
201: generateWhere(cb);
202: }
203:
204: /**
205: * Returns a printable version of the function.
206: */
207: public String toString() {
208: CharBuffer cb = new CharBuffer();
209: cb.append(_name);
210:
211: cb.append("(");
212: for (int i = 0; i < _args.size(); i++) {
213: if (i != 0)
214: cb.append(", ");
215:
216: cb.append(_args.get(i));
217: }
218:
219: cb.append(")");
220:
221: return cb.toString();
222: }
223:
224: public static ArrayList<FunctionSignature> getStandardFunctions() {
225: return (ArrayList) _standardFunctions.clone();
226: }
227:
228: static void addFunction(String signature) {
229: try {
230: FunctionSignature sig = new FunctionSignature(signature);
231:
232: _standardFunctions.add(sig);
233: } catch (Exception e) {
234: e.printStackTrace();
235: }
236: }
237:
238: static {
239: _standardFunctions = new ArrayList<FunctionSignature>();
240:
241: addFunction("int abs(int)");
242: addFunction("double abs(double)");
243:
244: addFunction("double acos(double)");
245: addFunction("double sin(double)");
246: addFunction("double atan(double)");
247: addFunction("double cos(double)");
248: addFunction("double cot(double)");
249: addFunction("double degrees(double)");
250: addFunction("double exp(double)");
251: addFunction("double log(double)");
252: addFunction("double log10(double)");
253: addFunction("double radians(double)");
254: addFunction("double sin(double)");
255: addFunction("double sqrt(double)");
256: addFunction("double tan(double)");
257: addFunction("double pi()");
258:
259: addFunction("int ceiling(double)");
260: addFunction("int floor(double)");
261: addFunction("int sign(double)");
262:
263: addFunction("double atan2(double, double)");
264: addFunction("double power(double, double)");
265: addFunction("double round(double, double)");
266: addFunction("double truncate(double, double)");
267:
268: addFunction("int mod()");
269: addFunction("int rand()");
270:
271: addFunction("int count(any)");
272: addFunction("double sum(any)");
273:
274: addFunction("int min(int)");
275: addFunction("int max(int)");
276:
277: addFunction("double min(double)");
278: addFunction("double max(double)");
279:
280: addFunction("int ascii(String)");
281: addFunction("int length(String)");
282:
283: addFunction("String char(int)");
284: addFunction("String space(int)");
285:
286: addFunction("String concat(String, String)");
287:
288: addFunction("int difference(String, String)");
289:
290: addFunction("String insert(String, int, int, String)");
291:
292: addFunction("String lcase(String)");
293: addFunction("String ltrim(String)");
294: addFunction("String rtrim(String)");
295: addFunction("String ucase(String)");
296: addFunction("String soundex(String)");
297:
298: addFunction("String left(String, int)");
299: addFunction("String repeat(String, int)");
300: addFunction("String right(String, int)");
301:
302: addFunction("int locate(String, String)");
303: addFunction("int locate(String, String, int)");
304:
305: addFunction("String replace(String, String, String)");
306:
307: addFunction("String substring(String, int, int)");
308:
309: addFunction("String database()");
310: addFunction("String user()");
311:
312: addFunction("Date curdate()");
313: addFunction("Date curtime()");
314: addFunction("Date now()");
315:
316: addFunction("String dayname(Date)");
317: addFunction("String monthname(Date)");
318:
319: addFunction("int dayofmonth(Date)");
320: addFunction("int dayofweek(Date)");
321: addFunction("int dayofyear(Date)");
322: addFunction("int hour(Date)");
323: addFunction("int minute(Date)");
324: addFunction("int month(Date)");
325: addFunction("int quarter(Date)");
326: addFunction("int second(Date)");
327: addFunction("int week(Date)");
328: addFunction("int year(Date)");
329:
330: addFunction("Date timestampadd(Date, Date)");
331: addFunction("Date timestampdiff(Date, Date)");
332: }
333: }
|