KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > expression > Function


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.expression;
6
7 import java.sql.Connection JavaDoc;
8 import java.sql.Date JavaDoc;
9 import java.sql.ResultSet JavaDoc;
10 import java.sql.SQLException JavaDoc;
11 import java.sql.Time JavaDoc;
12 import java.sql.Timestamp JavaDoc;
13 import java.text.SimpleDateFormat JavaDoc;
14 import java.util.Calendar JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Locale JavaDoc;
17 import java.util.TimeZone JavaDoc;
18
19 import org.h2.engine.Database;
20 import org.h2.engine.Mode;
21 import org.h2.engine.Session;
22 import org.h2.message.Message;
23 import org.h2.schema.Sequence;
24 import org.h2.security.BlockCipher;
25 import org.h2.security.CipherFactory;
26 import org.h2.security.SHA256;
27 import org.h2.table.Column;
28 import org.h2.table.ColumnResolver;
29 import org.h2.table.TableFilter;
30 import org.h2.tools.CompressTool;
31 import org.h2.tools.Csv;
32 import org.h2.util.MathUtils;
33 import org.h2.util.MemoryUtils;
34 import org.h2.util.ObjectArray;
35 import org.h2.util.RandomUtils;
36 import org.h2.util.StringUtils;
37 import org.h2.value.Value;
38 import org.h2.value.ValueArray;
39 import org.h2.value.ValueBoolean;
40 import org.h2.value.ValueBytes;
41 import org.h2.value.ValueDate;
42 import org.h2.value.ValueDouble;
43 import org.h2.value.ValueInt;
44 import org.h2.value.ValueLong;
45 import org.h2.value.ValueNull;
46 import org.h2.value.ValueResultSet;
47 import org.h2.value.ValueString;
48 import org.h2.value.ValueTime;
49 import org.h2.value.ValueTimestamp;
50 import org.h2.value.ValueUuid;
51
52 /**
53  * @author Thomas
54  */

55
56 public class Function extends Expression implements FunctionCall {
57     // TODO functions: ODBC TIMESTAMPDIFF
58
// TODO functions: add function hashcode(value)
59

60     public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3, ATAN2 = 4,
61             BITAND = 5, BITOR = 6, BITXOR = 7, CEILING = 8, COS = 9, COT = 10,
62             DEGREES = 11, EXP = 12, FLOOR = 13, LOG = 14, LOG10 = 15, MOD = 16,
63             PI = 17, POWER = 18, RADIANS = 19, RAND = 20,
64             ROUND = 21, ROUNDMAGIC = 22, SIGN = 23, SIN = 24, SQRT = 25,
65             TAN = 26, TRUNCATE = 27, SECURE_RAND = 28,
66             HASH = 29, ENCRYPT = 30, DECRYPT = 31,
67             COMPRESS = 32, EXPAND = 33, ZERO = 34, RANDOM_UUID = 35;
68
69     public static final int ASCII = 50, BIT_LENGTH = 51, CHAR = 52, CHAR_LENGTH = 53,
70             CONCAT = 54, DIFFERENCE = 55, HEXTORAW = 56, INSERT = 57, INSTR = 58,
71             LCASE = 59, LEFT = 60, LENGTH = 61, LOCATE = 62, LTRIM = 63,
72             OCTET_LENGTH = 64, RAWTOHEX = 65, REPEAT = 66, REPLACE = 67,
73             RIGHT = 68, RTRIM = 69, SOUNDEX = 70, SPACE = 71, SUBSTR = 72,
74             SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78,
75             STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82,
76             XMLATTR = 83, XMLNODE = 84, XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87,
77             XMLTEXT = 88;
78
79     public static final int CURDATE = 100, CURTIME = 101, DATEADD = 102, DATEDIFF = 103,
80             DAYNAME = 104, DAYOFMONTH = 105, DAYOFWEEK = 106, DAYOFYEAR = 107,
81             HOUR = 108, MINUTE = 109, MONTH = 110, MONTHNAME = 111, NOW = 112,
82             QUARTER = 113, SECOND = 114, WEEK = 115, YEAR = 116,
83             CURRENT_DATE = 117, CURRENT_TIME = 118, CURRENT_TIMESTAMP = 119,
84             EXTRACT = 120, FORMATDATETIME = 121, PARSEDATETIME = 122;
85
86     public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
87             IDENTITY = 153, AUTOCOMMIT = 154, READONLY = 155, DATABASE_PATH = 156, LOCK_TIMEOUT = 157;
88
89     public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203,
90             COALESCE = 204, NULLIF = 205, CASE = 206, NEXTVAL = 207, CURRVAL = 208,
91             ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211, MEMORY_FREE = 212,
92             MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217;
93
94     private static final int VARARGS = -1;
95
96     private static HashMap JavaDoc functions;
97
98     private FunctionInfo info;
99     private Expression[] args;
100     private ObjectArray varargs;
101     private int dataType, scale;
102     private long precision;
103     private Database database;
104
105     private static HashMap JavaDoc datePart;
106     private static final SimpleDateFormat JavaDoc FORMAT_DAYNAME = new SimpleDateFormat JavaDoc(
107             "EEEE", Locale.ENGLISH);
108     private static final SimpleDateFormat JavaDoc FORMAT_MONTHNAME = new SimpleDateFormat JavaDoc(
109             "MMMM", Locale.ENGLISH);
110     private static final char[] SOUNDEX_INDEX = new char[128];
111
112     static {
113         datePart = new HashMap JavaDoc();
114         datePart.put("YY", new Integer JavaDoc(Calendar.YEAR));
115         datePart.put("YEAR", new Integer JavaDoc(Calendar.YEAR));
116         datePart.put("MM", new Integer JavaDoc(Calendar.MONTH));
117         datePart.put("MONTH", new Integer JavaDoc(Calendar.MONTH));
118         datePart.put("DD", new Integer JavaDoc(Calendar.DATE));
119         datePart.put("DAY", new Integer JavaDoc(Calendar.DATE));
120         datePart.put("HH", new Integer JavaDoc(Calendar.HOUR));
121         datePart.put("HOUR", new Integer JavaDoc(Calendar.HOUR));
122         datePart.put("MI", new Integer JavaDoc(Calendar.MINUTE));
123         datePart.put("MINUTE", new Integer JavaDoc(Calendar.MINUTE));
124         datePart.put("SS", new Integer JavaDoc(Calendar.SECOND));
125         datePart.put("SECOND", new Integer JavaDoc(Calendar.SECOND));
126         datePart.put("MS", new Integer JavaDoc(Calendar.MILLISECOND));
127         datePart.put("MILLISECOND", new Integer JavaDoc(Calendar.MILLISECOND));
128     }
129
130     static {
131         String JavaDoc index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
132         char number = 0;
133         for(int i=0; i<index.length(); i++) {
134             char c = index.charAt(i);
135             if(c<'9') {
136                 number = c;
137             } else {
138                 SOUNDEX_INDEX[c] = number;
139                 SOUNDEX_INDEX[Character.toLowerCase(c)] = number;
140             }
141         }
142     }
143
144     static {
145         functions = new HashMap JavaDoc();
146         addFunction("ABS", ABS, 1, Value.NULL);
147         addFunction("ACOS", ACOS, 1, Value.DOUBLE);
148         addFunction("ASIN", ASIN, 1, Value.DOUBLE);
149         addFunction("ATAN", ATAN, 1, Value.DOUBLE);
150         addFunction("ATAN2", ATAN2, 2, Value.DOUBLE);
151         addFunction("BITAND", BITAND, 2, Value.INT);
152         addFunction("BITOR", BITOR, 2, Value.INT);
153         addFunction("BITXOR", BITXOR, 2, Value.INT);
154         addFunction("CEILING", CEILING, 1, Value.DOUBLE);
155         addFunction("COS", COS, 1, Value.DOUBLE);
156         addFunction("COT", COT, 1, Value.DOUBLE);
157         addFunction("DEGREES", DEGREES, 1, Value.DOUBLE);
158         addFunction("EXP", EXP, 1, Value.DOUBLE);
159         addFunction("FLOOR", FLOOR, 1, Value.DOUBLE);
160         addFunction("LOG", LOG, 1, Value.DOUBLE);
161         addFunction("LOG10", LOG10, 1, Value.DOUBLE);
162         addFunction("MOD", MOD, 2, Value.INT);
163         addFunction("PI", PI, 0, Value.DOUBLE);
164         addFunction("POWER", POWER, 2, Value.DOUBLE);
165         addFunction("RADIANS", RADIANS, 1, Value.DOUBLE);
166         addFunctionNotConst("RAND", RAND, VARARGS, Value.DOUBLE); // no args: regular rand; with one arg: seed random generator
167
addFunction("ROUND", ROUND, 2, Value.DOUBLE);
168         addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE);
169         addFunction("SIGN", SIGN, 1, Value.INT);
170         addFunction("SIN", SIN, 1, Value.DOUBLE);
171         addFunction("SQRT", SQRT, 1, Value.DOUBLE);
172         addFunction("TAN", TAN, 1, Value.DOUBLE);
173         addFunction("TRUNCATE", TRUNCATE, 2, Value.DOUBLE);
174         addFunction("HASH", HASH, 3, Value.BYTES);
175         addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES);
176         addFunction("DECRYPT", DECRYPT, 3, Value.BYTES);
177         addFunctionNotConst("SECURE_RAND", SECURE_RAND, 1, Value.BYTES);
178         addFunction("COMPRESS", COMPRESS, VARARGS, Value.BYTES);
179         addFunction("EXPAND", EXPAND, 1, Value.BYTES);
180         addFunction("ZERO", ZERO, 0, Value.INT);
181         addFunctionNotConst("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID);
182         addFunctionNotConst("SYS_GUID", RANDOM_UUID, 0, Value.UUID);
183         // string
184
addFunction("ASCII", ASCII, 1, Value.INT);
185         addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.INT);
186         addFunction("CHAR", CHAR, 1, Value.STRING);
187         addFunction("CHAR_LENGTH", CHAR_LENGTH, 1, Value.INT);
188         addFunction("CHARACTER_LENGTH", CHAR_LENGTH, 1, Value.INT); // same as CHAR_LENGTH
189
addFunctionWithNull("CONCAT", CONCAT, VARARGS, Value.STRING);
190         addFunction("DIFFERENCE", DIFFERENCE, 2, Value.INT);
191         addFunction("HEXTORAW", HEXTORAW, 1, Value.STRING);
192         addFunctionWithNull("INSERT", INSERT, 4, Value.STRING);
193         addFunction("LCASE", LCASE, 1, Value.STRING);
194         addFunction("LEFT", LEFT, 2, Value.STRING);
195         addFunction("LENGTH", LENGTH, 1, Value.INT);
196         addFunction("LOCATE", LOCATE, VARARGS, Value.INT); // 2 or 3 arguments
197
addFunction("POSITION", LOCATE, 2, Value.INT); // same as LOCATE with 2 arguments
198
addFunction("INSTR", INSTR, VARARGS, Value.INT);
199         addFunction("LTRIM", LTRIM, VARARGS, Value.STRING);
200         addFunction("OCTET_LENGTH", OCTET_LENGTH, 1, Value.INT);
201         addFunction("RAWTOHEX", RAWTOHEX, 1, Value.STRING);
202         addFunction("REPEAT", REPEAT, 2, Value.STRING);
203         addFunctionWithNull("REPLACE", REPLACE, VARARGS, Value.STRING);
204         addFunction("RIGHT", RIGHT, 2, Value.STRING);
205         addFunction("RTRIM", RTRIM, VARARGS, Value.STRING);
206         addFunction("SOUNDEX", SOUNDEX, 1, Value.STRING);
207         addFunction("SPACE", SPACE, 1, Value.STRING);
208         addFunction("SUBSTR", SUBSTR, VARARGS, Value.STRING);
209         addFunction("SUBSTRING", SUBSTRING, VARARGS, Value.STRING);
210         addFunction("UCASE", UCASE, 1, Value.STRING);
211         addFunction("LOWER", LOWER, 1, Value.STRING);
212         addFunction("UPPER", UPPER, 1, Value.STRING);
213         addFunction("POSITION", POSITION, 2, Value.INT);
214         addFunction("TRIM", TRIM, VARARGS, Value.STRING);
215         addFunction("STRINGENCODE", STRINGENCODE, 1, Value.STRING);
216         addFunction("STRINGDECODE", STRINGDECODE, 1, Value.STRING);
217         addFunction("STRINGTOUTF8", STRINGTOUTF8, 1, Value.BYTES);
218         addFunction("UTF8TOSTRING", UTF8TOSTRING, 1, Value.STRING);
219         addFunction("XMLATTR", XMLATTR, 2, Value.STRING);
220         addFunctionWithNull("XMLNODE", XMLNODE, VARARGS, Value.STRING);
221         addFunction("XMLCOMMENT", XMLCOMMENT, 1, Value.STRING);
222         addFunction("XMLCDATA", XMLCDATA, 1, Value.STRING);
223         addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING);
224         addFunction("XMLTEXT", XMLTEXT, 1, Value.STRING);
225
226         // date
227
addFunctionNotConst("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE);
228         addFunctionNotConst("CURDATE", CURDATE, 0, Value.DATE);
229         addFunctionNotConst("CURRENT_TIME", CURRENT_TIME, 0, Value.TIME);
230         addFunctionNotConst("CURTIME", CURTIME, 0, Value.TIME);
231         addFunctionNotConst("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP, VARARGS, Value.TIMESTAMP);
232         addFunctionNotConst("NOW", NOW, VARARGS, Value.TIMESTAMP);
233         addFunction("DATEADD", DATEADD, 3, Value.TIMESTAMP);
234         addFunction("DATEDIFF", DATEDIFF, 3, Value.LONG);
235         addFunction("DAYNAME", DAYNAME, 1, Value.STRING);
236         addFunction("DAY", DAYOFMONTH, 1, Value.INT);
237         addFunction("DAYOFMONTH", DAYOFMONTH, 1, Value.INT);
238         addFunction("DAYOFWEEK", DAYOFWEEK, 1, Value.INT);
239         addFunction("DAYOFYEAR", DAYOFYEAR, 1, Value.INT);
240         addFunction("HOUR", HOUR, 1, Value.INT);
241         addFunction("MINUTE", MINUTE, 1, Value.INT);
242         addFunction("MONTH", MONTH, 1, Value.INT);
243         addFunction("MONTHNAME", MONTHNAME, 1, Value.STRING);
244         addFunction("QUARTER", QUARTER, 1, Value.INT);
245         addFunction("SECOND", SECOND, 1, Value.INT);
246         addFunction("WEEK", WEEK, 1, Value.INT);
247         addFunction("YEAR", YEAR, 1, Value.INT);
248         addFunction("EXTRACT", EXTRACT, 2, Value.INT);
249         addFunctionWithNull("FORMATDATETIME", FORMATDATETIME, VARARGS, Value.STRING);
250         addFunctionWithNull("PARSEDATETIME", PARSEDATETIME, VARARGS, Value.TIMESTAMP);
251         // system
252
addFunctionNotConst("DATABASE", DATABASE, 0, Value.STRING);
253         addFunctionNotConst("USER", USER, 0, Value.STRING);
254         addFunctionNotConst("CURRENT_USER", CURRENT_USER, 0, Value.STRING);
255         addFunctionNotConst("IDENTITY", IDENTITY, 0, Value.LONG);
256         addFunctionNotConst("IDENTITY_VAL_LOCAL", IDENTITY, 0, Value.LONG);
257         addFunctionNotConst("LAST_INSERT_ID", IDENTITY, 0, Value.LONG);
258         addFunctionNotConst("AUTOCOMMIT", AUTOCOMMIT, 0, Value.BOOLEAN);
259         addFunctionNotConst("READONLY", READONLY, 0, Value.BOOLEAN);
260         addFunction("DATABASE_PATH", DATABASE_PATH, 0, Value.STRING);
261         addFunction("LOCK_TIMEOUT", LOCK_TIMEOUT, 0, Value.INT);
262         addFunctionWithNull("IFNULL", IFNULL, 2, Value.NULL);
263         addFunctionWithNull("CASEWHEN", CASEWHEN, 3, Value.NULL);
264         addFunctionWithNull("CONVERT", CONVERT, 1, Value.NULL);
265         addFunctionWithNull("CAST", CAST, 1, Value.NULL);
266         addFunctionWithNull("COALESCE", COALESCE, VARARGS, Value.NULL);
267         addFunctionWithNull("NVL", COALESCE, VARARGS, Value.NULL);
268         addFunctionWithNull("NULLIF", NULLIF, 2, Value.NULL);
269         addFunctionWithNull("CASE", CASE, VARARGS, Value.NULL);
270         addFunctionNotConst("NEXTVAL", NEXTVAL, VARARGS, Value.LONG);
271         addFunctionNotConst("CURRVAL", CURRVAL, VARARGS, Value.LONG);
272         addFunction("ARRAY_GET", ARRAY_GET, 2, Value.NULL);
273         addFunction("CSVREAD", CSVREAD, VARARGS, Value.RESULT_SET, false, false);
274         addFunction("CSVWRITE", CSVWRITE, VARARGS, Value.RESULT_SET, false, false);
275         addFunctionNotConst("MEMORY_FREE", MEMORY_FREE, 0, Value.INT);
276         addFunctionNotConst("MEMORY_USED", MEMORY_USED, 0, Value.INT);
277         addFunctionNotConst("LOCK_MODE", LOCK_MODE, 0, Value.INT);
278         addFunctionNotConst("SCHEMA", SCHEMA, 0, Value.STRING);
279         addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT);
280         addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT);
281     }
282
283     private static void addFunction(String JavaDoc name, int type, int parameterCount,
284             int dataType, boolean nullIfParameterIsNull, boolean isDeterm) {
285         FunctionInfo info = new FunctionInfo();
286         info.name = name;
287         info.type = type;
288         info.parameterCount = parameterCount;
289         info.dataType = dataType;
290         info.nullIfParameterIsNull = nullIfParameterIsNull;
291         info.isDeterministic = isDeterm;
292         functions.put(name, info);
293     }
294
295     private static void addFunctionNotConst(String JavaDoc name, int type, int parameterCount,
296             int dataType) {
297         addFunction(name, type, parameterCount, dataType, true, false);
298     }
299
300     private static void addFunction(String JavaDoc name, int type, int parameterCount,
301             int dataType) {
302         addFunction(name, type, parameterCount, dataType, true, true);
303     }
304
305     private static void addFunctionWithNull(String JavaDoc name, int type,
306             int parameterCount, int dataType) {
307         addFunction(name, type, parameterCount, dataType, false, true);
308     }
309
310     public static Function getFunction(Database database, String JavaDoc name) throws SQLException JavaDoc {
311         FunctionInfo info = (FunctionInfo) functions.get(name);
312         if(info==null) {
313             return null;
314         }
315         return new Function(database, info);
316     }
317
318     private Function(Database database, FunctionInfo info) {
319         this.database = database;
320         this.info = info;
321         if(info.parameterCount == VARARGS) {
322             varargs = new ObjectArray();
323         } else {
324             args = new Expression[info.parameterCount];
325         }
326     }
327
328     public void setParameter(int index, Expression param) throws SQLException JavaDoc {
329         if(varargs != null) {
330             varargs.add(param);
331         } else {
332             if(index >= args.length) {
333                 throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, ""+args.length);
334             }
335             args[index] = param;
336         }
337     }
338
339     private strictfp double log10(double value) {
340         return roundmagic(StrictMath.log(value) / StrictMath.log(10));
341     }
342
343     public Value getValue(Session session) throws SQLException JavaDoc {
344         return getValueWithArgs(session, args);
345     }
346
347     public Value getValueWithArgs(Session session, Expression[] args) throws SQLException JavaDoc {
348         if (info.nullIfParameterIsNull) {
349             for (int i = 0; i < args.length; i++) {
350                 Expression e = args[i];
351                 if (e != null && e.getValue(session) == ValueNull.INSTANCE) {
352                     return ValueNull.INSTANCE;
353                 }
354             }
355         }
356         Value v0 = args.length < 1 || args[0] == null ? null : args[0].getValue(session);
357         switch (info.type) {
358         case IFNULL:
359             return v0 == ValueNull.INSTANCE ? args[1].getValue(session) : v0;
360         case CASEWHEN: {
361             if(v0 == ValueNull.INSTANCE) {
362                 return v0;
363             }
364             Expression result = v0.getBoolean().booleanValue() ? args[1] : args[2];
365             return result.getValue(session);
366         }
367         case COALESCE: {
368             for (int i = 0; i < args.length; i++) {
369                 Value v = i==0 ? v0 : args[i].getValue(session);
370                 if (!(v == ValueNull.INSTANCE)) {
371                     return v.convertTo(dataType);
372                 }
373             }
374             return v0;
375         }
376         case CASE: {
377             // TODO function CASE: document & implement functionality
378
int i = 0;
379             for (; i < args.length; i++) {
380                 Value when = args[i++].getValue(session);
381                 if (Boolean.TRUE.equals(when)) {
382                     return args[i].getValue(session);
383                 }
384             }
385             return i < args.length ? args[i].getValue(session) : ValueNull.INSTANCE;
386         }
387         case ARRAY_GET: {
388             if(v0.getType() == Value.ARRAY) {
389                 Value v1 = args[1].getValue(session);
390                 int element = v1.getInt();
391                 Value[] list = ((ValueArray) v0).getList();
392                 if(element < 1 || element > list.length) {
393                     return ValueNull.INSTANCE;
394                 }
395                 return list[element-1];
396             }
397             return ValueNull.INSTANCE;
398         }
399         case ARRAY_LENGTH: {
400             if(v0.getType() == Value.ARRAY) {
401                 Value[] list = ((ValueArray) v0).getList();
402                 return ValueInt.get(list.length);
403             }
404             return ValueNull.INSTANCE;
405         }
406         default:
407             // ok
408
}
409         Value v1 = args.length < 2 || args[1] == null ? null : args[1].getValue(session);
410         Value v2 = args.length < 3 || args[2] == null ? null : args[2].getValue(session);
411         switch (info.type) {
412         case ABS:
413             return v0.getSignum() > 0 ? v0 : v0.negate();
414         case ACOS:
415             return ValueDouble.get(Math.acos(v0.getDouble()));
416         case ASIN:
417             return ValueDouble.get(Math.asin(v0.getDouble()));
418         case ATAN:
419             return ValueDouble.get(Math.atan(v0.getDouble()));
420         case ATAN2:
421             return ValueDouble.get(Math.atan2(v0.getDouble(), v1.getDouble()));
422         case BITAND:
423             return ValueInt.get(v0.getInt() & v1.getInt());
424         case BITOR:
425             return ValueInt.get(v0.getInt() | v1.getInt());
426         case BITXOR:
427             return ValueInt.get(v0.getInt() ^ v1.getInt());
428         case CEILING:
429             return ValueDouble.get(Math.ceil(v0.getDouble()));
430         case COS:
431             return ValueDouble.get(Math.cos(v0.getDouble()));
432         case COT: {
433             double d = Math.tan(v0.getDouble());
434             if (d == 0.0) {
435                 throw Message.getSQLException(Message.DIVISION_BY_ZERO_1, getSQL());
436             }
437             return ValueDouble.get(1. / d);
438         }
439         case DEGREES:
440             return ValueDouble.get(Math.toDegrees(v0.getDouble()));
441         case EXP:
442             return ValueDouble.get(Math.exp(v0.getDouble()));
443         case FLOOR:
444             return ValueDouble.get(Math.floor(v0.getDouble()));
445         case LOG:
446             return ValueDouble.get(Math.log(v0.getDouble()));
447         case LOG10:
448             return ValueDouble.get(log10(v0.getDouble()));
449         case MOD: {
450             int x = v1.getInt();
451             if (x == 0.0) {
452                 throw Message.getSQLException(Message.DIVISION_BY_ZERO_1, getSQL());
453             }
454             return ValueInt.get(v0.getInt() % x);
455         }
456         case PI:
457             return ValueDouble.get(Math.PI);
458         case POWER:
459             return ValueDouble.get(Math.pow(v0.getDouble(), v1.getDouble()));
460         case RADIANS:
461             return ValueDouble.get(Math.toRadians(v0.getDouble()));
462         case RAND: {
463             if(v0 != null) {
464                 session.getRandom().setSeed(v0.getInt());
465             }
466             // TODO function rand: if seed value is set, return a random value? probably yes
467
return ValueDouble.get(session.getRandom().nextDouble());
468         }
469         case ROUND: {
470             double f = Math.pow(10., v1.getDouble());
471             return ValueDouble.get(Math.round(v0.getDouble() * f) / f);
472         }
473         case ROUNDMAGIC:
474             return ValueDouble.get(roundmagic(v0.getDouble()));
475         case SIGN:
476             return ValueInt.get(v0.getSignum());
477         case SIN:
478             return ValueDouble.get(Math.sin(v0.getDouble()));
479         case SQRT:
480             return ValueDouble.get(Math.sqrt(v0.getDouble()));
481         case TAN:
482             return ValueDouble.get(Math.tan(v0.getDouble()));
483         case TRUNCATE: {
484             double d = v0.getDouble();
485             int p = v1.getInt();
486             double f = Math.pow(10., p);
487             double g = d * f;
488             return ValueDouble.get(((d < 0) ? Math.ceil(g) : Math.floor(g)) / f);
489         }
490         case SECURE_RAND:
491             return ValueBytes.getNoCopy(RandomUtils.getSecureBytes(v0.getInt()));
492         case HASH:
493             return ValueBytes.getNoCopy(getHash(v0.getString(), v1.getBytesNoCopy(), v2.getInt()));
494         case ENCRYPT:
495             return ValueBytes.getNoCopy(encrypt(v0.getString(), v1.getBytesNoCopy(), v2.getBytesNoCopy()));
496         case DECRYPT:
497             return ValueBytes.getNoCopy(decrypt(v0.getString(), v1.getBytesNoCopy(), v2.getBytesNoCopy()));
498         case COMPRESS: {
499             String JavaDoc algorithm = null;
500             if(v1 != null) {
501                 algorithm = v1.getString();
502             }
503             return ValueBytes.getNoCopy(CompressTool.getInstance().compress(v0.getBytesNoCopy(), algorithm));
504         }
505         case EXPAND:
506             return ValueBytes.getNoCopy(CompressTool.getInstance().expand(v0.getBytesNoCopy()));
507         case ZERO:
508             return ValueInt.get(0);
509         case RANDOM_UUID:
510             return ValueUuid.getNewRandom();
511         // string
512
case ASCII: {
513             String JavaDoc s = v0.getString();
514             if (s.length() == 0) {
515                 return ValueNull.INSTANCE;
516             }
517             return ValueInt.get(s.charAt(0));
518         }
519         case BIT_LENGTH:
520             return ValueInt.get(16 * length(v0));
521         case CHAR:
522             return ValueString.get(String.valueOf((char) v0.getInt()));
523         case CHAR_LENGTH:
524         case LENGTH:
525             return ValueInt.get(length(v0));
526         case OCTET_LENGTH:
527             return ValueInt.get(2 * length(v0));
528         case CONCAT: {
529             Value concat = ValueNull.INSTANCE;
530             for (int i = 0; i < args.length; i++) {
531                 Value v = args[i].getValue(session);
532                 if (v == ValueNull.INSTANCE) {
533                     continue;
534                 }
535                 if(concat == ValueNull.INSTANCE) {
536                     concat = v;
537                 } else {
538                     concat = ValueString.get(concat.getString().concat(v.getString()));
539                 }
540             }
541             return concat;
542         }
543         case DIFFERENCE:
544             return ValueInt.get(getDifference(v0.getString(), v1.getString()));
545         case HEXTORAW:
546             return ValueString.get(hexToRaw(v0.getString()));
547         case INSERT: {
548             if (v1 == ValueNull.INSTANCE || v2 == ValueNull.INSTANCE) {
549                 return v1;
550             }
551             Value v3 = args[3].getValue(session);
552             return ValueString.get(insert(v0.getString(), v1.getInt(), v2.getInt(), v3.getString()));
553         }
554         case LOWER:
555         case LCASE:
556             // TODO this is locale specific, need to document or provide a way to set the locale
557
return ValueString.get(v0.getString().toLowerCase());
558         case LEFT:
559             return ValueString.get(left(v0.getString(), v1.getInt()));
560         case LOCATE: {
561             int start = v2 == null ? 0 : v2.getInt();
562             return ValueInt.get(locate(v0.getString(), v1.getString(), start));
563         }
564         case INSTR: {
565             int start = v2 == null ? 0 : v2.getInt();
566             return ValueInt.get(locate(v1.getString(), v0.getString(), start));
567         }
568         case RAWTOHEX:
569             return ValueString.get(rawToHex(v0.getString()));
570         case REPEAT: {
571             // TODO DOS attacks: limit len?
572
int count = Math.max(0, v1.getInt());
573             return ValueString.get(repeat(v0.getString(), count));
574         }
575         case REPLACE: {
576             String JavaDoc s0 = v0 == ValueNull.INSTANCE ? "" : v0.getString();
577             String JavaDoc s1 = v1 == ValueNull.INSTANCE ? "" : v1.getString();
578             String JavaDoc s2 = (v2==null || v2 == ValueNull.INSTANCE) ? "" : v2.getString();
579             return ValueString.get(replace(s0, s1, s2));
580         }
581         case RIGHT:
582             return ValueString.get(right(v0.getString(), v1.getInt()));
583         case LTRIM:
584             return ValueString.get(trim(v0.getString(), true, false, v1 == null ? " " : v1.getString()));
585         case TRIM:
586             return ValueString.get(trim(v0.getString(), true, true, v1 == null ? " " : v1.getString()));
587         case RTRIM:
588             return ValueString.get(trim(v0.getString(), false, true, v1 == null ? " " : v1.getString()));
589         case SOUNDEX:
590             return ValueString.get(getSoundex(v0.getString()));
591         case SPACE: {
592             // TODO DOS attacks: limit len?
593
int len = Math.max(0, v0.getInt());
594             char[] chars = new char[len];
595             for (int i = len - 1; i >= 0; i--) {
596                 chars[i] = ' ';
597             }
598             return ValueString.get(new String JavaDoc(chars));
599         }
600         case SUBSTR:
601         case SUBSTRING: {
602             String JavaDoc s = v0.getString();
603             int length = v2 == null ? s.length() : v2.getInt();
604             return ValueString.get(substring(s, v1.getInt(), length));
605         }
606         case POSITION:
607             return ValueInt.get(locate(v0.getString(), v1.getString(), 0));
608         case UPPER:
609         case UCASE:
610             // TODO this is locale specific, need to document or provide a way to set the locale
611
return ValueString.get(v0.getString().toUpperCase());
612         case STRINGENCODE:
613             return ValueString.get(StringUtils.javaEncode(v0.getString()));
614         case STRINGDECODE:
615             return ValueString.get(StringUtils.javaDecode(v0.getString()));
616         case STRINGTOUTF8:
617             return ValueBytes.getNoCopy(StringUtils.utf8Encode(v0.getString()));
618         case UTF8TOSTRING:
619             return ValueString.get(StringUtils.utf8Decode(v0.getBytesNoCopy()));
620         case XMLATTR:
621             return ValueString.get(StringUtils.xmlAttr(v0.getString(), v1.getString()));
622         case XMLNODE: {
623             String JavaDoc attr = v1 == null ? null : v1 == ValueNull.INSTANCE ? null : v1.getString();
624             String JavaDoc content = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString();
625             return ValueString.get(StringUtils.xmlNode(v0.getString(), attr, content));
626         }
627         case XMLCOMMENT:
628             return ValueString.get(StringUtils.xmlComment(v0.getString()));
629         case XMLCDATA:
630             return ValueString.get(StringUtils.xmlCData(v0.getString()));
631         case XMLSTARTDOC:
632             return ValueString.get(StringUtils.xmlStartDoc());
633         case XMLTEXT:
634             return ValueString.get(StringUtils.xmlText(v0.getString()));
635         // date
636
case DATEADD:
637             return ValueTimestamp.getNoCopy(dateadd(v0.getString(), v1.getInt(), v2.getTimestampNoCopy()));
638         case DATEDIFF:
639             return ValueLong.get(datediff(v0.getString(), v1.getTimestampNoCopy(), v2.getTimestampNoCopy()));
640         case DAYNAME:
641             return ValueString.get(FORMAT_DAYNAME.format(v0.getDateNoCopy()));
642         case DAYOFMONTH:
643             return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH));
644         case DAYOFWEEK:
645             return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK));
646         case DAYOFYEAR:
647             return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR));
648         case HOUR:
649             return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY));
650         case MINUTE:
651             return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE));
652         case MONTH:
653             return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH));
654         case MONTHNAME:
655             return ValueString.get(FORMAT_MONTHNAME.format(v0.getDateNoCopy()));
656         case QUARTER:
657             return ValueInt.get((getDatePart(v0.getTimestamp(), Calendar.MONTH) - 1) / 3 + 1);
658         case SECOND:
659             return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.SECOND));
660         case WEEK:
661             return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.WEEK_OF_YEAR));
662         case YEAR:
663             return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.YEAR));
664         case CURDATE:
665         case CURRENT_DATE:
666             // need to normalize
667
return ValueDate.get(new Date JavaDoc(System.currentTimeMillis()));
668         case CURTIME:
669         case CURRENT_TIME:
670             // need to normalize
671
return ValueTime.get(new Time JavaDoc(System.currentTimeMillis()));
672         case NOW:
673         case CURRENT_TIMESTAMP: {
674             ValueTimestamp vt = ValueTimestamp.getNoCopy(new Timestamp JavaDoc(System.currentTimeMillis()));
675             if(v0 != null) {
676                 vt = (ValueTimestamp)vt.convertScale(Mode.getCurrentMode().convertOnlyToSmallerScale, v0.getInt());
677             }
678             return vt;
679         }
680         case EXTRACT: {
681             int field = getDatePart(v0.getString());
682             return ValueInt.get(getDatePart(v1.getTimestamp(), field));
683         }
684         case FORMATDATETIME: {
685             if(v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) {
686                 return ValueNull.INSTANCE;
687             }
688             String JavaDoc locale = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString();
689             Value v3 = args.length <= 3 ? null : args[3].getValue(session);
690             String JavaDoc tz = v3 == null ? null : v3 == ValueNull.INSTANCE ? null : v3.getString();
691             return ValueString.get(StringUtils.formatDateTime(v0.getTimestamp(), v1.getString(), locale, tz));
692         }
693         case PARSEDATETIME: {
694             if(v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) {
695                 return ValueNull.INSTANCE;
696             }
697             String JavaDoc locale = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString();
698             Value v3 = args.length <= 3 ? null : args[3].getValue(session);
699             String JavaDoc tz = v3 == null ? null : v3 == ValueNull.INSTANCE ? null : v3.getString();
700             java.util.Date JavaDoc d = StringUtils.parseDateTime(v0.getString(), v1.getString(), locale, tz);
701             return ValueTimestamp.getNoCopy(new Timestamp JavaDoc(d.getTime()));
702         }
703         // system
704
case DATABASE:
705             return ValueString.get(database.getShortName());
706         case USER:
707         case CURRENT_USER:
708             return ValueString.get(session.getUser().getName());
709         case IDENTITY:
710             return ValueLong.get(session.getLastIdentity());
711         case AUTOCOMMIT:
712             return ValueBoolean.get(session.getAutoCommit());
713         case READONLY:
714             return ValueBoolean.get(database.getReadOnly());
715         case DATABASE_PATH: {
716             String JavaDoc path = database.getDatabasePath();
717             return path == null ? (Value)ValueNull.INSTANCE : ValueString.get(path);
718         }
719         case LOCK_TIMEOUT:
720             return ValueInt.get(session.getLockTimeout());
721         case NULLIF:
722             return database.areEqual(v0, v1) ? ValueNull.INSTANCE : v0;
723         case CAST:
724             // TODO function convert compatibility with MS SQL Server: convert(varchar(255), name)
725
case CONVERT: {
726             v0 = v0.convertTo(dataType);
727             v0 = v0.convertScale(Mode.getCurrentMode().convertOnlyToSmallerScale, scale);
728             v0 = v0.convertPrecision(precision);
729             return v0;
730         }
731         case NEXTVAL: {
732             Sequence sequence = getSequence(session, v0, v1);
733             SequenceValue value = new SequenceValue(sequence);
734             return value.getValue(session);
735         }
736         case CURRVAL: {
737             Sequence sequence = getSequence(session, v0, v1);
738             return ValueLong.get(sequence.getCurrentValue());
739         }
740         case CSVREAD: {
741             String JavaDoc fileName = v0.getString();
742             String JavaDoc columnList = v1 == null ? null : v1.getString();
743             String JavaDoc[] columns = StringUtils.arraySplit(columnList, ',', true);
744             String JavaDoc charset = v2 == null ? null : v2.getString();
745             ValueResultSet vr = ValueResultSet.get(Csv.getInstance().read(fileName, columns, charset));
746             return vr;
747         }
748         case CSVWRITE: {
749             Connection JavaDoc conn = session.createConnection(false);
750             String JavaDoc charset = v2 == null ? null : v2.getString();
751             Csv.getInstance().write(conn, v0.getString(), v1.getString(), charset);
752             return ValueNull.INSTANCE;
753         }
754         case MEMORY_FREE:
755             session.getUser().checkAdmin();
756             return ValueInt.get(MemoryUtils.getMemoryFree());
757         case MEMORY_USED:
758             session.getUser().checkAdmin();
759             return ValueInt.get(MemoryUtils.getMemoryUsed());
760         case LOCK_MODE:
761             return ValueInt.get(database.getLockMode());
762         case SCHEMA:
763             return ValueString.get(session.getCurrentSchemaName());
764         case SESSION_ID:
765             return ValueInt.get(session.getId());
766         default:
767             throw Message.getInternalError("type=" + info.type);
768         }
769     }
770
771     Sequence getSequence(Session session, Value v0, Value v1) throws SQLException JavaDoc {
772         String JavaDoc schemaName, sequenceName;
773         if(v1 == null) {
774             schemaName = session.getCurrentSchemaName();
775             sequenceName = StringUtils.toUpperEnglish(v0.getString());
776         } else {
777             schemaName = v0.getString();
778             sequenceName = v1.getString();
779         }
780         return database.getSchema(schemaName).getSequence(sequenceName);
781     }
782     
783     private int length(Value v) throws SQLException JavaDoc {
784         switch(v.getType()) {
785         case Value.BLOB:
786         case Value.CLOB:
787         case Value.BYTES:
788         case Value.JAVA_OBJECT:
789             return (int)v.getPrecision();
790         }
791         return v.getString().length();
792     }
793
794     private byte[] getPaddedArrayCopy(byte[] data, int blockSize) {
795         int size = MathUtils.roundUp(data.length, blockSize);
796         byte[] newData = new byte[size];
797         System.arraycopy(data, 0, newData, 0, data.length);
798         return newData;
799     }
800
801     private byte[] decrypt(String JavaDoc algorithm, byte[] key, byte[] data) throws SQLException JavaDoc {
802         BlockCipher cipher = CipherFactory.getBlockCipher(algorithm);
803         byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength());
804         cipher.setKey(newKey);
805         byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN);
806         cipher.decrypt(newData, 0, newData.length);
807         return newData;
808     }
809
810     private byte[] encrypt(String JavaDoc algorithm, byte[] key, byte[] data) throws SQLException JavaDoc {
811         BlockCipher cipher = CipherFactory.getBlockCipher(algorithm);
812         byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength());
813         cipher.setKey(newKey);
814         byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN);
815         cipher.encrypt(newData, 0, newData.length);
816         return newData;
817     }
818
819     private byte[] getHash(String JavaDoc algorithm, byte[] bytes, int iterations) throws SQLException JavaDoc {
820         SHA256 hash = CipherFactory.getHash(algorithm);
821         for(int i=0; i<iterations; i++) {
822             bytes = hash.getHash(bytes);
823         }
824         return bytes;
825     }
826
827     private static int getDatePart(Timestamp JavaDoc d, int field) {
828         Calendar JavaDoc c = Calendar.getInstance();
829         c.setTime(d);
830         int value = c.get(field);
831         if(field == Calendar.MONTH) {
832             value++;
833         }
834         return value;
835     }
836
837     // private static long datediffRound(String part, Date d1, Date d2) throws SQLException {
838
// // diff (yy, 31.12.2004, 1.1.2005) = 0
839
// Integer p = (Integer)datePart.get(StringUtils.toUpperEnglish(part));
840
// if(p==null) {
841
// throw Errors.getSQLException(Errors.INVALID_VALUE_2, new String[]{"part", part}, null);
842
// }
843
// int field = p.intValue();
844
// long t1 = d1.getTime(), t2 = d2.getTime();
845
// switch(field) {
846
// case Calendar.MILLISECOND:
847
// return t2 - t1;
848
// case Calendar.SECOND:
849
// return (t2 - t1) / 1000;
850
// case Calendar.MINUTE:
851
// return (t2 - t1) / 1000 / 60;
852
// case Calendar.HOUR:
853
// return (t2 - t1) / 1000 / 60 / 60;
854
// case Calendar.DATE:
855
// return (t2 - t1) / 1000 / 60 / 60 / 24;
856
// }
857
// Calendar g1 = Calendar.getInstance();
858
// g1.setTimeInMillis(t1);
859
// int year1 = g1.get(Calendar.YEAR);
860
// Calendar g2 = Calendar.getInstance();
861
// g2.setTimeInMillis(t2);
862
// int year2 = g2.get(Calendar.YEAR);
863
// int result = year2 - year1;
864
// if(field==Calendar.MONTH) {
865
// int month1 = g1.get(Calendar.MONTH);
866
// int month2 = g2.get(Calendar.MONTH);
867
// result = 12 * result + (month2 - month1);
868
// g2.set(Calendar.MONTH, month1);
869
// }
870
// g2.set(Calendar.YEAR, year1);
871
// if(result > 0 && g1.after(g2)) {
872
// result--;
873
// } else if(result < 0 && g1.before(g2)) {
874
// result++;
875
// }
876
// return result;
877
// }
878

879     private static int getDatePart(String JavaDoc part) throws SQLException JavaDoc {
880         Integer JavaDoc p = (Integer JavaDoc) datePart.get(StringUtils.toUpperEnglish(part));
881         if(p==null) {
882             throw Message.getSQLException(Message.INVALID_VALUE_2, new String JavaDoc[] { "part", part }, null);
883         }
884         return p.intValue();
885     }
886
887     private static Timestamp JavaDoc dateadd(String JavaDoc part, int count, Timestamp JavaDoc d) throws SQLException JavaDoc {
888         int field = getDatePart(part);
889         Calendar JavaDoc calendar = Calendar.getInstance();
890         int nanos = d.getNanos() % 1000000;
891         calendar.setTime(d);
892         calendar.add(field, count);
893         // TODO gcj: required so that the millis are calculated?
894
calendar.get(Calendar.YEAR);
895         calendar.get(Calendar.HOUR_OF_DAY);
896         long t = calendar.getTime().getTime();
897         Timestamp JavaDoc ts = new Timestamp JavaDoc(t);
898         ts.setNanos(ts.getNanos() + nanos);
899         return ts;
900     }
901
902     private static long datediff(String JavaDoc part, Timestamp JavaDoc d1, Timestamp JavaDoc d2) throws SQLException JavaDoc {
903         // diff (yy, 31.12.2004, 1.1.2005) = 1
904
int field = getDatePart(part);
905         Calendar JavaDoc calendar = Calendar.getInstance();
906         long t1 = d1.getTime(), t2 = d2.getTime();
907         // need to convert to UTC, otherwise we get inconsistent results with certain timezones (those that are 30 minites off)
908
TimeZone JavaDoc zone = calendar.getTimeZone();
909         calendar.setTime(d1);
910         t1 += zone.getOffset(calendar.get(Calendar.ERA), calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
911                 calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK), calendar.get(Calendar.MILLISECOND));
912         calendar.setTime(d2);
913         t2 += zone.getOffset(calendar.get(Calendar.ERA), calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
914                 calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK), calendar.get(Calendar.MILLISECOND));
915         switch (field) {
916         case Calendar.MILLISECOND:
917             return t2 - t1;
918         case Calendar.SECOND:
919         case Calendar.MINUTE:
920         case Calendar.HOUR: {
921             // first 'normalize' the numbers so both are not negative
922
long hour = 60*60*1000;
923             long add = Math.min(t1/hour*hour, t2/hour*hour);
924             t1 -= add;
925             t2 -= add;
926             switch(field) {
927             case Calendar.SECOND:
928                 return t2 / 1000 - t1 / 1000;
929             case Calendar.MINUTE:
930                 return t2 / (60 * 1000) - t1 / (60 * 1000);
931             case Calendar.HOUR:
932                 return t2/hour - t1/hour;
933             default:
934                 throw Message.getInternalError("field:" + field);
935             }
936         }
937         case Calendar.DATE:
938             return t2 / (24 * 60 * 60 * 1000) - t1 / (24 * 60 * 60 * 1000);
939         }
940         calendar.setTime(new Timestamp JavaDoc(t1));
941         int year1 = calendar.get(Calendar.YEAR);
942         int month1 = calendar.get(Calendar.MONTH);
943         calendar.setTime(new Timestamp JavaDoc(t2));
944         int year2 = calendar.get(Calendar.YEAR);
945         int month2 = calendar.get(Calendar.MONTH);
946         int result = year2 - year1;
947         if (field == Calendar.MONTH) {
948             result = 12 * result + (month2 - month1);
949         }
950         return result;
951     }
952
953     private static String JavaDoc substring(String JavaDoc s, int start, int length) {
954         int len = s.length();
955         start--;
956         if(start < 0) {
957             start = 0;
958         }
959         if(length < 0) {
960             length = 0;
961         }
962         start = (start > len) ? len : start;
963         if (start + length > len) {
964             length = len - start;
965         }
966         return s.substring(start, start + length);
967     }
968
969     private static String JavaDoc trim(String JavaDoc s, boolean leading, boolean trailing, String JavaDoc sp) {
970         char space = (sp == null || sp.length() < 1) ? ' ' : sp.charAt(0);
971         // TODO function trim: HSQLDB says 'tabs are not removed', but they are. check what other databases do
972
if(leading) {
973             int len = s.length(), i = 0;
974             while (i < len && s.charAt(i) == space) {
975                 i++;
976             }
977             s = (i == 0) ? s : s.substring(i);
978         }
979         if(trailing) {
980             int endindex = s.length() - 1;
981             int i = endindex;
982             while (i >= 0 && s.charAt(i) == space) {
983                 i--;
984             }
985             s = i == endindex ? s : s.substring(0, i + 1);
986         }
987         return s;
988     }
989
990     private static String JavaDoc replace(String JavaDoc s, String JavaDoc replace, String JavaDoc with) {
991         if(replace == null || replace.length()==0) {
992             // avoid out of memory
993
return s;
994         }
995         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
996         int start = 0;
997         int len = replace.length();
998         while (true) {
999             int i = s.indexOf(replace, start);
1000            if (i == -1) {
1001                break;
1002            }
1003            buff.append(s.substring(start, i));
1004            buff.append(with);
1005            start = i + len;
1006        }
1007        buff.append(s.substring(start));
1008        return buff.toString();
1009    }
1010
1011    private static String JavaDoc repeat(String JavaDoc s, int count) {
1012        StringBuffer JavaDoc buff = new StringBuffer JavaDoc(s.length() * count);
1013        while (count-- > 0) {
1014            buff.append(s);
1015        }
1016        return buff.toString();
1017    }
1018
1019    private static String JavaDoc rawToHex(String JavaDoc s) {
1020        StringBuffer JavaDoc buff = new StringBuffer JavaDoc(4 * s.length());
1021        for (int i = 0; i < s.length(); i++) {
1022            String JavaDoc hex = Integer.toHexString(s.charAt(i) & 0xffff);
1023            for (int j = hex.length(); j < 4; j++) {
1024                buff.append('0');
1025            }
1026            buff.append(hex);
1027        }
1028        return buff.toString();
1029    }
1030
1031    private static int locate(String JavaDoc search, String JavaDoc s, int start) {
1032        int i = (start < 0) ? 0 : start - 1;
1033        return s.indexOf(search, i) + 1;
1034    }
1035
1036    private static String JavaDoc right(String JavaDoc s, int count) {
1037        if (count < 0) {
1038            count = 0;
1039        } else if (count > s.length()) {
1040            count = s.length();
1041        }
1042        return s.substring(s.length() - count);
1043    }
1044
1045    private static String JavaDoc left(String JavaDoc s, int count) {
1046        if (count < 0) {
1047            count = 0;
1048        } else if (count > s.length()) {
1049            count = s.length();
1050        }
1051        return s.substring(0, count);
1052    }
1053
1054    private static String JavaDoc insert(String JavaDoc s1, int start, int length, String JavaDoc s2) {
1055        if (s1 == null) {
1056            return s2;
1057        }
1058        if (s2 == null) {
1059            return s1;
1060        }
1061        int len1 = s1.length();
1062        int len2 = s2.length();
1063        start--;
1064        if (start < 0 || length <= 0 || len2 == 0 || start > len1) {
1065            return s1;
1066        }
1067        if (start + length > len1) {
1068            length = len1 - start;
1069        }
1070        return s1.substring(0, start) + s2 + s1.substring(start + length);
1071    }
1072
1073    private static String JavaDoc hexToRaw(String JavaDoc s) throws SQLException JavaDoc {
1074        // TODO function hextoraw compatibility with oracle
1075
int len = s.length();
1076        if (len % 4 != 0) {
1077            throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, s);
1078        }
1079        StringBuffer JavaDoc buff = new StringBuffer JavaDoc(len / 4);
1080        for (int i = 0; i < len; i += 4) {
1081            try {
1082                char raw = (char) Integer.parseInt(s.substring(i, i + 4), 16);
1083                buff.append(raw);
1084            } catch(NumberFormatException JavaDoc e) {
1085                throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, s);
1086            }
1087        }
1088        return buff.toString();
1089    }
1090
1091    private static int getDifference(String JavaDoc s1, String JavaDoc s2) {
1092        // TODO function difference: compatibility with SQL Server and HSQLDB
1093
s1 = getSoundex(s1);
1094        s2 = getSoundex(s2);
1095        int e = 0;
1096        for (int i = 0; i < 4; i++) {
1097            if (s1.charAt(i) == s2.charAt(i)) {
1098                e++;
1099            }
1100        }
1101        return e;
1102    }
1103
1104    private double roundmagic(double d) {
1105        if ((d < 0.0000000000001) && (d > -0.0000000000001)) {
1106            return 0.0;
1107        }
1108        if ((d > 1000000000000.) || (d < -1000000000000.)) {
1109            return d;
1110        }
1111        StringBuffer JavaDoc s = new StringBuffer JavaDoc();
1112        s.append(d);
1113        if(s.toString().indexOf("E") >= 0) {
1114            return d;
1115        }
1116        int len = s.length();
1117        if (len < 16) {
1118            return d;
1119        }
1120        if(s.toString().indexOf(".") > len-3) {
1121            return d;
1122        }
1123        s.delete(len-2, len);
1124        len -= 2;
1125        char c1 = s.charAt(len - 2);
1126        char c2 = s.charAt(len - 3);
1127        char c3 = s.charAt(len - 4);
1128        if ((c1 == '0') && (c2 == '0') && (c3 == '0')) {
1129            s.setCharAt(len - 1, '0');
1130        } else if ((c1 == '9') && (c2 == '9') && (c3 == '9')) {
1131            s.setCharAt(len - 1, '9');
1132            s.append('9');
1133            s.append('9');
1134            s.append('9');
1135        }
1136        return Double.valueOf(s.toString()).doubleValue();
1137    }
1138
1139    private static String JavaDoc getSoundex(String JavaDoc s) {
1140        int len = s.length();
1141        char[] chars = new char[] { '0', '0', '0', '0' };
1142        char lastdigit = '0';
1143        for (int i = 0, j = 0; i < len && j < 4; i++) {
1144            char c = s.charAt(i);
1145            char newdigit = c > SOUNDEX_INDEX.length ? 0 : SOUNDEX_INDEX[c];
1146            if(newdigit != 0) {
1147                if (j == 0) {
1148                    chars[j++] = c;
1149                    lastdigit = newdigit;
1150                } else if (newdigit <= '6') {
1151                    if (newdigit != lastdigit) {
1152                        chars[j++] = newdigit;
1153                        lastdigit = newdigit;
1154                    }
1155                } else if (newdigit == '7') {
1156                    lastdigit = newdigit;
1157                }
1158            }
1159        }
1160        return new String JavaDoc(chars);
1161    }
1162
1163    public int getType() {
1164        return dataType;
1165    }
1166
1167    public void mapColumns(ColumnResolver resolver, int level) throws SQLException JavaDoc {
1168        for (int i = 0; i < args.length; i++) {
1169            args[i].mapColumns(resolver, level);
1170        }
1171    }
1172
1173    public void doneWithParameters() throws SQLException JavaDoc {
1174        if(info.parameterCount == VARARGS) {
1175            int len = varargs.size();
1176            int min=0, max=Integer.MAX_VALUE;
1177            switch (info.type) {
1178            case COALESCE:
1179                min = 1;
1180                break;
1181            case NOW:
1182            case CURRENT_TIMESTAMP:
1183            case RAND:
1184                max = 1;
1185                break;
1186            case COMPRESS:
1187            case LTRIM:
1188            case RTRIM:
1189            case TRIM:
1190                max = 2;
1191                break;
1192            case REPLACE:
1193            case LOCATE:
1194            case INSTR:
1195            case SUBSTR:
1196            case SUBSTRING:
1197                min = 2;
1198                max = 3;
1199                break;
1200            case CASE:
1201            case CONCAT:
1202                min = 2;
1203                break;
1204            case CSVREAD:
1205                min = 1;
1206                break;
1207            case CSVWRITE:
1208                min = 2;
1209                break;
1210            case XMLNODE:
1211                min = 1;
1212                max = 3;
1213                break;
1214            case FORMATDATETIME:
1215            case PARSEDATETIME:
1216                min = 2;
1217                max = 4;
1218                break;
1219            case CURRVAL:
1220            case NEXTVAL:
1221                min = 1;
1222                max = 2;
1223                break;
1224            default:
1225                throw Message.getInternalError("type="+info.type);
1226            }
1227            boolean ok = (len >= min) && (len <= max);
1228            if(!ok) {
1229                throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, min + ".." + max);
1230            }
1231            args = new Expression[len];
1232            varargs.toArray(args);
1233            varargs = null;
1234        } else {
1235            int len = args.length;
1236            if(len>0 && args[len-1] == null) {
1237                throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, ""+len);
1238            }
1239        }
1240    }
1241
1242    public void setDataType(int dataType, long precision, int scale) {
1243        this.dataType = dataType;
1244        this.precision = precision;
1245        this.scale = scale;
1246    }
1247
1248    public void setDataType(Column col) {
1249        dataType = col.getType();
1250        precision = col.getPrecision();
1251        scale = col.getScale();
1252    }
1253
1254    public Expression optimize(Session session) throws SQLException JavaDoc {
1255        boolean allConst = info.isDeterministic;
1256        for(int i=0; i<args.length; i++) {
1257            Expression e = args[i].optimize(session);
1258            args[i] = e;
1259            if(!e.isConstant()) {
1260                allConst = false;
1261            }
1262        }
1263        Expression p0 = args.length < 1 ? null : args[0];
1264        switch (info.type) {
1265        case COALESCE: {
1266            dataType = Value.STRING;
1267            scale = 0;
1268            precision = 0;
1269            for(int i=0; i<args.length; i++) {
1270                Expression e = args[i];
1271                if(e != ValueExpression.NULL) {
1272                    dataType = e.getType();
1273                    scale = e.getScale();
1274                    precision = e.getPrecision();
1275                    break;
1276                }
1277            }
1278            break;
1279        }
1280        case CASEWHEN:
1281            dataType = Value.getHigherOrder(args[1].getType(), args[2].getType());
1282            precision = Math.max(args[1].getPrecision(), args[2].getPrecision());
1283            scale = Math.max(args[1].getScale(), args[2].getScale());
1284            break;
1285        case CAST:
1286        case CONVERT:
1287            // data type, precision and scale is already set
1288
break;
1289        case ABS:
1290        case FLOOR:
1291        case RADIANS:
1292        case ROUND:
1293        case TRUNCATE:
1294        case POWER:
1295            dataType = p0.getType();
1296            scale = p0.getScale();
1297            precision = p0.getPrecision();
1298            break;
1299        default:
1300            dataType = info.dataType;
1301            scale = 0;
1302            precision = 0;
1303        }
1304        if(allConst) {
1305            return ValueExpression.get(getValue(session));
1306        }
1307        return this;
1308    }
1309
1310    public void setEvaluatable(TableFilter tableFilter, boolean b) {
1311        for (int i = 0; i < args.length; i++) {
1312            Expression e = args[i];
1313            if (e != null) {
1314                e.setEvaluatable(tableFilter, b);
1315            }
1316        }
1317    }
1318
1319    public int getScale() {
1320        return scale;
1321    }
1322
1323    public long getPrecision() {
1324        return precision;
1325    }
1326
1327    public String JavaDoc getSQL() {
1328        // TODO function: getSQL for some functions is not correct
1329
StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
1330        buff.append(info.name);
1331        buff.append('(');
1332        switch(info.type) {
1333        case CAST:
1334        case CONVERT: {
1335            buff.append(StringUtils.unEnclose(args[0].getSQL()));
1336            buff.append(" AS ");
1337            buff.append(new Column(null, dataType, precision, scale).getCreateSQL());
1338            break;
1339        }
1340        case EXTRACT: {
1341            ValueString v = (ValueString)((ValueExpression)args[0]).getValue(null);
1342            buff.append(v.getString());
1343            buff.append(" FROM ");
1344            buff.append(StringUtils.unEnclose(args[1].getSQL()));
1345            break;
1346        }
1347        default: {
1348            for (int i = 0; i < args.length; i++) {
1349                if (i > 0) {
1350                    buff.append(", ");
1351                }
1352                Expression e = args[i];
1353                buff.append(StringUtils.unEnclose(e.getSQL()));
1354            }
1355        }
1356        }
1357        buff.append(')');
1358        return buff.toString();
1359    }
1360
1361    public void updateAggregate(Session session) throws SQLException JavaDoc {
1362        for (int i = 0; i < args.length; i++) {
1363            Expression e = args[i];
1364            if (e != null) {
1365                e.updateAggregate(session);
1366            }
1367        }
1368    }
1369
1370    public int getFunctionType() {
1371        return info.type;
1372    }
1373
1374    public String JavaDoc getName() {
1375        return info.name;
1376    }
1377
1378    public int getParameterCount() {
1379        return args.length;
1380    }
1381
1382    public ValueResultSet getValueForColumnList(Session session, Expression[] args) throws SQLException JavaDoc {
1383        if(info.type == CSVREAD) {
1384            String JavaDoc fileName = args[0].getValue(session).getString();
1385            if(fileName == null) {
1386                throw Message.getSQLException(Message.PARAMETER_NOT_SET_1, "fileName");
1387            }
1388            String JavaDoc columnList = args.length < 2 ? null : args[1].getValue(session).getString();
1389            String JavaDoc[] columns = StringUtils.arraySplit(columnList, ',', true);
1390            String JavaDoc charset = args.length < 3 ? null : args[2].getValue(session).getString();
1391            ResultSet JavaDoc rs = Csv.getInstance().read(fileName, columns, charset);
1392            ValueResultSet vr = ValueResultSet.getCopy(rs, 0);
1393            return vr;
1394        }
1395        return (ValueResultSet)getValueWithArgs(session, args);
1396    }
1397
1398    public Expression[] getArgs() {
1399        return args;
1400    }
1401
1402    public boolean isEverything(ExpressionVisitor visitor) {
1403        if(visitor.type == ExpressionVisitor.DETERMINISTIC && !info.isDeterministic) {
1404            return false;
1405        }
1406        for (int i = 0; i < args.length; i++) {
1407            Expression e = args[i];
1408            if (e != null && !e.isEverything(visitor)) {
1409                return false;
1410            }
1411        }
1412        return true;
1413    }
1414    
1415    public int getCost() {
1416        int cost = 3;
1417        for(int i=0; i<args.length; i++) {
1418            cost += args[i].getCost();
1419        }
1420        return cost;
1421    }
1422
1423}
1424
Popular Tags