EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.expression]

COVERAGE SUMMARY FOR SOURCE FILE [Function.java]

nameclass, %method, %block, %line, %
Function.java100% (1/1)97%  (59/61)94%  (5970/6369)93%  (1290.1/1383)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Function100% (1/1)97%  (59/61)94%  (5970/6369)93%  (1290.1/1383)
cancelStatement (Session, int): boolean 0%   (0/1)0%   (0/41)0%   (0/10)
getDiskSpaceUsed (Session, Value): long 0%   (0/1)0%   (0/15)0%   (0/4)
setParameter (int, Expression): void 100% (1/1)45%  (20/44)83%  (5/6)
doneWithParameters (): void 100% (1/1)65%  (40/62)91%  (10/11)
getDatePart (String): int 100% (1/1)73%  (11/15)75%  (3/4)
isEverything (ExpressionVisitor): boolean 100% (1/1)76%  (34/45)86%  (6/7)
calculatePrecisionAndDisplaySize (): void 100% (1/1)79%  (132/168)73%  (27/37)
getDisplaySize (): int 100% (1/1)80%  (8/10)67%  (2/3)
getHash (String, byte [], int): byte [] 100% (1/1)81%  (17/21)80%  (4/5)
hexToRaw (String): String 100% (1/1)81%  (39/48)73%  (8/11)
getValueForColumnList (Session, Expression []): ValueResultSet 100% (1/1)86%  (129/150)84%  (22.6/27)
roundMagic (double): double 100% (1/1)87%  (109/126)88%  (22.8/26)
checkParameterCount (int): void 100% (1/1)88%  (87/99)97%  (32/33)
insert (String, int, int, String): String 100% (1/1)89%  (47/53)83%  (10/12)
replace (String, String, String): String 100% (1/1)93%  (52/56)87%  (13/15)
getSimpleValue (Session, Value, Expression [], Value []): Value 100% (1/1)94%  (1106/1177)91%  (274/300)
getValueWithArgs (Session, Expression []): Value 100% (1/1)94%  (1191/1262)94%  (226.2/241)
datediff (String, Timestamp, Timestamp): long 100% (1/1)94%  (170/180)97%  (29/30)
getSequence (Session, Value, Value): Sequence 100% (1/1)95%  (72/76)96%  (24/25)
setCsvDelimiterEscape (Csv, String, String, String): void 100% (1/1)95%  (42/44)99%  (11.8/12)
translate (String, String, String): String 100% (1/1)97%  (71/73)99%  (16.8/17)
getSoundex (String): String 100% (1/1)98%  (84/86)99%  (16.9/17)
optimize (Session): Expression 100% (1/1)98%  (555/564)97%  (132/136)
<static initializer> 100% (1/1)100% (1137/1137)100% (221/221)
Function (Database, FunctionInfo): void 100% (1/1)100% (25/25)100% (8/8)
addFunction (String, int, int, int): void 100% (1/1)100% (9/9)100% (2/2)
addFunction (String, int, int, int, boolean, boolean, boolean): void 100% (1/1)100% (31/31)100% (10/10)
addFunctionNotDeterministic (String, int, int, int): void 100% (1/1)100% (9/9)100% (2/2)
addFunctionWithNull (String, int, int, int): void 100% (1/1)100% (9/9)100% (2/2)
dateadd (String, int, Timestamp): Timestamp 100% (1/1)100% (34/34)100% (9/9)
decrypt (String, byte [], byte []): byte [] 100% (1/1)100% (23/23)100% (6/6)
encrypt (String, byte [], byte []): byte [] 100% (1/1)100% (23/23)100% (6/6)
getArgs (): Expression [] 100% (1/1)100% (3/3)100% (1/1)
getCost (): int 100% (1/1)100% (28/28)100% (5/5)
getDifference (String, String): int 100% (1/1)100% (25/25)100% (7/7)
getFunction (Database, String): Function 100% (1/1)100% (30/30)100% (8/8)
getFunctionInfo (String): FunctionInfo 100% (1/1)100% (5/5)100% (1/1)
getFunctionType (): int 100% (1/1)100% (4/4)100% (1/1)
getName (): String 100% (1/1)100% (4/4)100% (1/1)
getNullOrValue (Session, Expression [], Value [], int): Value 100% (1/1)100% (30/30)100% (9/9)
getPaddedArrayCopy (byte [], int): byte [] 100% (1/1)100% (17/17)100% (4/4)
getPrecision (): long 100% (1/1)100% (10/10)100% (3/3)
getSQL (): String 100% (1/1)100% (198/198)100% (23/23)
getScale (): int 100% (1/1)100% (3/3)100% (1/1)
getType (): int 100% (1/1)100% (3/3)100% (1/1)
getValue (Session): Value 100% (1/1)100% (6/6)100% (1/1)
isBufferResultSetToLocalTemp (): boolean 100% (1/1)100% (4/4)100% (1/1)
isDatePart (String): boolean 100% (1/1)100% (12/12)100% (2/2)
isDeterministic (): boolean 100% (1/1)100% (4/4)100% (1/1)
left (String, int): String 100% (1/1)100% (17/17)100% (5/5)
length (Value): long 100% (1/1)100% (11/11)100% (3/3)
locate (String, String, int): int 100% (1/1)100% (29/29)100% (5/5)
log10 (double): double 100% (1/1)100% (7/7)100% (1/1)
mapColumns (ColumnResolver, int): void 100% (1/1)100% (24/24)100% (4/4)
rawToHex (String): String 100% (1/1)100% (43/43)100% (8/8)
repeat (String, int): String 100% (1/1)100% (19/19)100% (4/4)
right (String, int): String 100% (1/1)100% (19/19)100% (5/5)
setDataType (Column): void 100% (1/1)100% (17/17)100% (5/5)
setEvaluatable (TableFilter, boolean): void 100% (1/1)100% (24/24)100% (4/4)
substring (String, int, int): String 100% (1/1)100% (35/35)100% (10/10)
updateAggregate (Session): void 100% (1/1)100% (23/23)100% (4/4)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.expression;
7 
8import static org.h2.util.ToChar.toChar;
9 
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.InputStreamReader;
13import java.io.Reader;
14import java.sql.Connection;
15import java.sql.ResultSet;
16import java.sql.SQLException;
17import java.sql.Timestamp;
18import java.text.SimpleDateFormat;
19import java.util.ArrayList;
20import java.util.Calendar;
21import java.util.HashMap;
22import java.util.Locale;
23import java.util.TimeZone;
24import java.util.regex.PatternSyntaxException;
25 
26import org.h2.api.ErrorCode;
27import org.h2.command.Command;
28import org.h2.command.Parser;
29import org.h2.engine.Constants;
30import org.h2.engine.Database;
31import org.h2.engine.Mode;
32import org.h2.engine.Session;
33import org.h2.message.DbException;
34import org.h2.mvstore.DataUtils;
35import org.h2.schema.Schema;
36import org.h2.schema.Sequence;
37import org.h2.security.BlockCipher;
38import org.h2.security.CipherFactory;
39import org.h2.security.SHA256;
40import org.h2.store.fs.FileUtils;
41import org.h2.table.Column;
42import org.h2.table.ColumnResolver;
43import org.h2.table.LinkSchema;
44import org.h2.table.Table;
45import org.h2.table.TableFilter;
46import org.h2.tools.CompressTool;
47import org.h2.tools.Csv;
48import org.h2.util.AutoCloseInputStream;
49import org.h2.util.DateTimeUtils;
50import org.h2.util.JdbcUtils;
51import org.h2.util.MathUtils;
52import org.h2.util.New;
53import org.h2.util.StatementBuilder;
54import org.h2.util.StringUtils;
55import org.h2.util.Utils;
56import org.h2.value.DataType;
57import org.h2.value.Value;
58import org.h2.value.ValueArray;
59import org.h2.value.ValueBoolean;
60import org.h2.value.ValueBytes;
61import org.h2.value.ValueDate;
62import org.h2.value.ValueDouble;
63import org.h2.value.ValueInt;
64import org.h2.value.ValueLong;
65import org.h2.value.ValueNull;
66import org.h2.value.ValueResultSet;
67import org.h2.value.ValueString;
68import org.h2.value.ValueTime;
69import org.h2.value.ValueTimestamp;
70import org.h2.value.ValueUuid;
71 
72/**
73 * This class implements most built-in functions of this database.
74 */
75public class Function extends Expression implements FunctionCall {
76    public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3, ATAN2 = 4,
77            BITAND = 5, BITOR = 6, BITXOR = 7, CEILING = 8, COS = 9, COT = 10,
78            DEGREES = 11, EXP = 12, FLOOR = 13, LOG = 14, LOG10 = 15, MOD = 16,
79            PI = 17, POWER = 18, RADIANS = 19, RAND = 20, ROUND = 21,
80            ROUNDMAGIC = 22, SIGN = 23, SIN = 24, SQRT = 25, TAN = 26,
81            TRUNCATE = 27, SECURE_RAND = 28, HASH = 29, ENCRYPT = 30,
82            DECRYPT = 31, COMPRESS = 32, EXPAND = 33, ZERO = 34,
83            RANDOM_UUID = 35, COSH = 36, SINH = 37, TANH = 38, LN = 39;
84 
85    public static final int ASCII = 50, BIT_LENGTH = 51, CHAR = 52,
86            CHAR_LENGTH = 53, CONCAT = 54, DIFFERENCE = 55, HEXTORAW = 56,
87            INSERT = 57, INSTR = 58, LCASE = 59, LEFT = 60, LENGTH = 61,
88            LOCATE = 62, LTRIM = 63, OCTET_LENGTH = 64, RAWTOHEX = 65,
89            REPEAT = 66, REPLACE = 67, RIGHT = 68, RTRIM = 69, SOUNDEX = 70,
90            SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74, LOWER = 75,
91            UPPER = 76, POSITION = 77, TRIM = 78, STRINGENCODE = 79,
92            STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82,
93            XMLATTR = 83, XMLNODE = 84, XMLCOMMENT = 85, XMLCDATA = 86,
94            XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90,
95            LPAD = 91, CONCAT_WS = 92, TO_CHAR = 93, TRANSLATE = 94;
96 
97    public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102,
98            DATE_DIFF = 103, DAY_NAME = 104, DAY_OF_MONTH = 105,
99            DAY_OF_WEEK = 106, DAY_OF_YEAR = 107, HOUR = 108, MINUTE = 109,
100            MONTH = 110, MONTH_NAME = 111, NOW = 112, QUARTER = 113,
101            SECOND = 114, WEEK = 115, YEAR = 116, CURRENT_DATE = 117,
102            CURRENT_TIME = 118, CURRENT_TIMESTAMP = 119, EXTRACT = 120,
103            FORMATDATETIME = 121, PARSEDATETIME = 122, ISO_YEAR = 123,
104            ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125;
105 
106    public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
107            IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
108            READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158,
109            DISK_SPACE_USED = 159;
110 
111    public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202,
112            CAST = 203, COALESCE = 204, NULLIF = 205, CASE = 206,
113            NEXTVAL = 207, CURRVAL = 208, ARRAY_GET = 209, CSVREAD = 210,
114            CSVWRITE = 211, MEMORY_FREE = 212, MEMORY_USED = 213,
115            LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216,
116            ARRAY_LENGTH = 217, LINK_SCHEMA = 218, GREATEST = 219, LEAST = 220,
117            CANCEL_SESSION = 221, SET = 222, TABLE = 223, TABLE_DISTINCT = 224,
118            FILE_READ = 225, TRANSACTION_ID = 226, TRUNCATE_VALUE = 227,
119            NVL2 = 228, DECODE = 229, ARRAY_CONTAINS = 230;
120 
121    /**
122     * Used in MySQL-style INSERT ... ON DUPLICATE KEY UPDATE ... VALUES
123     */
124    public static final int VALUES = 250;
125 
126    /**
127     * This is called H2VERSION() and not VERSION(), because we return a fake
128     * value for VERSION() when running under the PostgreSQL ODBC driver.
129     */
130    public static final int H2VERSION = 231;
131 
132    public static final int ROW_NUMBER = 300;
133 
134    private static final int VAR_ARGS = -1;
135    private static final long PRECISION_UNKNOWN = -1;
136 
137    private static final HashMap<String, FunctionInfo> FUNCTIONS = New.hashMap();
138    private static final HashMap<String, Integer> DATE_PART = New.hashMap();
139    private static final char[] SOUNDEX_INDEX = new char[128];
140 
141    protected Expression[] args;
142 
143    private final FunctionInfo info;
144    private ArrayList<Expression> varArgs;
145    private int dataType, scale;
146    private long precision = PRECISION_UNKNOWN;
147    private int displaySize;
148    private final Database database;
149 
150    static {
151        // DATE_PART
152        DATE_PART.put("SQL_TSI_YEAR", Calendar.YEAR);
153        DATE_PART.put("YEAR", Calendar.YEAR);
154        DATE_PART.put("YYYY", Calendar.YEAR);
155        DATE_PART.put("YY", Calendar.YEAR);
156        DATE_PART.put("SQL_TSI_MONTH", Calendar.MONTH);
157        DATE_PART.put("MONTH", Calendar.MONTH);
158        DATE_PART.put("MM", Calendar.MONTH);
159        DATE_PART.put("M", Calendar.MONTH);
160        DATE_PART.put("SQL_TSI_WEEK", Calendar.WEEK_OF_YEAR);
161        DATE_PART.put("WW", Calendar.WEEK_OF_YEAR);
162        DATE_PART.put("WK", Calendar.WEEK_OF_YEAR);
163        DATE_PART.put("WEEK", Calendar.WEEK_OF_YEAR);
164        DATE_PART.put("DAY", Calendar.DAY_OF_MONTH);
165        DATE_PART.put("DD", Calendar.DAY_OF_MONTH);
166        DATE_PART.put("D", Calendar.DAY_OF_MONTH);
167        DATE_PART.put("SQL_TSI_DAY", Calendar.DAY_OF_MONTH);
168        DATE_PART.put("DAYOFYEAR", Calendar.DAY_OF_YEAR);
169        DATE_PART.put("DAY_OF_YEAR", Calendar.DAY_OF_YEAR);
170        DATE_PART.put("DY", Calendar.DAY_OF_YEAR);
171        DATE_PART.put("DOY", Calendar.DAY_OF_YEAR);
172        DATE_PART.put("SQL_TSI_HOUR", Calendar.HOUR_OF_DAY);
173        DATE_PART.put("HOUR", Calendar.HOUR_OF_DAY);
174        DATE_PART.put("HH", Calendar.HOUR_OF_DAY);
175        DATE_PART.put("SQL_TSI_MINUTE", Calendar.MINUTE);
176        DATE_PART.put("MINUTE", Calendar.MINUTE);
177        DATE_PART.put("MI", Calendar.MINUTE);
178        DATE_PART.put("N", Calendar.MINUTE);
179        DATE_PART.put("SQL_TSI_SECOND", Calendar.SECOND);
180        DATE_PART.put("SECOND", Calendar.SECOND);
181        DATE_PART.put("SS", Calendar.SECOND);
182        DATE_PART.put("S", Calendar.SECOND);
183        DATE_PART.put("MILLISECOND", Calendar.MILLISECOND);
184        DATE_PART.put("MS", Calendar.MILLISECOND);
185 
186        // SOUNDEX_INDEX
187        String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
188        char number = 0;
189        for (int i = 0, length = index.length(); i < length; i++) {
190            char c = index.charAt(i);
191            if (c < '9') {
192                number = c;
193            } else {
194                SOUNDEX_INDEX[c] = number;
195                SOUNDEX_INDEX[Character.toLowerCase(c)] = number;
196            }
197        }
198 
199        // FUNCTIONS
200        addFunction("ABS", ABS, 1, Value.NULL);
201        addFunction("ACOS", ACOS, 1, Value.DOUBLE);
202        addFunction("ASIN", ASIN, 1, Value.DOUBLE);
203        addFunction("ATAN", ATAN, 1, Value.DOUBLE);
204        addFunction("ATAN2", ATAN2, 2, Value.DOUBLE);
205        addFunction("BITAND", BITAND, 2, Value.LONG);
206        addFunction("BITOR", BITOR, 2, Value.LONG);
207        addFunction("BITXOR", BITXOR, 2, Value.LONG);
208        addFunction("CEILING", CEILING, 1, Value.DOUBLE);
209        addFunction("CEIL", CEILING, 1, Value.DOUBLE);
210        addFunction("COS", COS, 1, Value.DOUBLE);
211        addFunction("COSH", COSH, 1, Value.DOUBLE);
212        addFunction("COT", COT, 1, Value.DOUBLE);
213        addFunction("DEGREES", DEGREES, 1, Value.DOUBLE);
214        addFunction("EXP", EXP, 1, Value.DOUBLE);
215        addFunction("FLOOR", FLOOR, 1, Value.DOUBLE);
216        addFunction("LOG", LOG, 1, Value.DOUBLE);
217        addFunction("LN", LN, 1, Value.DOUBLE);
218        addFunction("LOG10", LOG10, 1, Value.DOUBLE);
219        addFunction("MOD", MOD, 2, Value.LONG);
220        addFunction("PI", PI, 0, Value.DOUBLE);
221        addFunction("POWER", POWER, 2, Value.DOUBLE);
222        addFunction("RADIANS", RADIANS, 1, Value.DOUBLE);
223        // RAND without argument: get the next value
224        // RAND with one argument: seed the random generator
225        addFunctionNotDeterministic("RAND", RAND, VAR_ARGS, Value.DOUBLE);
226        addFunctionNotDeterministic("RANDOM", RAND, VAR_ARGS, Value.DOUBLE);
227        addFunction("ROUND", ROUND, VAR_ARGS, Value.DOUBLE);
228        addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE);
229        addFunction("SIGN", SIGN, 1, Value.INT);
230        addFunction("SIN", SIN, 1, Value.DOUBLE);
231        addFunction("SINH", SINH, 1, Value.DOUBLE);
232        addFunction("SQRT", SQRT, 1, Value.DOUBLE);
233        addFunction("TAN", TAN, 1, Value.DOUBLE);
234        addFunction("TANH", TANH, 1, Value.DOUBLE);
235        addFunction("TRUNCATE", TRUNCATE, VAR_ARGS, Value.NULL);
236        // same as TRUNCATE
237        addFunction("TRUNC", TRUNCATE, VAR_ARGS, Value.NULL);
238        addFunction("HASH", HASH, 3, Value.BYTES);
239        addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES);
240        addFunction("DECRYPT", DECRYPT, 3, Value.BYTES);
241        addFunctionNotDeterministic("SECURE_RAND", SECURE_RAND, 1, Value.BYTES);
242        addFunction("COMPRESS", COMPRESS, VAR_ARGS, Value.BYTES);
243        addFunction("EXPAND", EXPAND, 1, Value.BYTES);
244        addFunction("ZERO", ZERO, 0, Value.INT);
245        addFunctionNotDeterministic("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID);
246        addFunctionNotDeterministic("SYS_GUID", RANDOM_UUID, 0, Value.UUID);
247        // string
248        addFunction("ASCII", ASCII, 1, Value.INT);
249        addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.LONG);
250        addFunction("CHAR", CHAR, 1, Value.STRING);
251        addFunction("CHR", CHAR, 1, Value.STRING);
252        addFunction("CHAR_LENGTH", CHAR_LENGTH, 1, Value.INT);
253        // same as CHAR_LENGTH
254        addFunction("CHARACTER_LENGTH", CHAR_LENGTH, 1, Value.INT);
255        addFunctionWithNull("CONCAT", CONCAT, VAR_ARGS, Value.STRING);
256        addFunctionWithNull("CONCAT_WS", CONCAT_WS, VAR_ARGS, Value.STRING);
257        addFunction("DIFFERENCE", DIFFERENCE, 2, Value.INT);
258        addFunction("HEXTORAW", HEXTORAW, 1, Value.STRING);
259        addFunctionWithNull("INSERT", INSERT, 4, Value.STRING);
260        addFunction("LCASE", LCASE, 1, Value.STRING);
261        addFunction("LEFT", LEFT, 2, Value.STRING);
262        addFunction("LENGTH", LENGTH, 1, Value.LONG);
263        // 2 or 3 arguments
264        addFunction("LOCATE", LOCATE, VAR_ARGS, Value.INT);
265        // alias for MSSQLServer
266        addFunction("CHARINDEX", LOCATE, VAR_ARGS, Value.INT);
267        // same as LOCATE with 2 arguments
268        addFunction("POSITION", LOCATE, 2, Value.INT);
269        addFunction("INSTR", INSTR, VAR_ARGS, Value.INT);
270        addFunction("LTRIM", LTRIM, VAR_ARGS, Value.STRING);
271        addFunction("OCTET_LENGTH", OCTET_LENGTH, 1, Value.LONG);
272        addFunction("RAWTOHEX", RAWTOHEX, 1, Value.STRING);
273        addFunction("REPEAT", REPEAT, 2, Value.STRING);
274        addFunction("REPLACE", REPLACE, VAR_ARGS, Value.STRING);
275        addFunction("RIGHT", RIGHT, 2, Value.STRING);
276        addFunction("RTRIM", RTRIM, VAR_ARGS, Value.STRING);
277        addFunction("SOUNDEX", SOUNDEX, 1, Value.STRING);
278        addFunction("SPACE", SPACE, 1, Value.STRING);
279        addFunction("SUBSTR", SUBSTR, VAR_ARGS, Value.STRING);
280        addFunction("SUBSTRING", SUBSTRING, VAR_ARGS, Value.STRING);
281        addFunction("UCASE", UCASE, 1, Value.STRING);
282        addFunction("LOWER", LOWER, 1, Value.STRING);
283        addFunction("UPPER", UPPER, 1, Value.STRING);
284        addFunction("POSITION", POSITION, 2, Value.INT);
285        addFunction("TRIM", TRIM, VAR_ARGS, Value.STRING);
286        addFunction("STRINGENCODE", STRINGENCODE, 1, Value.STRING);
287        addFunction("STRINGDECODE", STRINGDECODE, 1, Value.STRING);
288        addFunction("STRINGTOUTF8", STRINGTOUTF8, 1, Value.BYTES);
289        addFunction("UTF8TOSTRING", UTF8TOSTRING, 1, Value.STRING);
290        addFunction("XMLATTR", XMLATTR, 2, Value.STRING);
291        addFunctionWithNull("XMLNODE", XMLNODE, VAR_ARGS, Value.STRING);
292        addFunction("XMLCOMMENT", XMLCOMMENT, 1, Value.STRING);
293        addFunction("XMLCDATA", XMLCDATA, 1, Value.STRING);
294        addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING);
295        addFunction("XMLTEXT", XMLTEXT, VAR_ARGS, Value.STRING);
296        addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING);
297        addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING);
298        addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
299        addFunction("TO_CHAR", TO_CHAR, VAR_ARGS, Value.STRING);
300        addFunction("TRANSLATE", TRANSLATE, 3, Value.STRING);
301 
302        // date
303        addFunctionNotDeterministic("CURRENT_DATE", CURRENT_DATE,
304                0, Value.DATE);
305        addFunctionNotDeterministic("CURDATE", CURDATE,
306                0, Value.DATE);
307        // alias for MSSQLServer
308        addFunctionNotDeterministic("GETDATE", CURDATE,
309                0, Value.DATE);
310        addFunctionNotDeterministic("CURRENT_TIME", CURRENT_TIME,
311                0, Value.TIME);
312        addFunctionNotDeterministic("CURTIME", CURTIME,
313                0, Value.TIME);
314        addFunctionNotDeterministic("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP,
315                VAR_ARGS, Value.TIMESTAMP);
316        addFunctionNotDeterministic("NOW", NOW,
317                VAR_ARGS, Value.TIMESTAMP);
318        addFunction("DATEADD", DATE_ADD,
319                3, Value.TIMESTAMP);
320        addFunction("TIMESTAMPADD", DATE_ADD,
321                3, Value.LONG);
322        addFunction("DATEDIFF", DATE_DIFF,
323                3, Value.LONG);
324        addFunction("TIMESTAMPDIFF", DATE_DIFF,
325                3, Value.LONG);
326        addFunction("DAYNAME", DAY_NAME,
327                1, Value.STRING);
328        addFunction("DAYNAME", DAY_NAME,
329                1, Value.STRING);
330        addFunction("DAY", DAY_OF_MONTH,
331                1, Value.INT);
332        addFunction("DAY_OF_MONTH", DAY_OF_MONTH,
333                1, Value.INT);
334        addFunction("DAY_OF_WEEK", DAY_OF_WEEK,
335                1, Value.INT);
336        addFunction("DAY_OF_YEAR", DAY_OF_YEAR,
337                1, Value.INT);
338        addFunction("DAYOFMONTH", DAY_OF_MONTH,
339                1, Value.INT);
340        addFunction("DAYOFWEEK", DAY_OF_WEEK,
341                1, Value.INT);
342        addFunction("DAYOFYEAR", DAY_OF_YEAR,
343                1, Value.INT);
344        addFunction("HOUR", HOUR,
345                1, Value.INT);
346        addFunction("MINUTE", MINUTE,
347                1, Value.INT);
348        addFunction("MONTH", MONTH,
349                1, Value.INT);
350        addFunction("MONTHNAME", MONTH_NAME,
351                1, Value.STRING);
352        addFunction("QUARTER", QUARTER,
353                1, Value.INT);
354        addFunction("SECOND", SECOND,
355                1, Value.INT);
356        addFunction("WEEK", WEEK,
357                1, Value.INT);
358        addFunction("YEAR", YEAR,
359                1, Value.INT);
360        addFunction("EXTRACT", EXTRACT,
361                2, Value.INT);
362        addFunctionWithNull("FORMATDATETIME", FORMATDATETIME,
363                VAR_ARGS, Value.STRING);
364        addFunctionWithNull("PARSEDATETIME", PARSEDATETIME,
365                VAR_ARGS, Value.TIMESTAMP);
366        addFunction("ISO_YEAR", ISO_YEAR,
367                1, Value.INT);
368        addFunction("ISO_WEEK", ISO_WEEK,
369                1, Value.INT);
370        addFunction("ISO_DAY_OF_WEEK", ISO_DAY_OF_WEEK,
371                1, Value.INT);
372        // system
373        addFunctionNotDeterministic("DATABASE", DATABASE,
374                0, Value.STRING);
375        addFunctionNotDeterministic("USER", USER,
376                0, Value.STRING);
377        addFunctionNotDeterministic("CURRENT_USER", CURRENT_USER,
378                0, Value.STRING);
379        addFunctionNotDeterministic("IDENTITY", IDENTITY,
380                0, Value.LONG);
381        addFunctionNotDeterministic("SCOPE_IDENTITY", SCOPE_IDENTITY,
382                0, Value.LONG);
383        addFunctionNotDeterministic("IDENTITY_VAL_LOCAL", IDENTITY,
384                0, Value.LONG);
385        addFunctionNotDeterministic("LAST_INSERT_ID", IDENTITY,
386                0, Value.LONG);
387        addFunctionNotDeterministic("LASTVAL", IDENTITY,
388                0, Value.LONG);
389        addFunctionNotDeterministic("AUTOCOMMIT", AUTOCOMMIT,
390                0, Value.BOOLEAN);
391        addFunctionNotDeterministic("READONLY", READONLY,
392                0, Value.BOOLEAN);
393        addFunction("DATABASE_PATH", DATABASE_PATH,
394                0, Value.STRING);
395        addFunctionNotDeterministic("LOCK_TIMEOUT", LOCK_TIMEOUT,
396                0, Value.INT);
397        addFunctionWithNull("IFNULL", IFNULL,
398                2, Value.NULL);
399        addFunctionWithNull("ISNULL", IFNULL,
400                2, Value.NULL);
401        addFunctionWithNull("CASEWHEN", CASEWHEN,
402                3, Value.NULL);
403        addFunctionWithNull("CONVERT", CONVERT,
404                1, Value.NULL);
405        addFunctionWithNull("CAST", CAST,
406                1, Value.NULL);
407        addFunctionWithNull("TRUNCATE_VALUE", TRUNCATE_VALUE,
408                3, Value.NULL);
409        addFunctionWithNull("COALESCE", COALESCE,
410                VAR_ARGS, Value.NULL);
411        addFunctionWithNull("NVL", COALESCE,
412                VAR_ARGS, Value.NULL);
413        addFunctionWithNull("NVL2", NVL2,
414                3, Value.NULL);
415        addFunctionWithNull("NULLIF", NULLIF,
416                2, Value.NULL);
417        addFunctionWithNull("CASE", CASE,
418                VAR_ARGS, Value.NULL);
419        addFunctionNotDeterministic("NEXTVAL", NEXTVAL,
420                VAR_ARGS, Value.LONG);
421        addFunctionNotDeterministic("CURRVAL", CURRVAL,
422                VAR_ARGS, Value.LONG);
423        addFunction("ARRAY_GET", ARRAY_GET,
424                2, Value.STRING);
425        addFunction("ARRAY_CONTAINS", ARRAY_CONTAINS,
426                2, Value.BOOLEAN, false, true, true);
427        addFunction("CSVREAD", CSVREAD,
428                VAR_ARGS, Value.RESULT_SET, false, false, false);
429        addFunction("CSVWRITE", CSVWRITE,
430                VAR_ARGS, Value.INT, false, false, true);
431        addFunctionNotDeterministic("MEMORY_FREE", MEMORY_FREE,
432                0, Value.INT);
433        addFunctionNotDeterministic("MEMORY_USED", MEMORY_USED,
434                0, Value.INT);
435        addFunctionNotDeterministic("LOCK_MODE", LOCK_MODE,
436                0, Value.INT);
437        addFunctionNotDeterministic("SCHEMA", SCHEMA,
438                0, Value.STRING);
439        addFunctionNotDeterministic("SESSION_ID", SESSION_ID,
440                0, Value.INT);
441        addFunction("ARRAY_LENGTH", ARRAY_LENGTH,
442                1, Value.INT);
443        addFunctionNotDeterministic("LINK_SCHEMA", LINK_SCHEMA,
444                6, Value.RESULT_SET);
445        addFunctionWithNull("LEAST", LEAST,
446                VAR_ARGS, Value.NULL);
447        addFunctionWithNull("GREATEST", GREATEST,
448                VAR_ARGS, Value.NULL);
449        addFunctionNotDeterministic("CANCEL_SESSION", CANCEL_SESSION,
450                1, Value.BOOLEAN);
451        addFunction("SET", SET,
452                2, Value.NULL, false, false, true);
453        addFunction("FILE_READ", FILE_READ,
454                VAR_ARGS, Value.NULL, false, false, true);
455        addFunctionNotDeterministic("TRANSACTION_ID", TRANSACTION_ID,
456                0, Value.STRING);
457        addFunctionWithNull("DECODE", DECODE,
458                VAR_ARGS, Value.NULL);
459        addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED,
460                1, Value.LONG);
461        addFunction("H2VERSION", H2VERSION, 0, Value.STRING);
462 
463        // TableFunction
464        addFunctionWithNull("TABLE", TABLE,
465                VAR_ARGS, Value.RESULT_SET);
466        addFunctionWithNull("TABLE_DISTINCT", TABLE_DISTINCT,
467                VAR_ARGS, Value.RESULT_SET);
468 
469        // pseudo function
470        addFunctionWithNull("ROW_NUMBER", ROW_NUMBER, 0, Value.LONG);
471 
472        // ON DUPLICATE KEY VALUES function
473        addFunction("VALUES", VALUES, 1, Value.NULL, false, true, false);
474    }
475 
476    protected Function(Database database, FunctionInfo info) {
477        this.database = database;
478        this.info = info;
479        if (info.parameterCount == VAR_ARGS) {
480            varArgs = New.arrayList();
481        } else {
482            args = new Expression[info.parameterCount];
483        }
484    }
485 
486    private static void addFunction(String name, int type, int parameterCount,
487            int dataType, boolean nullIfParameterIsNull, boolean deterministic,
488            boolean bufferResultSetToLocalTemp) {
489        FunctionInfo info = new FunctionInfo();
490        info.name = name;
491        info.type = type;
492        info.parameterCount = parameterCount;
493        info.dataType = dataType;
494        info.nullIfParameterIsNull = nullIfParameterIsNull;
495        info.deterministic = deterministic;
496        info.bufferResultSetToLocalTemp = bufferResultSetToLocalTemp;
497        FUNCTIONS.put(name, info);
498    }
499 
500    private static void addFunctionNotDeterministic(String name, int type,
501            int parameterCount, int dataType) {
502        addFunction(name, type, parameterCount, dataType, true, false, true);
503    }
504 
505    private static void addFunction(String name, int type, int parameterCount,
506            int dataType) {
507        addFunction(name, type, parameterCount, dataType, true, true, true);
508    }
509 
510    private static void addFunctionWithNull(String name, int type,
511            int parameterCount, int dataType) {
512        addFunction(name, type, parameterCount, dataType, false, true, true);
513    }
514 
515    /**
516     * Get the function info object for this function, or null if there is no
517     * such function.
518     *
519     * @param name the function name
520     * @return the function info
521     */
522    private static FunctionInfo getFunctionInfo(String name) {
523        return FUNCTIONS.get(name);
524    }
525 
526    /**
527     * Get an instance of the given function for this database.
528     * If no function with this name is found, null is returned.
529     *
530     * @param database the database
531     * @param name the function name
532     * @return the function object or null
533     */
534    public static Function getFunction(Database database, String name) {
535        if (!database.getSettings().databaseToUpper) {
536            // if not yet converted to uppercase, do it now
537            name = StringUtils.toUpperEnglish(name);
538        }
539        FunctionInfo info = getFunctionInfo(name);
540        if (info == null) {
541            return null;
542        }
543        switch(info.type) {
544        case TABLE:
545        case TABLE_DISTINCT:
546            return new TableFunction(database, info, Long.MAX_VALUE);
547        default:
548            return new Function(database, info);
549        }
550    }
551 
552    /**
553     * Set the parameter expression at the given index.
554     *
555     * @param index the index (0, 1,...)
556     * @param param the expression
557     */
558    public void setParameter(int index, Expression param) {
559        if (varArgs != null) {
560            varArgs.add(param);
561        } else {
562            if (index >= args.length) {
563                throw DbException.get(ErrorCode.INVALID_PARAMETER_COUNT_2,
564                        info.name, "" + args.length);
565            }
566            args[index] = param;
567        }
568    }
569 
570    private static strictfp double log10(double value) {
571        return roundMagic(StrictMath.log(value) / StrictMath.log(10));
572    }
573 
574    @Override
575    public Value getValue(Session session) {
576        return getValueWithArgs(session, args);
577    }
578 
579    private Value getSimpleValue(Session session, Value v0, Expression[] args,
580            Value[] values) {
581        Value result;
582        switch (info.type) {
583        case ABS:
584            result = v0.getSignum() > 0 ? v0 : v0.negate();
585            break;
586        case ACOS:
587            result = ValueDouble.get(Math.acos(v0.getDouble()));
588            break;
589        case ASIN:
590            result = ValueDouble.get(Math.asin(v0.getDouble()));
591            break;
592        case ATAN:
593            result = ValueDouble.get(Math.atan(v0.getDouble()));
594            break;
595        case CEILING:
596            result = ValueDouble.get(Math.ceil(v0.getDouble()));
597            break;
598        case COS:
599            result = ValueDouble.get(Math.cos(v0.getDouble()));
600            break;
601        case COSH:
602            result = ValueDouble.get(Math.cosh(v0.getDouble()));
603            break;
604        case COT: {
605            double d = Math.tan(v0.getDouble());
606            if (d == 0.0) {
607                throw DbException.get(ErrorCode.DIVISION_BY_ZERO_1, getSQL());
608            }
609            result = ValueDouble.get(1. / d);
610            break;
611        }
612        case DEGREES:
613            result = ValueDouble.get(Math.toDegrees(v0.getDouble()));
614            break;
615        case EXP:
616            result = ValueDouble.get(Math.exp(v0.getDouble()));
617            break;
618        case FLOOR:
619            result = ValueDouble.get(Math.floor(v0.getDouble()));
620            break;
621        case LN:
622            result = ValueDouble.get(Math.log(v0.getDouble()));
623            break;
624        case LOG:
625            if (database.getMode().logIsLogBase10) {
626                result = ValueDouble.get(Math.log10(v0.getDouble()));
627            } else {
628                result = ValueDouble.get(Math.log(v0.getDouble()));
629            }
630            break;
631        case LOG10:
632            result = ValueDouble.get(log10(v0.getDouble()));
633            break;
634        case PI:
635            result = ValueDouble.get(Math.PI);
636            break;
637        case RADIANS:
638            result = ValueDouble.get(Math.toRadians(v0.getDouble()));
639            break;
640        case RAND: {
641            if (v0 != null) {
642                session.getRandom().setSeed(v0.getInt());
643            }
644            result = ValueDouble.get(session.getRandom().nextDouble());
645            break;
646        }
647        case ROUNDMAGIC:
648            result = ValueDouble.get(roundMagic(v0.getDouble()));
649            break;
650        case SIGN:
651            result = ValueInt.get(v0.getSignum());
652            break;
653        case SIN:
654            result = ValueDouble.get(Math.sin(v0.getDouble()));
655            break;
656        case SINH:
657            result = ValueDouble.get(Math.sinh(v0.getDouble()));
658            break;
659        case SQRT:
660            result = ValueDouble.get(Math.sqrt(v0.getDouble()));
661            break;
662        case TAN:
663            result = ValueDouble.get(Math.tan(v0.getDouble()));
664            break;
665        case TANH:
666            result = ValueDouble.get(Math.tanh(v0.getDouble()));
667            break;
668        case SECURE_RAND:
669            result = ValueBytes.getNoCopy(
670                    MathUtils.secureRandomBytes(v0.getInt()));
671            break;
672        case EXPAND:
673            result = ValueBytes.getNoCopy(
674                    CompressTool.getInstance().expand(v0.getBytesNoCopy()));
675            break;
676        case ZERO:
677            result = ValueInt.get(0);
678            break;
679        case RANDOM_UUID:
680            result = ValueUuid.getNewRandom();
681            break;
682            // string
683        case ASCII: {
684            String s = v0.getString();
685            if (s.length() == 0) {
686                result = ValueNull.INSTANCE;
687            } else {
688                result = ValueInt.get(s.charAt(0));
689            }
690            break;
691        }
692        case BIT_LENGTH:
693            result = ValueLong.get(16 * length(v0));
694            break;
695        case CHAR:
696            result = ValueString.get(String.valueOf((char) v0.getInt()),
697                    database.getMode().treatEmptyStringsAsNull);
698            break;
699        case CHAR_LENGTH:
700        case LENGTH:
701            result = ValueLong.get(length(v0));
702            break;
703        case OCTET_LENGTH:
704            result = ValueLong.get(2 * length(v0));
705            break;
706        case CONCAT_WS:
707        case CONCAT: {
708            result = ValueNull.INSTANCE;
709            int start = 0;
710            String separator = "";
711            if (info.type == CONCAT_WS) {
712                start = 1;
713                separator = getNullOrValue(session, args, values, 0).getString();
714            }
715            for (int i = start; i < args.length; i++) {
716                Value v = getNullOrValue(session, args, values, i);
717                if (v == ValueNull.INSTANCE) {
718                    continue;
719                }
720                if (result == ValueNull.INSTANCE) {
721                    result = v;
722                } else {
723                    String tmp = v.getString();
724                    if (!StringUtils.isNullOrEmpty(separator)
725                            && !StringUtils.isNullOrEmpty(tmp)) {
726                        tmp = separator.concat(tmp);
727                    }
728                    result = ValueString.get(result.getString().concat(tmp),
729                            database.getMode().treatEmptyStringsAsNull);
730                }
731            }
732            if (info.type == CONCAT_WS) {
733                if (separator != null && result == ValueNull.INSTANCE) {
734                    result = ValueString.get("",
735                            database.getMode().treatEmptyStringsAsNull);
736                }
737            }
738            break;
739        }
740        case HEXTORAW:
741            result = ValueString.get(hexToRaw(v0.getString()),
742                    database.getMode().treatEmptyStringsAsNull);
743            break;
744        case LOWER:
745        case LCASE:
746            // TODO this is locale specific, need to document or provide a way
747            // to set the locale
748            result = ValueString.get(v0.getString().toLowerCase(),
749                    database.getMode().treatEmptyStringsAsNull);
750            break;
751        case RAWTOHEX:
752            result = ValueString.get(rawToHex(v0.getString()),
753                    database.getMode().treatEmptyStringsAsNull);
754            break;
755        case SOUNDEX:
756            result = ValueString.get(getSoundex(v0.getString()),
757                    database.getMode().treatEmptyStringsAsNull);
758            break;
759        case SPACE: {
760            int len = Math.max(0, v0.getInt());
761            char[] chars = new char[len];
762            for (int i = len - 1; i >= 0; i--) {
763                chars[i] = ' ';
764            }
765            result = ValueString.get(new String(chars),
766                    database.getMode().treatEmptyStringsAsNull);
767            break;
768        }
769        case UPPER:
770        case UCASE:
771            // TODO this is locale specific, need to document or provide a way
772            // to set the locale
773            result = ValueString.get(v0.getString().toUpperCase(),
774                    database.getMode().treatEmptyStringsAsNull);
775            break;
776        case STRINGENCODE:
777            result = ValueString.get(StringUtils.javaEncode(v0.getString()),
778                    database.getMode().treatEmptyStringsAsNull);
779            break;
780        case STRINGDECODE:
781            result = ValueString.get(StringUtils.javaDecode(v0.getString()),
782                    database.getMode().treatEmptyStringsAsNull);
783            break;
784        case STRINGTOUTF8:
785            result = ValueBytes.getNoCopy(v0.getString().
786                    getBytes(Constants.UTF8));
787            break;
788        case UTF8TOSTRING:
789            result = ValueString.get(new String(v0.getBytesNoCopy(),
790                    Constants.UTF8),
791                    database.getMode().treatEmptyStringsAsNull);
792            break;
793        case XMLCOMMENT:
794            result = ValueString.get(StringUtils.xmlComment(v0.getString()),
795                    database.getMode().treatEmptyStringsAsNull);
796            break;
797        case XMLCDATA:
798            result = ValueString.get(StringUtils.xmlCData(v0.getString()),
799                    database.getMode().treatEmptyStringsAsNull);
800            break;
801        case XMLSTARTDOC:
802            result = ValueString.get(StringUtils.xmlStartDoc(),
803                    database.getMode().treatEmptyStringsAsNull);
804            break;
805        case DAY_NAME: {
806            SimpleDateFormat dayName = new SimpleDateFormat(
807                    "EEEE", Locale.ENGLISH);
808            result = ValueString.get(dayName.format(v0.getDate()),
809                    database.getMode().treatEmptyStringsAsNull);
810            break;
811        }
812        case DAY_OF_MONTH:
813            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(),
814                    Calendar.DAY_OF_MONTH));
815            break;
816        case DAY_OF_WEEK:
817            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(),
818                    Calendar.DAY_OF_WEEK));
819            break;
820        case DAY_OF_YEAR:
821            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(),
822                    Calendar.DAY_OF_YEAR));
823            break;
824        case HOUR:
825            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(),
826                    Calendar.HOUR_OF_DAY));
827            break;
828        case MINUTE:
829            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(),
830                    Calendar.MINUTE));
831            break;
832        case MONTH:
833            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(),
834                    Calendar.MONTH));
835            break;
836        case MONTH_NAME: {
837            SimpleDateFormat monthName = new SimpleDateFormat("MMMM",
838                    Locale.ENGLISH);
839            result = ValueString.get(monthName.format(v0.getDate()),
840                    database.getMode().treatEmptyStringsAsNull);
841            break;
842        }
843        case QUARTER:
844            result = ValueInt.get((DateTimeUtils.getDatePart(v0.getDate(),
845                    Calendar.MONTH) - 1) / 3 + 1);
846            break;
847        case SECOND:
848            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(),
849                    Calendar.SECOND));
850            break;
851        case WEEK:
852            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(),
853                    Calendar.WEEK_OF_YEAR));
854            break;
855        case YEAR:
856            result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(),
857                    Calendar.YEAR));
858            break;
859        case ISO_YEAR:
860            result = ValueInt.get(DateTimeUtils.getIsoYear(v0.getDate()));
861            break;
862        case ISO_WEEK:
863            result = ValueInt.get(DateTimeUtils.getIsoWeek(v0.getDate()));
864            break;
865        case ISO_DAY_OF_WEEK:
866            result = ValueInt.get(DateTimeUtils.getIsoDayOfWeek(v0.getDate()));
867            break;
868        case CURDATE:
869        case CURRENT_DATE: {
870            long now = session.getTransactionStart();
871            // need to normalize
872            result = ValueDate.fromMillis(now);
873            break;
874        }
875        case CURTIME:
876        case CURRENT_TIME: {
877            long now = session.getTransactionStart();
878            // need to normalize
879            result = ValueTime.fromMillis(now);
880            break;
881        }
882        case NOW:
883        case CURRENT_TIMESTAMP: {
884            long now = session.getTransactionStart();
885            ValueTimestamp vt = ValueTimestamp.fromMillis(now);
886            if (v0 != null) {
887                Mode mode = database.getMode();
888                vt = (ValueTimestamp) vt.convertScale(
889                        mode.convertOnlyToSmallerScale, v0.getInt());
890            }
891            result = vt;
892            break;
893        }
894        case DATABASE:
895            result = ValueString.get(database.getShortName(),
896                    database.getMode().treatEmptyStringsAsNull);
897            break;
898        case USER:
899        case CURRENT_USER:
900            result = ValueString.get(session.getUser().getName(),
901                    database.getMode().treatEmptyStringsAsNull);
902            break;
903        case IDENTITY:
904            result = session.getLastIdentity();
905            break;
906        case SCOPE_IDENTITY:
907            result = session.getLastScopeIdentity();
908            break;
909        case AUTOCOMMIT:
910            result = ValueBoolean.get(session.getAutoCommit());
911            break;
912        case READONLY:
913            result = ValueBoolean.get(database.isReadOnly());
914            break;
915        case DATABASE_PATH: {
916            String path = database.getDatabasePath();
917            result = path == null ?
918                    (Value) ValueNull.INSTANCE : ValueString.get(path,
919                    database.getMode().treatEmptyStringsAsNull);
920            break;
921        }
922        case LOCK_TIMEOUT:
923            result = ValueInt.get(session.getLockTimeout());
924            break;
925        case DISK_SPACE_USED:
926            result = ValueLong.get(getDiskSpaceUsed(session, v0));
927            break;
928        case CAST:
929        case CONVERT: {
930            v0 = v0.convertTo(dataType);
931            Mode mode = database.getMode();
932            v0 = v0.convertScale(mode.convertOnlyToSmallerScale, scale);
933            v0 = v0.convertPrecision(getPrecision(), false);
934            result = v0;
935            break;
936        }
937        case MEMORY_FREE:
938            session.getUser().checkAdmin();
939            result = ValueInt.get(Utils.getMemoryFree());
940            break;
941        case MEMORY_USED:
942            session.getUser().checkAdmin();
943            result = ValueInt.get(Utils.getMemoryUsed());
944            break;
945        case LOCK_MODE:
946            result = ValueInt.get(database.getLockMode());
947            break;
948        case SCHEMA:
949            result = ValueString.get(session.getCurrentSchemaName(),
950                    database.getMode().treatEmptyStringsAsNull);
951            break;
952        case SESSION_ID:
953            result = ValueInt.get(session.getId());
954            break;
955        case IFNULL: {
956            result = v0;
957            if (v0 == ValueNull.INSTANCE) {
958                result = getNullOrValue(session, args, values, 1);
959            }
960            break;
961        }
962        case CASEWHEN: {
963            Value v;
964            if (v0 == ValueNull.INSTANCE ||
965                    !v0.getBoolean().booleanValue()) {
966                v = getNullOrValue(session, args, values, 2);
967            } else {
968                v = getNullOrValue(session, args, values, 1);
969            }
970            result = v.convertTo(dataType);
971            break;
972        }
973        case DECODE: {
974            int index = -1;
975            for (int i = 1, len = args.length - 1; i < len; i += 2) {
976                if (database.areEqual(v0,
977                        getNullOrValue(session, args, values, i))) {
978                    index = i + 1;
979                    break;
980                }
981            }
982            if (index < 0 && args.length % 2 == 0) {
983                index = args.length - 1;
984            }
985            Value v = index < 0 ? ValueNull.INSTANCE :
986                    getNullOrValue(session, args, values, index);
987            result = v.convertTo(dataType);
988            break;
989        }
990        case NVL2: {
991            Value v;
992            if (v0 == ValueNull.INSTANCE) {
993                v = getNullOrValue(session, args, values, 2);
994            } else {
995                v = getNullOrValue(session, args, values, 1);
996            }
997            result = v.convertTo(dataType);
998            break;
999        }
1000        case COALESCE: {
1001            result = v0;
1002            for (int i = 0; i < args.length; i++) {
1003                Value v = getNullOrValue(session, args, values, i);
1004                if (!(v == ValueNull.INSTANCE)) {
1005                    result = v.convertTo(dataType);
1006                    break;
1007                }
1008            }
1009            break;
1010        }
1011        case GREATEST:
1012        case LEAST: {
1013            result = ValueNull.INSTANCE;
1014            for (int i = 0; i < args.length; i++) {
1015                Value v = getNullOrValue(session, args, values, i);
1016                if (!(v == ValueNull.INSTANCE)) {
1017                    v = v.convertTo(dataType);
1018                    if (result == ValueNull.INSTANCE) {
1019                        result = v;
1020                    } else {
1021                        int comp = database.compareTypeSave(result, v);
1022                        if (info.type == GREATEST && comp < 0) {
1023                            result = v;
1024                        } else if (info.type == LEAST && comp > 0) {
1025                            result = v;
1026                        }
1027                    }
1028                }
1029            }
1030            break;
1031        }
1032        case CASE: {
1033            Expression then = null;
1034            if (v0 == null) {
1035                // Searched CASE expression
1036                // (null, when, then)
1037                // (null, when, then, else)
1038                // (null, when, then, when, then)
1039                // (null, when, then, when, then, else)
1040                for (int i = 1, len = args.length - 1; i < len; i += 2) {
1041                    Value when = args[i].getValue(session);
1042                    if (!(when == ValueNull.INSTANCE) &&
1043                            when.getBoolean().booleanValue()) {
1044                        then = args[i + 1];
1045                        break;
1046                    }
1047                }
1048            } else {
1049                // Simple CASE expression
1050                // (expr, when, then)
1051                // (expr, when, then, else)
1052                // (expr, when, then, when, then)
1053                // (expr, when, then, when, then, else)
1054                if (!(v0 == ValueNull.INSTANCE)) {
1055                    for (int i = 1, len = args.length - 1; i < len; i += 2) {
1056                        Value when = args[i].getValue(session);
1057                        if (database.areEqual(v0, when)) {
1058                            then = args[i + 1];
1059                            break;
1060                        }
1061                    }
1062                }
1063            }
1064            if (then == null && args.length % 2 == 0) {
1065                // then = elsePart
1066                then = args[args.length - 1];
1067            }
1068            Value v = then == null ? ValueNull.INSTANCE : then.getValue(session);
1069            result = v.convertTo(dataType);
1070            break;
1071        }
1072        case ARRAY_GET: {
1073            if (v0.getType() == Value.ARRAY) {
1074                Value v1 = getNullOrValue(session, args, values, 1);
1075                int element = v1.getInt();
1076                Value[] list = ((ValueArray) v0).getList();
1077                if (element < 1 || element > list.length) {
1078                    result = ValueNull.INSTANCE;
1079                } else {
1080                    result = list[element - 1];
1081                }
1082            } else {
1083                result = ValueNull.INSTANCE;
1084            }
1085            break;
1086        }
1087        case ARRAY_LENGTH: {
1088            if (v0.getType() == Value.ARRAY) {
1089                Value[] list = ((ValueArray) v0).getList();
1090                result = ValueInt.get(list.length);
1091            } else {
1092                result = ValueNull.INSTANCE;
1093            }
1094            break;
1095        }
1096        case ARRAY_CONTAINS: {
1097            result = ValueBoolean.get(false);
1098            if (v0.getType() == Value.ARRAY) {
1099                Value v1 = getNullOrValue(session, args, values, 1);
1100                Value[] list = ((ValueArray) v0).getList();
1101                for (Value v : list) {
1102                    if (v.equals(v1)) {
1103                        result = ValueBoolean.get(true);
1104                        break;
1105                    }
1106                }
1107            }
1108            break;
1109        }
1110        case CANCEL_SESSION: {
1111            result = ValueBoolean.get(cancelStatement(session, v0.getInt()));
1112            break;
1113        }
1114        case TRANSACTION_ID: {
1115            result = session.getTransactionId();
1116            break;
1117        }
1118        default:
1119            result = null;
1120        }
1121        return result;
1122    }
1123 
1124    private static boolean cancelStatement(Session session, int targetSessionId) {
1125        session.getUser().checkAdmin();
1126        Session[] sessions = session.getDatabase().getSessions(false);
1127        for (Session s : sessions) {
1128            if (s.getId() == targetSessionId) {
1129                Command c = s.getCurrentCommand();
1130                if (c == null) {
1131                    return false;
1132                }
1133                c.cancel();
1134                return true;
1135            }
1136        }
1137        return false;
1138    }
1139 
1140    private static long getDiskSpaceUsed(Session session, Value v0) {
1141        Parser p = new Parser(session);
1142        String sql = v0.getString();
1143        Table table = p.parseTableName(sql);
1144        return table.getDiskSpaceUsed();
1145    }
1146 
1147    private static Value getNullOrValue(Session session, Expression[] args,
1148            Value[] values, int i) {
1149        if (i >= args.length) {
1150            return null;
1151        }
1152        Value v = values[i];
1153        if (v == null) {
1154            Expression e = args[i];
1155            if (e == null) {
1156                return null;
1157            }
1158            v = values[i] = e.getValue(session);
1159        }
1160        return v;
1161    }
1162 
1163    private Value getValueWithArgs(Session session, Expression[] args) {
1164        Value[] values = new Value[args.length];
1165        if (info.nullIfParameterIsNull) {
1166            for (int i = 0; i < args.length; i++) {
1167                Expression e = args[i];
1168                Value v = e.getValue(session);
1169                if (v == ValueNull.INSTANCE) {
1170                    return ValueNull.INSTANCE;
1171                }
1172                values[i] = v;
1173            }
1174        }
1175        Value v0 = getNullOrValue(session, args, values, 0);
1176        Value resultSimple = getSimpleValue(session, v0, args, values);
1177        if (resultSimple != null) {
1178            return resultSimple;
1179        }
1180        Value v1 = getNullOrValue(session, args, values, 1);
1181        Value v2 = getNullOrValue(session, args, values, 2);
1182        Value v3 = getNullOrValue(session, args, values, 3);
1183        Value v4 = getNullOrValue(session, args, values, 4);
1184        Value v5 = getNullOrValue(session, args, values, 5);
1185        Value result;
1186        switch (info.type) {
1187        case ATAN2:
1188            result = ValueDouble.get(
1189                    Math.atan2(v0.getDouble(), v1.getDouble()));
1190            break;
1191        case BITAND:
1192            result = ValueLong.get(v0.getLong() & v1.getLong());
1193            break;
1194        case BITOR:
1195            result = ValueLong.get(v0.getLong() | v1.getLong());
1196            break;
1197        case BITXOR:
1198            result = ValueLong.get(v0.getLong() ^ v1.getLong());
1199            break;
1200        case MOD: {
1201            long x = v1.getLong();
1202            if (x == 0) {
1203                throw DbException.get(ErrorCode.DIVISION_BY_ZERO_1, getSQL());
1204            }
1205            result = ValueLong.get(v0.getLong() % x);
1206            break;
1207        }
1208        case POWER:
1209            result = ValueDouble.get(Math.pow(
1210                    v0.getDouble(), v1.getDouble()));
1211            break;
1212        case ROUND: {
1213            double f = v1 == null ? 1. : Math.pow(10., v1.getDouble());
1214            result = ValueDouble.get(Math.round(v0.getDouble() * f) / f);
1215            break;
1216        }
1217        case TRUNCATE: {
1218            if (v0.getType() == Value.TIMESTAMP) {
1219                java.sql.Timestamp d = v0.getTimestamp();
1220                Calendar c = Calendar.getInstance();
1221                c.setTime(d);
1222                c.set(Calendar.HOUR_OF_DAY, 0);
1223                c.set(Calendar.MINUTE, 0);
1224                c.set(Calendar.SECOND, 0);
1225                c.set(Calendar.MILLISECOND, 0);
1226                result = ValueTimestamp.fromMillis(c.getTimeInMillis());
1227            } else {
1228                double d = v0.getDouble();
1229                int p = v1 == null ? 0 : v1.getInt();
1230                double f = Math.pow(10., p);
1231                double g = d * f;
1232                result = ValueDouble.get(((d < 0) ? Math.ceil(g) : Math.floor(g)) / f);
1233            }
1234            break;
1235        }
1236        case HASH:
1237            result = ValueBytes.getNoCopy(getHash(v0.getString(),
1238                    v1.getBytesNoCopy(), v2.getInt()));
1239            break;
1240        case ENCRYPT:
1241            result = ValueBytes.getNoCopy(encrypt(v0.getString(),
1242                    v1.getBytesNoCopy(), v2.getBytesNoCopy()));
1243            break;
1244        case DECRYPT:
1245            result = ValueBytes.getNoCopy(decrypt(v0.getString(),
1246                    v1.getBytesNoCopy(), v2.getBytesNoCopy()));
1247            break;
1248        case COMPRESS: {
1249            String algorithm = null;
1250            if (v1 != null) {
1251                algorithm = v1.getString();
1252            }
1253            result = ValueBytes.getNoCopy(CompressTool.getInstance().
1254                    compress(v0.getBytesNoCopy(), algorithm));
1255            break;
1256        }
1257        case DIFFERENCE:
1258            result = ValueInt.get(getDifference(
1259                    v0.getString(), v1.getString()));
1260            break;
1261        case INSERT: {
1262            if (v1 == ValueNull.INSTANCE || v2 == ValueNull.INSTANCE) {
1263                result = v1;
1264            } else {
1265                result = ValueString.get(insert(v0.getString(),
1266                        v1.getInt(), v2.getInt(), v3.getString()),
1267                        database.getMode().treatEmptyStringsAsNull);
1268            }
1269            break;
1270        }
1271        case LEFT:
1272            result = ValueString.get(left(v0.getString(), v1.getInt()),
1273                    database.getMode().treatEmptyStringsAsNull);
1274            break;
1275        case LOCATE: {
1276            int start = v2 == null ? 0 : v2.getInt();
1277            result = ValueInt.get(locate(v0.getString(), v1.getString(), start));
1278            break;
1279        }
1280        case INSTR: {
1281            int start = v2 == null ? 0 : v2.getInt();
1282            result = ValueInt.get(locate(v1.getString(), v0.getString(), start));
1283            break;
1284        }
1285        case REPEAT: {
1286            int count = Math.max(0, v1.getInt());
1287            result = ValueString.get(repeat(v0.getString(), count),
1288                    database.getMode().treatEmptyStringsAsNull);
1289            break;
1290        }
1291        case REPLACE: {
1292            String s0 = v0.getString();
1293            String s1 = v1.getString();
1294            String s2 = (v2 == null) ? "" : v2.getString();
1295            result = ValueString.get(replace(s0, s1, s2),
1296                    database.getMode().treatEmptyStringsAsNull);
1297            break;
1298        }
1299        case RIGHT:
1300            result = ValueString.get(right(v0.getString(), v1.getInt()),
1301                    database.getMode().treatEmptyStringsAsNull);
1302            break;
1303        case LTRIM:
1304            result = ValueString.get(StringUtils.trim(v0.getString(),
1305                    true, false, v1 == null ? " " : v1.getString()),
1306                    database.getMode().treatEmptyStringsAsNull);
1307            break;
1308        case TRIM:
1309            result = ValueString.get(StringUtils.trim(v0.getString(),
1310                    true, true, v1 == null ? " " : v1.getString()),
1311                    database.getMode().treatEmptyStringsAsNull);
1312            break;
1313        case RTRIM:
1314            result = ValueString.get(StringUtils.trim(v0.getString(),
1315                    false, true, v1 == null ? " " : v1.getString()),
1316                    database.getMode().treatEmptyStringsAsNull);
1317            break;
1318        case SUBSTR:
1319        case SUBSTRING: {
1320            String s = v0.getString();
1321            int offset = v1.getInt();
1322            if (offset < 0) {
1323                offset = s.length() + offset + 1;
1324            }
1325            int length = v2 == null ? s.length() : v2.getInt();
1326            result = ValueString.get(substring(s, offset, length),
1327                    database.getMode().treatEmptyStringsAsNull);
1328            break;
1329        }
1330        case POSITION:
1331            result = ValueInt.get(locate(v0.getString(), v1.getString(), 0));
1332            break;
1333        case XMLATTR:
1334            result = ValueString.get(
1335                    StringUtils.xmlAttr(v0.getString(), v1.getString()),
1336                    database.getMode().treatEmptyStringsAsNull);
1337            break;
1338        case XMLNODE: {
1339            String attr = v1 == null ?
1340                    null : v1 == ValueNull.INSTANCE ? null : v1.getString();
1341            String content = v2 == null ?
1342                    null : v2 == ValueNull.INSTANCE ? null : v2.getString();
1343            boolean indent = v3 == null ?
1344                    true : v3.getBoolean();
1345            result = ValueString.get(StringUtils.xmlNode(
1346                    v0.getString(), attr, content, indent),
1347                    database.getMode().treatEmptyStringsAsNull);
1348            break;
1349        }
1350        case REGEXP_REPLACE: {
1351            String regexp = v1.getString();
1352            String replacement = v2.getString();
1353            try {
1354                result = ValueString.get(
1355                        v0.getString().replaceAll(regexp, replacement),
1356                        database.getMode().treatEmptyStringsAsNull);
1357            } catch (StringIndexOutOfBoundsException e) {
1358                throw DbException.get(
1359                        ErrorCode.LIKE_ESCAPE_ERROR_1, e, replacement);
1360            } catch (PatternSyntaxException e) {
1361                throw DbException.get(
1362                        ErrorCode.LIKE_ESCAPE_ERROR_1, e, regexp);
1363            }
1364            break;
1365        }
1366        case RPAD:
1367            result = ValueString.get(StringUtils.pad(v0.getString(),
1368                    v1.getInt(), v2 == null ? null : v2.getString(), true),
1369                    database.getMode().treatEmptyStringsAsNull);
1370            break;
1371        case LPAD:
1372            result = ValueString.get(StringUtils.pad(v0.getString(),
1373                    v1.getInt(), v2 == null ? null : v2.getString(), false),
1374                    database.getMode().treatEmptyStringsAsNull);
1375            break;
1376        case TO_CHAR:
1377            switch(v0.getType()){
1378            case Value.TIME:
1379            case Value.DATE:
1380            case Value.TIMESTAMP:
1381                result = ValueString.get(toChar(v0.getTimestamp(),
1382                        v1 == null ? null : v1.getString(),
1383                        v2 == null ? null : v2.getString()),
1384                        database.getMode().treatEmptyStringsAsNull);
1385                break;
1386            case Value.SHORT:
1387            case Value.INT:
1388            case Value.LONG:
1389            case Value.DECIMAL:
1390            case Value.DOUBLE:
1391            case Value.FLOAT:
1392                result = ValueString.get(toChar(v0.getBigDecimal(),
1393                        v1 == null ? null : v1.getString(),
1394                        v2 == null ? null : v2.getString()),
1395                        database.getMode().treatEmptyStringsAsNull);
1396                break;
1397            default:
1398                result = ValueString.get(v0.getString(),
1399                        database.getMode().treatEmptyStringsAsNull);
1400            }
1401            break;
1402        case TRANSLATE: {
1403            String matching = v1.getString();
1404            String replacement = v2.getString();
1405            result = ValueString.get(
1406                    translate(v0.getString(), matching, replacement),
1407                    database.getMode().treatEmptyStringsAsNull);
1408            break;
1409        }
1410        case H2VERSION:
1411            result = ValueString.get(Constants.getVersion(),
1412                    database.getMode().treatEmptyStringsAsNull);
1413            break;
1414        case DATE_ADD:
1415            result = ValueTimestamp.get(dateadd(
1416                    v0.getString(), v1.getInt(), v2.getTimestamp()));
1417            break;
1418        case DATE_DIFF:
1419            result = ValueLong.get(datediff(
1420                    v0.getString(), v1.getTimestamp(), v2.getTimestamp()));
1421            break;
1422        case EXTRACT: {
1423            int field = getDatePart(v0.getString());
1424            result = ValueInt.get(DateTimeUtils.getDatePart(
1425                    v1.getTimestamp(), field));
1426            break;
1427        }
1428        case FORMATDATETIME: {
1429            if (v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) {
1430                result = ValueNull.INSTANCE;
1431            } else {
1432                String locale = v2 == null ?
1433                        null : v2 == ValueNull.INSTANCE ? null : v2.getString();
1434                String tz = v3 == null ?
1435                        null : v3 == ValueNull.INSTANCE ? null : v3.getString();
1436                result = ValueString.get(DateTimeUtils.formatDateTime(
1437                        v0.getTimestamp(), v1.getString(), locale, tz),
1438                        database.getMode().treatEmptyStringsAsNull);
1439            }
1440            break;
1441        }
1442        case PARSEDATETIME: {
1443            if (v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) {
1444                result = ValueNull.INSTANCE;
1445            } else {
1446                String locale = v2 == null ?
1447                        null : v2 == ValueNull.INSTANCE ? null : v2.getString();
1448                String tz = v3 == null ?
1449                        null : v3 == ValueNull.INSTANCE ? null : v3.getString();
1450                java.util.Date d = DateTimeUtils.parseDateTime(
1451                        v0.getString(), v1.getString(), locale, tz);
1452                result = ValueTimestamp.fromMillis(d.getTime());
1453            }
1454            break;
1455        }
1456        case NULLIF:
1457            result = database.areEqual(v0, v1) ? ValueNull.INSTANCE : v0;
1458            break;
1459            // system
1460        case NEXTVAL: {
1461            Sequence sequence = getSequence(session, v0, v1);
1462            SequenceValue value = new SequenceValue(sequence);
1463            result = value.getValue(session);
1464            break;
1465        }
1466        case CURRVAL: {
1467            Sequence sequence = getSequence(session, v0, v1);
1468            result = ValueLong.get(sequence.getCurrentValue());
1469            break;
1470        }
1471        case CSVREAD: {
1472            String fileName = v0.getString();
1473            String columnList = v1 == null ? null : v1.getString();
1474            Csv csv = new Csv();
1475            String options = v2 == null ? null : v2.getString();
1476            String charset = null;
1477            if (options != null && options.indexOf('=') >= 0) {
1478                charset = csv.setOptions(options);
1479            } else {
1480                charset = options;
1481                String fieldSeparatorRead = v3 == null ? null : v3.getString();
1482                String fieldDelimiter = v4 == null ? null : v4.getString();
1483                String escapeCharacter = v5 == null ? null : v5.getString();
1484                Value v6 = getNullOrValue(session, args, values, 6);
1485                String nullString = v6 == null ? null : v6.getString();
1486                setCsvDelimiterEscape(csv, fieldSeparatorRead, fieldDelimiter,
1487                        escapeCharacter);
1488                csv.setNullString(nullString);
1489            }
1490            char fieldSeparator = csv.getFieldSeparatorRead();
1491            String[] columns = StringUtils.arraySplit(columnList,
1492                    fieldSeparator, true);
1493            try {
1494                ValueResultSet vr = ValueResultSet.get(csv.read(fileName,
1495                        columns, charset));
1496                result = vr;
1497            } catch (SQLException e) {
1498                throw DbException.convert(e);
1499            }
1500            break;
1501        }
1502        case LINK_SCHEMA: {
1503            session.getUser().checkAdmin();
1504            Connection conn = session.createConnection(false);
1505            ResultSet rs = LinkSchema.linkSchema(conn, v0.getString(),
1506                    v1.getString(), v2.getString(), v3.getString(),
1507                    v4.getString(), v5.getString());
1508            result = ValueResultSet.get(rs);
1509            break;
1510        }
1511        case CSVWRITE: {
1512            session.getUser().checkAdmin();
1513            Connection conn = session.createConnection(false);
1514            Csv csv = new Csv();
1515            String options = v2 == null ? null : v2.getString();
1516            String charset = null;
1517            if (options != null && options.indexOf('=') >= 0) {
1518                charset = csv.setOptions(options);
1519            } else {
1520                charset = options;
1521                String fieldSeparatorWrite = v3 == null ? null : v3.getString();
1522                String fieldDelimiter = v4 == null ? null : v4.getString();
1523                String escapeCharacter = v5 == null ? null : v5.getString();
1524                Value v6 = getNullOrValue(session, args, values, 6);
1525                String nullString = v6 == null ? null : v6.getString();
1526                Value v7 = getNullOrValue(session, args, values, 7);
1527                String lineSeparator = v7 == null ? null : v7.getString();
1528                setCsvDelimiterEscape(csv, fieldSeparatorWrite, fieldDelimiter,
1529                        escapeCharacter);
1530                csv.setNullString(nullString);
1531                if (lineSeparator != null) {
1532                    csv.setLineSeparator(lineSeparator);
1533                }
1534            }
1535            try {
1536                int rows = csv.write(conn, v0.getString(), v1.getString(),
1537                        charset);
1538                result = ValueInt.get(rows);
1539            } catch (SQLException e) {
1540                throw DbException.convert(e);
1541            }
1542            break;
1543        }
1544        case SET: {
1545            Variable var = (Variable) args[0];
1546            session.setVariable(var.getName(), v1);
1547            result = v1;
1548            break;
1549        }
1550        case FILE_READ: {
1551            session.getUser().checkAdmin();
1552            String fileName = v0.getString();
1553            boolean blob = args.length == 1;
1554            try {
1555                InputStream in = new AutoCloseInputStream(
1556                        FileUtils.newInputStream(fileName));
1557                if (blob) {
1558                    result = database.getLobStorage().createBlob(in, -1);
1559                } else {
1560                    Reader reader;
1561                    if (v1 == ValueNull.INSTANCE) {
1562                        reader = new InputStreamReader(in);
1563                    } else {
1564                        reader = new InputStreamReader(in, v1.getString());
1565                    }
1566                    result = database.getLobStorage().createClob(reader, -1);
1567                }
1568            } catch (IOException e) {
1569                throw DbException.convertIOException(e, fileName);
1570            }
1571            break;
1572        }
1573        case TRUNCATE_VALUE: {
1574            result = v0.convertPrecision(v1.getLong(), v2.getBoolean());
1575            break;
1576        }
1577        case XMLTEXT:
1578            if (v1 == null) {
1579                result = ValueString.get(StringUtils.xmlText(
1580                        v0.getString()),
1581                        database.getMode().treatEmptyStringsAsNull);
1582            } else {
1583                result = ValueString.get(StringUtils.xmlText(
1584                        v0.getString(), v1.getBoolean()),
1585                        database.getMode().treatEmptyStringsAsNull);
1586            }
1587            break;
1588        case VALUES:
1589            result = session.getVariable(args[0].getSchemaName() + "." +
1590                    args[0].getTableName() + "." + args[0].getColumnName());
1591            break;
1592        default:
1593            throw DbException.throwInternalError("type=" + info.type);
1594        }
1595        return result;
1596    }
1597 
1598    private Sequence getSequence(Session session, Value v0, Value v1) {
1599        String schemaName, sequenceName;
1600        if (v1 == null) {
1601            Parser p = new Parser(session);
1602            String sql = v0.getString();
1603            Expression expr = p.parseExpression(sql);
1604            if (expr instanceof ExpressionColumn) {
1605                ExpressionColumn seq = (ExpressionColumn) expr;
1606                schemaName = seq.getOriginalTableAliasName();
1607                if (schemaName == null) {
1608                    schemaName = session.getCurrentSchemaName();
1609                    sequenceName = sql;
1610                } else {
1611                    sequenceName = seq.getColumnName();
1612                }
1613            } else {
1614                throw DbException.getSyntaxError(sql, 1);
1615            }
1616        } else {
1617            schemaName = v0.getString();
1618            sequenceName = v1.getString();
1619        }
1620        Schema s = database.findSchema(schemaName);
1621        if (s == null) {
1622            schemaName = StringUtils.toUpperEnglish(schemaName);
1623            s = database.getSchema(schemaName);
1624        }
1625        Sequence seq = s.findSequence(sequenceName);
1626        if (seq == null) {
1627            sequenceName = StringUtils.toUpperEnglish(sequenceName);
1628            seq = s.getSequence(sequenceName);
1629        }
1630        return seq;
1631    }
1632 
1633    private static long length(Value v) {
1634        switch (v.getType()) {
1635        case Value.BLOB:
1636        case Value.CLOB:
1637        case Value.BYTES:
1638        case Value.JAVA_OBJECT:
1639            return v.getPrecision();
1640        default:
1641            return v.getString().length();
1642        }
1643    }
1644 
1645    private static byte[] getPaddedArrayCopy(byte[] data, int blockSize) {
1646        int size = MathUtils.roundUpInt(data.length, blockSize);
1647        byte[] newData = DataUtils.newBytes(size);
1648        System.arraycopy(data, 0, newData, 0, data.length);
1649        return newData;
1650    }
1651 
1652    private static byte[] decrypt(String algorithm, byte[] key, byte[] data) {
1653        BlockCipher cipher = CipherFactory.getBlockCipher(algorithm);
1654        byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength());
1655        cipher.setKey(newKey);
1656        byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN);
1657        cipher.decrypt(newData, 0, newData.length);
1658        return newData;
1659    }
1660 
1661    private static byte[] encrypt(String algorithm, byte[] key, byte[] data) {
1662        BlockCipher cipher = CipherFactory.getBlockCipher(algorithm);
1663        byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength());
1664        cipher.setKey(newKey);
1665        byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN);
1666        cipher.encrypt(newData, 0, newData.length);
1667        return newData;
1668    }
1669 
1670    private static byte[] getHash(String algorithm, byte[] bytes, int iterations) {
1671        if (!"SHA256".equalsIgnoreCase(algorithm)) {
1672            throw DbException.getInvalidValueException("algorithm", algorithm);
1673        }
1674        for (int i = 0; i < iterations; i++) {
1675            bytes = SHA256.getHash(bytes, false);
1676        }
1677        return bytes;
1678    }
1679 
1680    /**
1681     * Check if a given string is a valid date part string.
1682     *
1683     * @param part the string
1684     * @return true if it is
1685     */
1686    public static boolean isDatePart(String part) {
1687        Integer p = DATE_PART.get(StringUtils.toUpperEnglish(part));
1688        return p != null;
1689    }
1690 
1691    private static int getDatePart(String part) {
1692        Integer p = DATE_PART.get(StringUtils.toUpperEnglish(part));
1693        if (p == null) {
1694            throw DbException.getInvalidValueException("date part", part);
1695        }
1696        return p.intValue();
1697    }
1698 
1699    private static Timestamp dateadd(String part, int count, Timestamp d) {
1700        int field = getDatePart(part);
1701        Calendar calendar = Calendar.getInstance();
1702        int nanos = d.getNanos() % 1000000;
1703        calendar.setTime(d);
1704        calendar.add(field, count);
1705        long t = calendar.getTime().getTime();
1706        Timestamp ts = new Timestamp(t);
1707        ts.setNanos(ts.getNanos() + nanos);
1708        return ts;
1709    }
1710 
1711    /**
1712     * Calculate the number of crossed unit boundaries between two timestamps.
1713     * This method is supported for MS SQL Server compatibility.
1714     * <pre>
1715     * DATEDIFF(YEAR, '2004-12-31', '2005-01-01') = 1
1716     * </pre>
1717     *
1718     * @param part the part
1719     * @param d1 the first date
1720     * @param d2 the second date
1721     * @return the number of crossed boundaries
1722     */
1723    private static long datediff(String part, Timestamp d1, Timestamp d2) {
1724        int field = getDatePart(part);
1725        Calendar calendar = Calendar.getInstance();
1726        long t1 = d1.getTime(), t2 = d2.getTime();
1727        // need to convert to UTC, otherwise we get inconsistent results with
1728        // certain time zones (those that are 30 minutes off)
1729        TimeZone zone = calendar.getTimeZone();
1730        calendar.setTime(d1);
1731        t1 += zone.getOffset(calendar.get(Calendar.ERA),
1732                calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
1733                calendar.get(Calendar.DAY_OF_MONTH),
1734                calendar.get(Calendar.DAY_OF_WEEK),
1735                calendar.get(Calendar.MILLISECOND));
1736        calendar.setTime(d2);
1737        t2 += zone.getOffset(calendar.get(Calendar.ERA),
1738                calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
1739                calendar.get(Calendar.DAY_OF_MONTH),
1740                calendar.get(Calendar.DAY_OF_WEEK),
1741                calendar.get(Calendar.MILLISECOND));
1742        switch (field) {
1743        case Calendar.MILLISECOND:
1744            return t2 - t1;
1745        case Calendar.SECOND:
1746        case Calendar.MINUTE:
1747        case Calendar.HOUR_OF_DAY: {
1748            // first 'normalize' the numbers so both are not negative
1749            long hour = 60 * 60 * 1000;
1750            long add = Math.min(t1 / hour * hour, t2 / hour * hour);
1751            t1 -= add;
1752            t2 -= add;
1753            switch (field) {
1754            case Calendar.SECOND:
1755                return t2 / 1000 - t1 / 1000;
1756            case Calendar.MINUTE:
1757                return t2 / (60 * 1000) - t1 / (60 * 1000);
1758            case Calendar.HOUR_OF_DAY:
1759                return t2 / hour - t1 / hour;
1760            default:
1761                throw DbException.throwInternalError("field:" + field);
1762            }
1763        }
1764        case Calendar.DATE:
1765            return t2 / (24 * 60 * 60 * 1000) - t1 / (24 * 60 * 60 * 1000);
1766        default:
1767            break;
1768        }
1769        calendar.setTimeInMillis(t1);
1770        int year1 = calendar.get(Calendar.YEAR);
1771        int month1 = calendar.get(Calendar.MONTH);
1772        calendar.setTimeInMillis(t2);
1773        int year2 = calendar.get(Calendar.YEAR);
1774        int month2 = calendar.get(Calendar.MONTH);
1775        int result = year2 - year1;
1776        if (field == Calendar.MONTH) {
1777            result = 12 * result + (month2 - month1);
1778        }
1779        return result;
1780    }
1781 
1782    private static String substring(String s, int start, int length) {
1783        int len = s.length();
1784        start--;
1785        if (start < 0) {
1786            start = 0;
1787        }
1788        if (length < 0) {
1789            length = 0;
1790        }
1791        start = (start > len) ? len : start;
1792        if (start + length > len) {
1793            length = len - start;
1794        }
1795        return s.substring(start, start + length);
1796    }
1797 
1798    private static String replace(String s, String replace, String with) {
1799        if (s == null || replace == null || with == null) {
1800            return null;
1801        }
1802        if (replace.length() == 0) {
1803            // avoid out of memory
1804            return s;
1805        }
1806        StringBuilder buff = new StringBuilder(s.length());
1807        int start = 0;
1808        int len = replace.length();
1809        while (true) {
1810            int i = s.indexOf(replace, start);
1811            if (i == -1) {
1812                break;
1813            }
1814            buff.append(s.substring(start, i)).append(with);
1815            start = i + len;
1816        }
1817        buff.append(s.substring(start));
1818        return buff.toString();
1819    }
1820 
1821    private static String repeat(String s, int count) {
1822        StringBuilder buff = new StringBuilder(s.length() * count);
1823        while (count-- > 0) {
1824            buff.append(s);
1825        }
1826        return buff.toString();
1827    }
1828 
1829    private static String rawToHex(String s) {
1830        int length = s.length();
1831        StringBuilder buff = new StringBuilder(4 * length);
1832        for (int i = 0; i < length; i++) {
1833            String hex = Integer.toHexString(s.charAt(i) & 0xffff);
1834            for (int j = hex.length(); j < 4; j++) {
1835                buff.append('0');
1836            }
1837            buff.append(hex);
1838        }
1839        return buff.toString();
1840    }
1841 
1842    private static int locate(String search, String s, int start) {
1843        if (start < 0) {
1844            int i = s.length() + start;
1845            return s.lastIndexOf(search, i) + 1;
1846        }
1847        int i = (start == 0) ? 0 : start - 1;
1848        return s.indexOf(search, i) + 1;
1849    }
1850 
1851    private static String right(String s, int count) {
1852        if (count < 0) {
1853            count = 0;
1854        } else if (count > s.length()) {
1855            count = s.length();
1856        }
1857        return s.substring(s.length() - count);
1858    }
1859 
1860    private static String left(String s, int count) {
1861        if (count < 0) {
1862            count = 0;
1863        } else if (count > s.length()) {
1864            count = s.length();
1865        }
1866        return s.substring(0, count);
1867    }
1868 
1869    private static String insert(String s1, int start, int length, String s2) {
1870        if (s1 == null) {
1871            return s2;
1872        }
1873        if (s2 == null) {
1874            return s1;
1875        }
1876        int len1 = s1.length();
1877        int len2 = s2.length();
1878        start--;
1879        if (start < 0 || length <= 0 || len2 == 0 || start > len1) {
1880            return s1;
1881        }
1882        if (start + length > len1) {
1883            length = len1 - start;
1884        }
1885        return s1.substring(0, start) + s2 + s1.substring(start + length);
1886    }
1887 
1888    private static String hexToRaw(String s) {
1889        // TODO function hextoraw compatibility with oracle
1890        int len = s.length();
1891        if (len % 4 != 0) {
1892            throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, s);
1893        }
1894        StringBuilder buff = new StringBuilder(len / 4);
1895        for (int i = 0; i < len; i += 4) {
1896            try {
1897                char raw = (char) Integer.parseInt(s.substring(i, i + 4), 16);
1898                buff.append(raw);
1899            } catch (NumberFormatException e) {
1900                throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, s);
1901            }
1902        }
1903        return buff.toString();
1904    }
1905 
1906    private static int getDifference(String s1, String s2) {
1907        // TODO function difference: compatibility with SQL Server and HSQLDB
1908        s1 = getSoundex(s1);
1909        s2 = getSoundex(s2);
1910        int e = 0;
1911        for (int i = 0; i < 4; i++) {
1912            if (s1.charAt(i) == s2.charAt(i)) {
1913                e++;
1914            }
1915        }
1916        return e;
1917    }
1918 
1919    private static String translate(String original, String findChars,
1920            String replaceChars) {
1921        if (StringUtils.isNullOrEmpty(original) ||
1922                StringUtils.isNullOrEmpty(findChars)) {
1923            return original;
1924        }
1925        // if it stays null, then no replacements have been made
1926        StringBuilder buff = null;
1927        // if shorter than findChars, then characters are removed
1928        // (if null, we don't access replaceChars at all)
1929        int replaceSize = replaceChars == null ? 0 : replaceChars.length();
1930        for (int i = 0, size = original.length(); i < size; i++) {
1931            char ch = original.charAt(i);
1932            int index = findChars.indexOf(ch);
1933            if (index >= 0) {
1934                if (buff == null) {
1935                    buff = new StringBuilder(size);
1936                    if (i > 0) {
1937                        buff.append(original.substring(0, i));
1938                    }
1939                }
1940                if (index < replaceSize) {
1941                    ch = replaceChars.charAt(index);
1942                }
1943            }
1944            if (buff != null) {
1945                buff.append(ch);
1946            }
1947        }
1948        return buff == null ? original : buff.toString();
1949    }
1950 
1951    private static double roundMagic(double d) {
1952        if ((d < 0.0000000000001) && (d > -0.0000000000001)) {
1953            return 0.0;
1954        }
1955        if ((d > 1000000000000.) || (d < -1000000000000.)) {
1956            return d;
1957        }
1958        StringBuilder s = new StringBuilder();
1959        s.append(d);
1960        if (s.toString().indexOf('E') >= 0) {
1961            return d;
1962        }
1963        int len = s.length();
1964        if (len < 16) {
1965            return d;
1966        }
1967        if (s.toString().indexOf('.') > len - 3) {
1968            return d;
1969        }
1970        s.delete(len - 2, len);
1971        len -= 2;
1972        char c1 = s.charAt(len - 2);
1973        char c2 = s.charAt(len - 3);
1974        char c3 = s.charAt(len - 4);
1975        if ((c1 == '0') && (c2 == '0') && (c3 == '0')) {
1976            s.setCharAt(len - 1, '0');
1977        } else if ((c1 == '9') && (c2 == '9') && (c3 == '9')) {
1978            s.setCharAt(len - 1, '9');
1979            s.append('9');
1980            s.append('9');
1981            s.append('9');
1982        }
1983        return Double.parseDouble(s.toString());
1984    }
1985 
1986    private static String getSoundex(String s) {
1987        int len = s.length();
1988        char[] chars = { '0', '0', '0', '0' };
1989        char lastDigit = '0';
1990        for (int i = 0, j = 0; i < len && j < 4; i++) {
1991            char c = s.charAt(i);
1992            char newDigit = c > SOUNDEX_INDEX.length ?
1993                    0 : SOUNDEX_INDEX[c];
1994            if (newDigit != 0) {
1995                if (j == 0) {
1996                    chars[j++] = c;
1997                    lastDigit = newDigit;
1998                } else if (newDigit <= '6') {
1999                    if (newDigit != lastDigit) {
2000                        chars[j++] = newDigit;
2001                        lastDigit = newDigit;
2002                    }
2003                } else if (newDigit == '7') {
2004                    lastDigit = newDigit;
2005                }
2006            }
2007        }
2008        return new String(chars);
2009    }
2010 
2011    @Override
2012    public int getType() {
2013        return dataType;
2014    }
2015 
2016    @Override
2017    public void mapColumns(ColumnResolver resolver, int level) {
2018        for (Expression e : args) {
2019            if (e != null) {
2020                e.mapColumns(resolver, level);
2021            }
2022        }
2023    }
2024 
2025    /**
2026     * Check if the parameter count is correct.
2027     *
2028     * @param len the number of parameters set
2029     * @throws DbException if the parameter count is incorrect
2030     */
2031    protected void checkParameterCount(int len) {
2032        int min = 0, max = Integer.MAX_VALUE;
2033        switch (info.type) {
2034        case COALESCE:
2035        case CSVREAD:
2036        case LEAST:
2037        case GREATEST:
2038            min = 1;
2039            break;
2040        case NOW:
2041        case CURRENT_TIMESTAMP:
2042        case RAND:
2043            max = 1;
2044            break;
2045        case COMPRESS:
2046        case LTRIM:
2047        case RTRIM:
2048        case TRIM:
2049        case FILE_READ:
2050        case ROUND:
2051        case XMLTEXT:
2052        case TRUNCATE:
2053            min = 1;
2054            max = 2;
2055            break;
2056        case TO_CHAR:
2057            min = 1;
2058            max = 3;
2059            break;
2060        case REPLACE:
2061        case LOCATE:
2062        case INSTR:
2063        case SUBSTR:
2064        case SUBSTRING:
2065        case LPAD:
2066        case RPAD:
2067            min = 2;
2068            max = 3;
2069            break;
2070        case CONCAT:
2071        case CONCAT_WS:
2072        case CSVWRITE:
2073            min = 2;
2074            break;
2075        case XMLNODE:
2076            min = 1;
2077            max = 4;
2078            break;
2079        case FORMATDATETIME:
2080        case PARSEDATETIME:
2081            min = 2;
2082            max = 4;
2083            break;
2084        case CURRVAL:
2085        case NEXTVAL:
2086            min = 1;
2087            max = 2;
2088            break;
2089        case DECODE:
2090        case CASE:
2091            min = 3;
2092            break;
2093        default:
2094            DbException.throwInternalError("type=" + info.type);
2095        }
2096        boolean ok = (len >= min) && (len <= max);
2097        if (!ok) {
2098            throw DbException.get(
2099                    ErrorCode.INVALID_PARAMETER_COUNT_2,
2100                    info.name, min + ".." + max);
2101        }
2102    }
2103 
2104    /**
2105     * This method is called after all the parameters have been set.
2106     * It checks if the parameter count is correct.
2107     *
2108     * @throws DbException if the parameter count is incorrect.
2109     */
2110    public void doneWithParameters() {
2111        if (info.parameterCount == VAR_ARGS) {
2112            int len = varArgs.size();
2113            checkParameterCount(len);
2114            args = new Expression[len];
2115            varArgs.toArray(args);
2116            varArgs = null;
2117        } else {
2118            int len = args.length;
2119            if (len > 0 && args[len - 1] == null) {
2120                throw DbException.get(
2121                        ErrorCode.INVALID_PARAMETER_COUNT_2,
2122                        info.name, "" + len);
2123            }
2124        }
2125    }
2126 
2127    public void setDataType(Column col) {
2128        dataType = col.getType();
2129        precision = col.getPrecision();
2130        displaySize = col.getDisplaySize();
2131        scale = col.getScale();
2132    }
2133 
2134    @Override
2135    public Expression optimize(Session session) {
2136        boolean allConst = info.deterministic;
2137        for (int i = 0; i < args.length; i++) {
2138            Expression e = args[i];
2139            if (e == null) {
2140                continue;
2141            }
2142            e = e.optimize(session);
2143            args[i] = e;
2144            if (!e.isConstant()) {
2145                allConst = false;
2146            }
2147        }
2148        int t, s, d;
2149        long p;
2150        Expression p0 = args.length < 1 ? null : args[0];
2151        switch (info.type) {
2152        case IFNULL:
2153        case NULLIF:
2154        case COALESCE:
2155        case LEAST:
2156        case GREATEST: {
2157            t = Value.UNKNOWN;
2158            s = 0;
2159            p = 0;
2160            d = 0;
2161            for (Expression e : args) {
2162                if (e != ValueExpression.getNull()) {
2163                    int type = e.getType();
2164                    if (type != Value.UNKNOWN && type != Value.NULL) {
2165                        t = Value.getHigherOrder(t, type);
2166                        s = Math.max(s, e.getScale());
2167                        p = Math.max(p, e.getPrecision());
2168                        d = Math.max(d, e.getDisplaySize());
2169                    }
2170                }
2171            }
2172            if (t == Value.UNKNOWN) {
2173                t = Value.STRING;
2174                s = 0;
2175                p = Integer.MAX_VALUE;
2176                d = Integer.MAX_VALUE;
2177            }
2178            break;
2179        }
2180        case CASE:
2181        case DECODE: {
2182            t = Value.UNKNOWN;
2183            s = 0;
2184            p = 0;
2185            d = 0;
2186            // (expr, when, then)
2187            // (expr, when, then, else)
2188            // (expr, when, then, when, then)
2189            // (expr, when, then, when, then, else)
2190            for (int i = 2, len = args.length; i < len; i += 2) {
2191                Expression then = args[i];
2192                if (then != ValueExpression.getNull()) {
2193                    int type = then.getType();
2194                    if (type != Value.UNKNOWN && type != Value.NULL) {
2195                        t = Value.getHigherOrder(t, type);
2196                        s = Math.max(s, then.getScale());
2197                        p = Math.max(p, then.getPrecision());
2198                        d = Math.max(d, then.getDisplaySize());
2199                    }
2200                }
2201            }
2202            if (args.length % 2 == 0) {
2203                Expression elsePart = args[args.length - 1];
2204                if (elsePart != ValueExpression.getNull()) {
2205                    int type = elsePart.getType();
2206                    if (type != Value.UNKNOWN && type != Value.NULL) {
2207                        t = Value.getHigherOrder(t, type);
2208                        s = Math.max(s, elsePart.getScale());
2209                        p = Math.max(p, elsePart.getPrecision());
2210                        d = Math.max(d, elsePart.getDisplaySize());
2211                    }
2212                }
2213            }
2214            if (t == Value.UNKNOWN) {
2215                t = Value.STRING;
2216                s = 0;
2217                p = Integer.MAX_VALUE;
2218                d = Integer.MAX_VALUE;
2219            }
2220            break;
2221        }
2222        case CASEWHEN:
2223            t = Value.getHigherOrder(args[1].getType(), args[2].getType());
2224            p = Math.max(args[1].getPrecision(), args[2].getPrecision());
2225            d = Math.max(args[1].getDisplaySize(), args[2].getDisplaySize());
2226            s = Math.max(args[1].getScale(), args[2].getScale());
2227            break;
2228        case NVL2:
2229            switch (args[1].getType()) {
2230            case Value.STRING:
2231            case Value.CLOB:
2232            case Value.STRING_FIXED:
2233            case Value.STRING_IGNORECASE:
2234                t = args[1].getType();
2235                break;
2236            default:
2237                t = Value.getHigherOrder(args[1].getType(), args[2].getType());
2238                break;
2239            }
2240            p = Math.max(args[1].getPrecision(), args[2].getPrecision());
2241            d = Math.max(args[1].getDisplaySize(), args[2].getDisplaySize());
2242            s = Math.max(args[1].getScale(), args[2].getScale());
2243            break;
2244        case CAST:
2245        case CONVERT:
2246        case TRUNCATE_VALUE:
2247            // data type, precision and scale is already set
2248            t = dataType;
2249            p = precision;
2250            s = scale;
2251            d = displaySize;
2252            break;
2253        case TRUNCATE:
2254            t = p0.getType();
2255            s = p0.getScale();
2256            p = p0.getPrecision();
2257            d = p0.getDisplaySize();
2258            if (t == Value.NULL) {
2259                t = Value.INT;
2260                p = ValueInt.PRECISION;
2261                d = ValueInt.DISPLAY_SIZE;
2262                s = 0;
2263            } else if (t == Value.TIMESTAMP) {
2264                t = Value.DATE;
2265                p = ValueDate.PRECISION;
2266                s = 0;
2267                d = ValueDate.DISPLAY_SIZE;
2268            }
2269            break;
2270        case ABS:
2271        case FLOOR:
2272        case ROUND:
2273            t = p0.getType();
2274            s = p0.getScale();
2275            p = p0.getPrecision();
2276            d = p0.getDisplaySize();
2277            if (t == Value.NULL) {
2278                t = Value.INT;
2279                p = ValueInt.PRECISION;
2280                d = ValueInt.DISPLAY_SIZE;
2281                s = 0;
2282            }
2283            break;
2284        case SET: {
2285            Expression p1 = args[1];
2286            t = p1.getType();
2287            p = p1.getPrecision();
2288            s = p1.getScale();
2289            d = p1.getDisplaySize();
2290            if (!(p0 instanceof Variable)) {
2291                throw DbException.get(
2292                        ErrorCode.CAN_ONLY_ASSIGN_TO_VARIABLE_1, p0.getSQL());
2293            }
2294            break;
2295        }
2296        case FILE_READ: {
2297            if (args.length == 1) {
2298                t = Value.BLOB;
2299            } else {
2300                t = Value.CLOB;
2301            }
2302            p = Integer.MAX_VALUE;
2303            s = 0;
2304            d = Integer.MAX_VALUE;
2305            break;
2306        }
2307        case SUBSTRING:
2308        case SUBSTR: {
2309            t = info.dataType;
2310            p = args[0].getPrecision();
2311            s = 0;
2312            if (args[1].isConstant()) {
2313                // if only two arguments are used,
2314                // subtract offset from first argument length
2315                p -= args[1].getValue(session).getLong() - 1;
2316            }
2317            if (args.length == 3 && args[2].isConstant()) {
2318                // if the third argument is constant it is at most this value
2319                p = Math.min(p, args[2].getValue(session).getLong());
2320            }
2321            p = Math.max(0, p);
2322            d = MathUtils.convertLongToInt(p);
2323            break;
2324        }
2325        default:
2326            t = info.dataType;
2327            DataType type = DataType.getDataType(t);
2328            p = PRECISION_UNKNOWN;
2329            d = 0;
2330            s = type.defaultScale;
2331        }
2332        dataType = t;
2333        precision = p;
2334        scale = s;
2335        displaySize = d;
2336        if (allConst) {
2337            Value v = getValue(session);
2338            if (v == ValueNull.INSTANCE) {
2339                if (info.type == CAST || info.type == CONVERT) {
2340                    return this;
2341                }
2342            }
2343            return ValueExpression.get(v);
2344        }
2345        return this;
2346    }
2347 
2348    @Override
2349    public void setEvaluatable(TableFilter tableFilter, boolean b) {
2350        for (Expression e : args) {
2351            if (e != null) {
2352                e.setEvaluatable(tableFilter, b);
2353            }
2354        }
2355    }
2356 
2357    @Override
2358    public int getScale() {
2359        return scale;
2360    }
2361 
2362    @Override
2363    public long getPrecision() {
2364        if (precision == PRECISION_UNKNOWN) {
2365            calculatePrecisionAndDisplaySize();
2366        }
2367        return precision;
2368    }
2369 
2370    @Override
2371    public int getDisplaySize() {
2372        if (precision == PRECISION_UNKNOWN) {
2373            calculatePrecisionAndDisplaySize();
2374        }
2375        return displaySize;
2376    }
2377 
2378    private void calculatePrecisionAndDisplaySize() {
2379        switch (info.type) {
2380        case ENCRYPT:
2381        case DECRYPT:
2382            precision = args[2].getPrecision();
2383            displaySize = args[2].getDisplaySize();
2384            break;
2385        case COMPRESS:
2386            precision = args[0].getPrecision();
2387            displaySize = args[0].getDisplaySize();
2388            break;
2389        case CHAR:
2390            precision = 1;
2391            displaySize = 1;
2392            break;
2393        case CONCAT:
2394            precision = 0;
2395            displaySize = 0;
2396            for (Expression e : args) {
2397                precision += e.getPrecision();
2398                displaySize = MathUtils.convertLongToInt(
2399                        (long) displaySize + e.getDisplaySize());
2400                if (precision < 0) {
2401                    precision = Long.MAX_VALUE;
2402                }
2403            }
2404            break;
2405        case HEXTORAW:
2406            precision = (args[0].getPrecision() + 3) / 4;
2407            displaySize = MathUtils.convertLongToInt(precision);
2408            break;
2409        case LCASE:
2410        case LTRIM:
2411        case RIGHT:
2412        case RTRIM:
2413        case UCASE:
2414        case LOWER:
2415        case UPPER:
2416        case TRIM:
2417        case STRINGDECODE:
2418        case UTF8TOSTRING:
2419        case TRUNCATE:
2420            precision = args[0].getPrecision();
2421            displaySize = args[0].getDisplaySize();
2422            break;
2423        case RAWTOHEX:
2424            precision = args[0].getPrecision() * 4;
2425            displaySize = MathUtils.convertLongToInt(precision);
2426            break;
2427        case SOUNDEX:
2428            precision = 4;
2429            displaySize = (int) precision;
2430            break;
2431        case DAY_NAME:
2432        case MONTH_NAME:
2433            // day and month names may be long in some languages
2434            precision = 20;
2435            displaySize = (int) precision;
2436            break;
2437        default:
2438            DataType type = DataType.getDataType(dataType);
2439            precision = type.defaultPrecision;
2440            displaySize = type.defaultDisplaySize;
2441        }
2442    }
2443 
2444    @Override
2445    public String getSQL() {
2446        StatementBuilder buff = new StatementBuilder(info.name);
2447        if (info.type == CASE) {
2448            if (args[0] != null) {
2449                buff.append(" ").append(args[0].getSQL());
2450            }
2451            for (int i = 1, len = args.length - 1; i < len; i += 2) {
2452                buff.append(" WHEN ").append(args[i].getSQL());
2453                buff.append(" THEN ").append(args[i + 1].getSQL());
2454            }
2455            if (args.length % 2 == 0) {
2456                buff.append(" ELSE ").append(args[args.length - 1].getSQL());
2457            }
2458            return buff.append(" END").toString();
2459        }
2460        buff.append('(');
2461        switch (info.type) {
2462        case CAST: {
2463            buff.append(args[0].getSQL()).append(" AS ").
2464                append(new Column(null, dataType, precision,
2465                        scale, displaySize).getCreateSQL());
2466            break;
2467        }
2468        case CONVERT: {
2469            buff.append(args[0].getSQL()).append(',').
2470                append(new Column(null, dataType, precision,
2471                        scale, displaySize).getCreateSQL());
2472            break;
2473        }
2474        case EXTRACT: {
2475            ValueString v = (ValueString) ((ValueExpression) args[0]).getValue(null);
2476            buff.append(v.getString()).append(" FROM ").append(args[1].getSQL());
2477            break;
2478        }
2479        default: {
2480            for (Expression e : args) {
2481                buff.appendExceptFirst(", ");
2482                buff.append(e.getSQL());
2483            }
2484        }
2485        }
2486        return buff.append(')').toString();
2487    }
2488 
2489    @Override
2490    public void updateAggregate(Session session) {
2491        for (Expression e : args) {
2492            if (e != null) {
2493                e.updateAggregate(session);
2494            }
2495        }
2496    }
2497 
2498    public int getFunctionType() {
2499        return info.type;
2500    }
2501 
2502    @Override
2503    public String getName() {
2504        return info.name;
2505    }
2506 
2507    @Override
2508    public ValueResultSet getValueForColumnList(Session session,
2509            Expression[] argList) {
2510        switch (info.type) {
2511        case CSVREAD: {
2512            String fileName = argList[0].getValue(session).getString();
2513            if (fileName == null) {
2514                throw DbException.get(ErrorCode.PARAMETER_NOT_SET_1, "fileName");
2515            }
2516            String columnList = argList.length < 2 ?
2517                    null : argList[1].getValue(session).getString();
2518            Csv csv = new Csv();
2519            String options = argList.length < 3 ?
2520                    null : argList[2].getValue(session).getString();
2521            String charset = null;
2522            if (options != null && options.indexOf('=') >= 0) {
2523                charset = csv.setOptions(options);
2524            } else {
2525                charset = options;
2526                String fieldSeparatorRead = argList.length < 4 ?
2527                        null : argList[3].getValue(session).getString();
2528                String fieldDelimiter = argList.length < 5 ?
2529                        null : argList[4].getValue(session).getString();
2530                String escapeCharacter = argList.length < 6 ?
2531                        null : argList[5].getValue(session).getString();
2532                setCsvDelimiterEscape(csv, fieldSeparatorRead, fieldDelimiter,
2533                        escapeCharacter);
2534            }
2535            char fieldSeparator = csv.getFieldSeparatorRead();
2536            String[] columns = StringUtils.arraySplit(columnList, fieldSeparator, true);
2537            ResultSet rs = null;
2538            ValueResultSet x;
2539            try {
2540                rs = csv.read(fileName, columns, charset);
2541                x = ValueResultSet.getCopy(rs, 0);
2542            } catch (SQLException e) {
2543                throw DbException.convert(e);
2544            } finally {
2545                csv.close();
2546                JdbcUtils.closeSilently(rs);
2547            }
2548            return x;
2549        }
2550        default:
2551            break;
2552        }
2553        return (ValueResultSet) getValueWithArgs(session, argList);
2554    }
2555 
2556    private static void setCsvDelimiterEscape(Csv csv, String fieldSeparator,
2557            String fieldDelimiter, String escapeCharacter) {
2558        if (fieldSeparator != null) {
2559            csv.setFieldSeparatorWrite(fieldSeparator);
2560            if (fieldSeparator.length() > 0) {
2561                char fs = fieldSeparator.charAt(0);
2562                csv.setFieldSeparatorRead(fs);
2563            }
2564        }
2565        if (fieldDelimiter != null) {
2566            char fd = fieldDelimiter.length() == 0 ?
2567                    0 : fieldDelimiter.charAt(0);
2568            csv.setFieldDelimiter(fd);
2569        }
2570        if (escapeCharacter != null) {
2571            char ec = escapeCharacter.length() == 0 ?
2572                    0 : escapeCharacter.charAt(0);
2573            csv.setEscapeCharacter(ec);
2574        }
2575    }
2576 
2577    @Override
2578    public Expression[] getArgs() {
2579        return args;
2580    }
2581 
2582    @Override
2583    public boolean isEverything(ExpressionVisitor visitor) {
2584        for (Expression e : args) {
2585            if (e != null && !e.isEverything(visitor)) {
2586                return false;
2587            }
2588        }
2589        switch (visitor.getType()) {
2590        case ExpressionVisitor.DETERMINISTIC:
2591        case ExpressionVisitor.QUERY_COMPARABLE:
2592        case ExpressionVisitor.READONLY:
2593            return info.deterministic;
2594        case ExpressionVisitor.EVALUATABLE:
2595        case ExpressionVisitor.GET_DEPENDENCIES:
2596        case ExpressionVisitor.INDEPENDENT:
2597        case ExpressionVisitor.NOT_FROM_RESOLVER:
2598        case ExpressionVisitor.OPTIMIZABLE_MIN_MAX_COUNT_ALL:
2599        case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
2600        case ExpressionVisitor.GET_COLUMNS:
2601            return true;
2602        default:
2603            throw DbException.throwInternalError("type=" + visitor.getType());
2604        }
2605    }
2606 
2607    @Override
2608    public int getCost() {
2609        int cost = 3;
2610        for (Expression e : args) {
2611            if (e != null) {
2612                cost += e.getCost();
2613            }
2614        }
2615        return cost;
2616    }
2617 
2618    @Override
2619    public boolean isDeterministic() {
2620        return info.deterministic;
2621    }
2622 
2623    @Override
2624    public boolean isBufferResultSetToLocalTemp() {
2625        return info.bufferResultSetToLocalTemp;
2626    }
2627 
2628}

[all classes][org.h2.expression]
EMMA 2.0.5312 (C) Vladimir Roubtsov