File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\expression\Function.java.html

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