1 5 package org.h2.expression; 6 7 import java.sql.Connection ; 8 import java.sql.Date ; 9 import java.sql.ResultSet ; 10 import java.sql.SQLException ; 11 import java.sql.Time ; 12 import java.sql.Timestamp ; 13 import java.text.SimpleDateFormat ; 14 import java.util.Calendar ; 15 import java.util.HashMap ; 16 import java.util.Locale ; 17 import java.util.TimeZone ; 18 19 import org.h2.engine.Database; 20 import org.h2.engine.Mode; 21 import org.h2.engine.Session; 22 import org.h2.message.Message; 23 import org.h2.schema.Sequence; 24 import org.h2.security.BlockCipher; 25 import org.h2.security.CipherFactory; 26 import org.h2.security.SHA256; 27 import org.h2.table.Column; 28 import org.h2.table.ColumnResolver; 29 import org.h2.table.TableFilter; 30 import org.h2.tools.CompressTool; 31 import org.h2.tools.Csv; 32 import org.h2.util.MathUtils; 33 import org.h2.util.MemoryUtils; 34 import org.h2.util.ObjectArray; 35 import org.h2.util.RandomUtils; 36 import org.h2.util.StringUtils; 37 import org.h2.value.Value; 38 import org.h2.value.ValueArray; 39 import org.h2.value.ValueBoolean; 40 import org.h2.value.ValueBytes; 41 import org.h2.value.ValueDate; 42 import org.h2.value.ValueDouble; 43 import org.h2.value.ValueInt; 44 import org.h2.value.ValueLong; 45 import org.h2.value.ValueNull; 46 import org.h2.value.ValueResultSet; 47 import org.h2.value.ValueString; 48 import org.h2.value.ValueTime; 49 import org.h2.value.ValueTimestamp; 50 import org.h2.value.ValueUuid; 51 52 55 56 public class Function extends Expression implements FunctionCall { 57 60 public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3, ATAN2 = 4, 61 BITAND = 5, BITOR = 6, BITXOR = 7, CEILING = 8, COS = 9, COT = 10, 62 DEGREES = 11, EXP = 12, FLOOR = 13, LOG = 14, LOG10 = 15, MOD = 16, 63 PI = 17, POWER = 18, RADIANS = 19, RAND = 20, 64 ROUND = 21, ROUNDMAGIC = 22, SIGN = 23, SIN = 24, SQRT = 25, 65 TAN = 26, TRUNCATE = 27, SECURE_RAND = 28, 66 HASH = 29, ENCRYPT = 30, DECRYPT = 31, 67 COMPRESS = 32, EXPAND = 33, ZERO = 34, RANDOM_UUID = 35; 68 69 public static final int ASCII = 50, BIT_LENGTH = 51, CHAR = 52, CHAR_LENGTH = 53, 70 CONCAT = 54, DIFFERENCE = 55, HEXTORAW = 56, INSERT = 57, INSTR = 58, 71 LCASE = 59, LEFT = 60, LENGTH = 61, LOCATE = 62, LTRIM = 63, 72 OCTET_LENGTH = 64, RAWTOHEX = 65, REPEAT = 66, REPLACE = 67, 73 RIGHT = 68, RTRIM = 69, SOUNDEX = 70, SPACE = 71, SUBSTR = 72, 74 SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78, 75 STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, 76 XMLATTR = 83, XMLNODE = 84, XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, 77 XMLTEXT = 88; 78 79 public static final int CURDATE = 100, CURTIME = 101, DATEADD = 102, DATEDIFF = 103, 80 DAYNAME = 104, DAYOFMONTH = 105, DAYOFWEEK = 106, DAYOFYEAR = 107, 81 HOUR = 108, MINUTE = 109, MONTH = 110, MONTHNAME = 111, NOW = 112, 82 QUARTER = 113, SECOND = 114, WEEK = 115, YEAR = 116, 83 CURRENT_DATE = 117, CURRENT_TIME = 118, CURRENT_TIMESTAMP = 119, 84 EXTRACT = 120, FORMATDATETIME = 121, PARSEDATETIME = 122; 85 86 public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152, 87 IDENTITY = 153, AUTOCOMMIT = 154, READONLY = 155, DATABASE_PATH = 156, LOCK_TIMEOUT = 157; 88 89 public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203, 90 COALESCE = 204, NULLIF = 205, CASE = 206, NEXTVAL = 207, CURRVAL = 208, 91 ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211, MEMORY_FREE = 212, 92 MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217; 93 94 private static final int VARARGS = -1; 95 96 private static HashMap functions; 97 98 private FunctionInfo info; 99 private Expression[] args; 100 private ObjectArray varargs; 101 private int dataType, scale; 102 private long precision; 103 private Database database; 104 105 private static HashMap datePart; 106 private static final SimpleDateFormat FORMAT_DAYNAME = new SimpleDateFormat ( 107 "EEEE", Locale.ENGLISH); 108 private static final SimpleDateFormat FORMAT_MONTHNAME = new SimpleDateFormat ( 109 "MMMM", Locale.ENGLISH); 110 private static final char[] SOUNDEX_INDEX = new char[128]; 111 112 static { 113 datePart = new HashMap (); 114 datePart.put("YY", new Integer (Calendar.YEAR)); 115 datePart.put("YEAR", new Integer (Calendar.YEAR)); 116 datePart.put("MM", new Integer (Calendar.MONTH)); 117 datePart.put("MONTH", new Integer (Calendar.MONTH)); 118 datePart.put("DD", new Integer (Calendar.DATE)); 119 datePart.put("DAY", new Integer (Calendar.DATE)); 120 datePart.put("HH", new Integer (Calendar.HOUR)); 121 datePart.put("HOUR", new Integer (Calendar.HOUR)); 122 datePart.put("MI", new Integer (Calendar.MINUTE)); 123 datePart.put("MINUTE", new Integer (Calendar.MINUTE)); 124 datePart.put("SS", new Integer (Calendar.SECOND)); 125 datePart.put("SECOND", new Integer (Calendar.SECOND)); 126 datePart.put("MS", new Integer (Calendar.MILLISECOND)); 127 datePart.put("MILLISECOND", new Integer (Calendar.MILLISECOND)); 128 } 129 130 static { 131 String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"; 132 char number = 0; 133 for(int i=0; i<index.length(); i++) { 134 char c = index.charAt(i); 135 if(c<'9') { 136 number = c; 137 } else { 138 SOUNDEX_INDEX[c] = number; 139 SOUNDEX_INDEX[Character.toLowerCase(c)] = number; 140 } 141 } 142 } 143 144 static { 145 functions = new HashMap (); 146 addFunction("ABS", ABS, 1, Value.NULL); 147 addFunction("ACOS", ACOS, 1, Value.DOUBLE); 148 addFunction("ASIN", ASIN, 1, Value.DOUBLE); 149 addFunction("ATAN", ATAN, 1, Value.DOUBLE); 150 addFunction("ATAN2", ATAN2, 2, Value.DOUBLE); 151 addFunction("BITAND", BITAND, 2, Value.INT); 152 addFunction("BITOR", BITOR, 2, Value.INT); 153 addFunction("BITXOR", BITXOR, 2, Value.INT); 154 addFunction("CEILING", CEILING, 1, Value.DOUBLE); 155 addFunction("COS", COS, 1, Value.DOUBLE); 156 addFunction("COT", COT, 1, Value.DOUBLE); 157 addFunction("DEGREES", DEGREES, 1, Value.DOUBLE); 158 addFunction("EXP", EXP, 1, Value.DOUBLE); 159 addFunction("FLOOR", FLOOR, 1, Value.DOUBLE); 160 addFunction("LOG", LOG, 1, Value.DOUBLE); 161 addFunction("LOG10", LOG10, 1, Value.DOUBLE); 162 addFunction("MOD", MOD, 2, Value.INT); 163 addFunction("PI", PI, 0, Value.DOUBLE); 164 addFunction("POWER", POWER, 2, Value.DOUBLE); 165 addFunction("RADIANS", RADIANS, 1, Value.DOUBLE); 166 addFunctionNotConst("RAND", RAND, VARARGS, Value.DOUBLE); addFunction("ROUND", ROUND, 2, Value.DOUBLE); 168 addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE); 169 addFunction("SIGN", SIGN, 1, Value.INT); 170 addFunction("SIN", SIN, 1, Value.DOUBLE); 171 addFunction("SQRT", SQRT, 1, Value.DOUBLE); 172 addFunction("TAN", TAN, 1, Value.DOUBLE); 173 addFunction("TRUNCATE", TRUNCATE, 2, Value.DOUBLE); 174 addFunction("HASH", HASH, 3, Value.BYTES); 175 addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES); 176 addFunction("DECRYPT", DECRYPT, 3, Value.BYTES); 177 addFunctionNotConst("SECURE_RAND", SECURE_RAND, 1, Value.BYTES); 178 addFunction("COMPRESS", COMPRESS, VARARGS, Value.BYTES); 179 addFunction("EXPAND", EXPAND, 1, Value.BYTES); 180 addFunction("ZERO", ZERO, 0, Value.INT); 181 addFunctionNotConst("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID); 182 addFunctionNotConst("SYS_GUID", RANDOM_UUID, 0, Value.UUID); 183 addFunction("ASCII", ASCII, 1, Value.INT); 185 addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.INT); 186 addFunction("CHAR", CHAR, 1, Value.STRING); 187 addFunction("CHAR_LENGTH", CHAR_LENGTH, 1, Value.INT); 188 addFunction("CHARACTER_LENGTH", CHAR_LENGTH, 1, Value.INT); addFunctionWithNull("CONCAT", CONCAT, VARARGS, Value.STRING); 190 addFunction("DIFFERENCE", DIFFERENCE, 2, Value.INT); 191 addFunction("HEXTORAW", HEXTORAW, 1, Value.STRING); 192 addFunctionWithNull("INSERT", INSERT, 4, Value.STRING); 193 addFunction("LCASE", LCASE, 1, Value.STRING); 194 addFunction("LEFT", LEFT, 2, Value.STRING); 195 addFunction("LENGTH", LENGTH, 1, Value.INT); 196 addFunction("LOCATE", LOCATE, VARARGS, Value.INT); addFunction("POSITION", LOCATE, 2, Value.INT); addFunction("INSTR", INSTR, VARARGS, Value.INT); 199 addFunction("LTRIM", LTRIM, VARARGS, Value.STRING); 200 addFunction("OCTET_LENGTH", OCTET_LENGTH, 1, Value.INT); 201 addFunction("RAWTOHEX", RAWTOHEX, 1, Value.STRING); 202 addFunction("REPEAT", REPEAT, 2, Value.STRING); 203 addFunctionWithNull("REPLACE", REPLACE, VARARGS, Value.STRING); 204 addFunction("RIGHT", RIGHT, 2, Value.STRING); 205 addFunction("RTRIM", RTRIM, VARARGS, Value.STRING); 206 addFunction("SOUNDEX", SOUNDEX, 1, Value.STRING); 207 addFunction("SPACE", SPACE, 1, Value.STRING); 208 addFunction("SUBSTR", SUBSTR, VARARGS, Value.STRING); 209 addFunction("SUBSTRING", SUBSTRING, VARARGS, Value.STRING); 210 addFunction("UCASE", UCASE, 1, Value.STRING); 211 addFunction("LOWER", LOWER, 1, Value.STRING); 212 addFunction("UPPER", UPPER, 1, Value.STRING); 213 addFunction("POSITION", POSITION, 2, Value.INT); 214 addFunction("TRIM", TRIM, VARARGS, Value.STRING); 215 addFunction("STRINGENCODE", STRINGENCODE, 1, Value.STRING); 216 addFunction("STRINGDECODE", STRINGDECODE, 1, Value.STRING); 217 addFunction("STRINGTOUTF8", STRINGTOUTF8, 1, Value.BYTES); 218 addFunction("UTF8TOSTRING", UTF8TOSTRING, 1, Value.STRING); 219 addFunction("XMLATTR", XMLATTR, 2, Value.STRING); 220 addFunctionWithNull("XMLNODE", XMLNODE, VARARGS, Value.STRING); 221 addFunction("XMLCOMMENT", XMLCOMMENT, 1, Value.STRING); 222 addFunction("XMLCDATA", XMLCDATA, 1, Value.STRING); 223 addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING); 224 addFunction("XMLTEXT", XMLTEXT, 1, Value.STRING); 225 226 addFunctionNotConst("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE); 228 addFunctionNotConst("CURDATE", CURDATE, 0, Value.DATE); 229 addFunctionNotConst("CURRENT_TIME", CURRENT_TIME, 0, Value.TIME); 230 addFunctionNotConst("CURTIME", CURTIME, 0, Value.TIME); 231 addFunctionNotConst("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP, VARARGS, Value.TIMESTAMP); 232 addFunctionNotConst("NOW", NOW, VARARGS, Value.TIMESTAMP); 233 addFunction("DATEADD", DATEADD, 3, Value.TIMESTAMP); 234 addFunction("DATEDIFF", DATEDIFF, 3, Value.LONG); 235 addFunction("DAYNAME", DAYNAME, 1, Value.STRING); 236 addFunction("DAY", DAYOFMONTH, 1, Value.INT); 237 addFunction("DAYOFMONTH", DAYOFMONTH, 1, Value.INT); 238 addFunction("DAYOFWEEK", DAYOFWEEK, 1, Value.INT); 239 addFunction("DAYOFYEAR", DAYOFYEAR, 1, Value.INT); 240 addFunction("HOUR", HOUR, 1, Value.INT); 241 addFunction("MINUTE", MINUTE, 1, Value.INT); 242 addFunction("MONTH", MONTH, 1, Value.INT); 243 addFunction("MONTHNAME", MONTHNAME, 1, Value.STRING); 244 addFunction("QUARTER", QUARTER, 1, Value.INT); 245 addFunction("SECOND", SECOND, 1, Value.INT); 246 addFunction("WEEK", WEEK, 1, Value.INT); 247 addFunction("YEAR", YEAR, 1, Value.INT); 248 addFunction("EXTRACT", EXTRACT, 2, Value.INT); 249 addFunctionWithNull("FORMATDATETIME", FORMATDATETIME, VARARGS, Value.STRING); 250 addFunctionWithNull("PARSEDATETIME", PARSEDATETIME, VARARGS, Value.TIMESTAMP); 251 addFunctionNotConst("DATABASE", DATABASE, 0, Value.STRING); 253 addFunctionNotConst("USER", USER, 0, Value.STRING); 254 addFunctionNotConst("CURRENT_USER", CURRENT_USER, 0, Value.STRING); 255 addFunctionNotConst("IDENTITY", IDENTITY, 0, Value.LONG); 256 addFunctionNotConst("IDENTITY_VAL_LOCAL", IDENTITY, 0, Value.LONG); 257 addFunctionNotConst("LAST_INSERT_ID", IDENTITY, 0, Value.LONG); 258 addFunctionNotConst("AUTOCOMMIT", AUTOCOMMIT, 0, Value.BOOLEAN); 259 addFunctionNotConst("READONLY", READONLY, 0, Value.BOOLEAN); 260 addFunction("DATABASE_PATH", DATABASE_PATH, 0, Value.STRING); 261 addFunction("LOCK_TIMEOUT", LOCK_TIMEOUT, 0, Value.INT); 262 addFunctionWithNull("IFNULL", IFNULL, 2, Value.NULL); 263 addFunctionWithNull("CASEWHEN", CASEWHEN, 3, Value.NULL); 264 addFunctionWithNull("CONVERT", CONVERT, 1, Value.NULL); 265 addFunctionWithNull("CAST", CAST, 1, Value.NULL); 266 addFunctionWithNull("COALESCE", COALESCE, VARARGS, Value.NULL); 267 addFunctionWithNull("NVL", COALESCE, VARARGS, Value.NULL); 268 addFunctionWithNull("NULLIF", NULLIF, 2, Value.NULL); 269 addFunctionWithNull("CASE", CASE, VARARGS, Value.NULL); 270 addFunctionNotConst("NEXTVAL", NEXTVAL, VARARGS, Value.LONG); 271 addFunctionNotConst("CURRVAL", CURRVAL, VARARGS, Value.LONG); 272 addFunction("ARRAY_GET", ARRAY_GET, 2, Value.NULL); 273 addFunction("CSVREAD", CSVREAD, VARARGS, Value.RESULT_SET, false, false); 274 addFunction("CSVWRITE", CSVWRITE, VARARGS, Value.RESULT_SET, false, false); 275 addFunctionNotConst("MEMORY_FREE", MEMORY_FREE, 0, Value.INT); 276 addFunctionNotConst("MEMORY_USED", MEMORY_USED, 0, Value.INT); 277 addFunctionNotConst("LOCK_MODE", LOCK_MODE, 0, Value.INT); 278 addFunctionNotConst("SCHEMA", SCHEMA, 0, Value.STRING); 279 addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT); 280 addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT); 281 } 282 283 private static void addFunction(String name, int type, int parameterCount, 284 int dataType, boolean nullIfParameterIsNull, boolean isDeterm) { 285 FunctionInfo info = new FunctionInfo(); 286 info.name = name; 287 info.type = type; 288 info.parameterCount = parameterCount; 289 info.dataType = dataType; 290 info.nullIfParameterIsNull = nullIfParameterIsNull; 291 info.isDeterministic = isDeterm; 292 functions.put(name, info); 293 } 294 295 private static void addFunctionNotConst(String name, int type, int parameterCount, 296 int dataType) { 297 addFunction(name, type, parameterCount, dataType, true, false); 298 } 299 300 private static void addFunction(String name, int type, int parameterCount, 301 int dataType) { 302 addFunction(name, type, parameterCount, dataType, true, true); 303 } 304 305 private static void addFunctionWithNull(String name, int type, 306 int parameterCount, int dataType) { 307 addFunction(name, type, parameterCount, dataType, false, true); 308 } 309 310 public static Function getFunction(Database database, String name) throws SQLException { 311 FunctionInfo info = (FunctionInfo) functions.get(name); 312 if(info==null) { 313 return null; 314 } 315 return new Function(database, info); 316 } 317 318 private Function(Database database, FunctionInfo info) { 319 this.database = database; 320 this.info = info; 321 if(info.parameterCount == VARARGS) { 322 varargs = new ObjectArray(); 323 } else { 324 args = new Expression[info.parameterCount]; 325 } 326 } 327 328 public void setParameter(int index, Expression param) throws SQLException { 329 if(varargs != null) { 330 varargs.add(param); 331 } else { 332 if(index >= args.length) { 333 throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, ""+args.length); 334 } 335 args[index] = param; 336 } 337 } 338 339 private strictfp double log10(double value) { 340 return roundmagic(StrictMath.log(value) / StrictMath.log(10)); 341 } 342 343 public Value getValue(Session session) throws SQLException { 344 return getValueWithArgs(session, args); 345 } 346 347 public Value getValueWithArgs(Session session, Expression[] args) throws SQLException { 348 if (info.nullIfParameterIsNull) { 349 for (int i = 0; i < args.length; i++) { 350 Expression e = args[i]; 351 if (e != null && e.getValue(session) == ValueNull.INSTANCE) { 352 return ValueNull.INSTANCE; 353 } 354 } 355 } 356 Value v0 = args.length < 1 || args[0] == null ? null : args[0].getValue(session); 357 switch (info.type) { 358 case IFNULL: 359 return v0 == ValueNull.INSTANCE ? args[1].getValue(session) : v0; 360 case CASEWHEN: { 361 if(v0 == ValueNull.INSTANCE) { 362 return v0; 363 } 364 Expression result = v0.getBoolean().booleanValue() ? args[1] : args[2]; 365 return result.getValue(session); 366 } 367 case COALESCE: { 368 for (int i = 0; i < args.length; i++) { 369 Value v = i==0 ? v0 : args[i].getValue(session); 370 if (!(v == ValueNull.INSTANCE)) { 371 return v.convertTo(dataType); 372 } 373 } 374 return v0; 375 } 376 case CASE: { 377 int i = 0; 379 for (; i < args.length; i++) { 380 Value when = args[i++].getValue(session); 381 if (Boolean.TRUE.equals(when)) { 382 return args[i].getValue(session); 383 } 384 } 385 return i < args.length ? args[i].getValue(session) : ValueNull.INSTANCE; 386 } 387 case ARRAY_GET: { 388 if(v0.getType() == Value.ARRAY) { 389 Value v1 = args[1].getValue(session); 390 int element = v1.getInt(); 391 Value[] list = ((ValueArray) v0).getList(); 392 if(element < 1 || element > list.length) { 393 return ValueNull.INSTANCE; 394 } 395 return list[element-1]; 396 } 397 return ValueNull.INSTANCE; 398 } 399 case ARRAY_LENGTH: { 400 if(v0.getType() == Value.ARRAY) { 401 Value[] list = ((ValueArray) v0).getList(); 402 return ValueInt.get(list.length); 403 } 404 return ValueNull.INSTANCE; 405 } 406 default: 407 } 409 Value v1 = args.length < 2 || args[1] == null ? null : args[1].getValue(session); 410 Value v2 = args.length < 3 || args[2] == null ? null : args[2].getValue(session); 411 switch (info.type) { 412 case ABS: 413 return v0.getSignum() > 0 ? v0 : v0.negate(); 414 case ACOS: 415 return ValueDouble.get(Math.acos(v0.getDouble())); 416 case ASIN: 417 return ValueDouble.get(Math.asin(v0.getDouble())); 418 case ATAN: 419 return ValueDouble.get(Math.atan(v0.getDouble())); 420 case ATAN2: 421 return ValueDouble.get(Math.atan2(v0.getDouble(), v1.getDouble())); 422 case BITAND: 423 return ValueInt.get(v0.getInt() & v1.getInt()); 424 case BITOR: 425 return ValueInt.get(v0.getInt() | v1.getInt()); 426 case BITXOR: 427 return ValueInt.get(v0.getInt() ^ v1.getInt()); 428 case CEILING: 429 return ValueDouble.get(Math.ceil(v0.getDouble())); 430 case COS: 431 return ValueDouble.get(Math.cos(v0.getDouble())); 432 case COT: { 433 double d = Math.tan(v0.getDouble()); 434 if (d == 0.0) { 435 throw Message.getSQLException(Message.DIVISION_BY_ZERO_1, getSQL()); 436 } 437 return ValueDouble.get(1. / d); 438 } 439 case DEGREES: 440 return ValueDouble.get(Math.toDegrees(v0.getDouble())); 441 case EXP: 442 return ValueDouble.get(Math.exp(v0.getDouble())); 443 case FLOOR: 444 return ValueDouble.get(Math.floor(v0.getDouble())); 445 case LOG: 446 return ValueDouble.get(Math.log(v0.getDouble())); 447 case LOG10: 448 return ValueDouble.get(log10(v0.getDouble())); 449 case MOD: { 450 int x = v1.getInt(); 451 if (x == 0.0) { 452 throw Message.getSQLException(Message.DIVISION_BY_ZERO_1, getSQL()); 453 } 454 return ValueInt.get(v0.getInt() % x); 455 } 456 case PI: 457 return ValueDouble.get(Math.PI); 458 case POWER: 459 return ValueDouble.get(Math.pow(v0.getDouble(), v1.getDouble())); 460 case RADIANS: 461 return ValueDouble.get(Math.toRadians(v0.getDouble())); 462 case RAND: { 463 if(v0 != null) { 464 session.getRandom().setSeed(v0.getInt()); 465 } 466 return ValueDouble.get(session.getRandom().nextDouble()); 468 } 469 case ROUND: { 470 double f = Math.pow(10., v1.getDouble()); 471 return ValueDouble.get(Math.round(v0.getDouble() * f) / f); 472 } 473 case ROUNDMAGIC: 474 return ValueDouble.get(roundmagic(v0.getDouble())); 475 case SIGN: 476 return ValueInt.get(v0.getSignum()); 477 case SIN: 478 return ValueDouble.get(Math.sin(v0.getDouble())); 479 case SQRT: 480 return ValueDouble.get(Math.sqrt(v0.getDouble())); 481 case TAN: 482 return ValueDouble.get(Math.tan(v0.getDouble())); 483 case TRUNCATE: { 484 double d = v0.getDouble(); 485 int p = v1.getInt(); 486 double f = Math.pow(10., p); 487 double g = d * f; 488 return ValueDouble.get(((d < 0) ? Math.ceil(g) : Math.floor(g)) / f); 489 } 490 case SECURE_RAND: 491 return ValueBytes.getNoCopy(RandomUtils.getSecureBytes(v0.getInt())); 492 case HASH: 493 return ValueBytes.getNoCopy(getHash(v0.getString(), v1.getBytesNoCopy(), v2.getInt())); 494 case ENCRYPT: 495 return ValueBytes.getNoCopy(encrypt(v0.getString(), v1.getBytesNoCopy(), v2.getBytesNoCopy())); 496 case DECRYPT: 497 return ValueBytes.getNoCopy(decrypt(v0.getString(), v1.getBytesNoCopy(), v2.getBytesNoCopy())); 498 case COMPRESS: { 499 String algorithm = null; 500 if(v1 != null) { 501 algorithm = v1.getString(); 502 } 503 return ValueBytes.getNoCopy(CompressTool.getInstance().compress(v0.getBytesNoCopy(), algorithm)); 504 } 505 case EXPAND: 506 return ValueBytes.getNoCopy(CompressTool.getInstance().expand(v0.getBytesNoCopy())); 507 case ZERO: 508 return ValueInt.get(0); 509 case RANDOM_UUID: 510 return ValueUuid.getNewRandom(); 511 case ASCII: { 513 String s = v0.getString(); 514 if (s.length() == 0) { 515 return ValueNull.INSTANCE; 516 } 517 return ValueInt.get(s.charAt(0)); 518 } 519 case BIT_LENGTH: 520 return ValueInt.get(16 * length(v0)); 521 case CHAR: 522 return ValueString.get(String.valueOf((char) v0.getInt())); 523 case CHAR_LENGTH: 524 case LENGTH: 525 return ValueInt.get(length(v0)); 526 case OCTET_LENGTH: 527 return ValueInt.get(2 * length(v0)); 528 case CONCAT: { 529 Value concat = ValueNull.INSTANCE; 530 for (int i = 0; i < args.length; i++) { 531 Value v = args[i].getValue(session); 532 if (v == ValueNull.INSTANCE) { 533 continue; 534 } 535 if(concat == ValueNull.INSTANCE) { 536 concat = v; 537 } else { 538 concat = ValueString.get(concat.getString().concat(v.getString())); 539 } 540 } 541 return concat; 542 } 543 case DIFFERENCE: 544 return ValueInt.get(getDifference(v0.getString(), v1.getString())); 545 case HEXTORAW: 546 return ValueString.get(hexToRaw(v0.getString())); 547 case INSERT: { 548 if (v1 == ValueNull.INSTANCE || v2 == ValueNull.INSTANCE) { 549 return v1; 550 } 551 Value v3 = args[3].getValue(session); 552 return ValueString.get(insert(v0.getString(), v1.getInt(), v2.getInt(), v3.getString())); 553 } 554 case LOWER: 555 case LCASE: 556 return ValueString.get(v0.getString().toLowerCase()); 558 case LEFT: 559 return ValueString.get(left(v0.getString(), v1.getInt())); 560 case LOCATE: { 561 int start = v2 == null ? 0 : v2.getInt(); 562 return ValueInt.get(locate(v0.getString(), v1.getString(), start)); 563 } 564 case INSTR: { 565 int start = v2 == null ? 0 : v2.getInt(); 566 return ValueInt.get(locate(v1.getString(), v0.getString(), start)); 567 } 568 case RAWTOHEX: 569 return ValueString.get(rawToHex(v0.getString())); 570 case REPEAT: { 571 int count = Math.max(0, v1.getInt()); 573 return ValueString.get(repeat(v0.getString(), count)); 574 } 575 case REPLACE: { 576 String s0 = v0 == ValueNull.INSTANCE ? "" : v0.getString(); 577 String s1 = v1 == ValueNull.INSTANCE ? "" : v1.getString(); 578 String s2 = (v2==null || v2 == ValueNull.INSTANCE) ? "" : v2.getString(); 579 return ValueString.get(replace(s0, s1, s2)); 580 } 581 case RIGHT: 582 return ValueString.get(right(v0.getString(), v1.getInt())); 583 case LTRIM: 584 return ValueString.get(trim(v0.getString(), true, false, v1 == null ? " " : v1.getString())); 585 case TRIM: 586 return ValueString.get(trim(v0.getString(), true, true, v1 == null ? " " : v1.getString())); 587 case RTRIM: 588 return ValueString.get(trim(v0.getString(), false, true, v1 == null ? " " : v1.getString())); 589 case SOUNDEX: 590 return ValueString.get(getSoundex(v0.getString())); 591 case SPACE: { 592 int len = Math.max(0, v0.getInt()); 594 char[] chars = new char[len]; 595 for (int i = len - 1; i >= 0; i--) { 596 chars[i] = ' '; 597 } 598 return ValueString.get(new String (chars)); 599 } 600 case SUBSTR: 601 case SUBSTRING: { 602 String s = v0.getString(); 603 int length = v2 == null ? s.length() : v2.getInt(); 604 return ValueString.get(substring(s, v1.getInt(), length)); 605 } 606 case POSITION: 607 return ValueInt.get(locate(v0.getString(), v1.getString(), 0)); 608 case UPPER: 609 case UCASE: 610 return ValueString.get(v0.getString().toUpperCase()); 612 case STRINGENCODE: 613 return ValueString.get(StringUtils.javaEncode(v0.getString())); 614 case STRINGDECODE: 615 return ValueString.get(StringUtils.javaDecode(v0.getString())); 616 case STRINGTOUTF8: 617 return ValueBytes.getNoCopy(StringUtils.utf8Encode(v0.getString())); 618 case UTF8TOSTRING: 619 return ValueString.get(StringUtils.utf8Decode(v0.getBytesNoCopy())); 620 case XMLATTR: 621 return ValueString.get(StringUtils.xmlAttr(v0.getString(), v1.getString())); 622 case XMLNODE: { 623 String attr = v1 == null ? null : v1 == ValueNull.INSTANCE ? null : v1.getString(); 624 String content = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString(); 625 return ValueString.get(StringUtils.xmlNode(v0.getString(), attr, content)); 626 } 627 case XMLCOMMENT: 628 return ValueString.get(StringUtils.xmlComment(v0.getString())); 629 case XMLCDATA: 630 return ValueString.get(StringUtils.xmlCData(v0.getString())); 631 case XMLSTARTDOC: 632 return ValueString.get(StringUtils.xmlStartDoc()); 633 case XMLTEXT: 634 return ValueString.get(StringUtils.xmlText(v0.getString())); 635 case DATEADD: 637 return ValueTimestamp.getNoCopy(dateadd(v0.getString(), v1.getInt(), v2.getTimestampNoCopy())); 638 case DATEDIFF: 639 return ValueLong.get(datediff(v0.getString(), v1.getTimestampNoCopy(), v2.getTimestampNoCopy())); 640 case DAYNAME: 641 return ValueString.get(FORMAT_DAYNAME.format(v0.getDateNoCopy())); 642 case DAYOFMONTH: 643 return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_MONTH)); 644 case DAYOFWEEK: 645 return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_WEEK)); 646 case DAYOFYEAR: 647 return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.DAY_OF_YEAR)); 648 case HOUR: 649 return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY)); 650 case MINUTE: 651 return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE)); 652 case MONTH: 653 return ValueInt.get(getDatePart(v0.getTimestampNoCopy(), Calendar.MONTH)); 654 case MONTHNAME: 655 return ValueString.get(FORMAT_MONTHNAME.format(v0.getDateNoCopy())); 656 case QUARTER: 657 return ValueInt.get((getDatePart(v0.getTimestamp(), Calendar.MONTH) - 1) / 3 + 1); 658 case SECOND: 659 return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.SECOND)); 660 case WEEK: 661 return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.WEEK_OF_YEAR)); 662 case YEAR: 663 return ValueInt.get(getDatePart(v0.getTimestamp(), Calendar.YEAR)); 664 case CURDATE: 665 case CURRENT_DATE: 666 return ValueDate.get(new Date (System.currentTimeMillis())); 668 case CURTIME: 669 case CURRENT_TIME: 670 return ValueTime.get(new Time (System.currentTimeMillis())); 672 case NOW: 673 case CURRENT_TIMESTAMP: { 674 ValueTimestamp vt = ValueTimestamp.getNoCopy(new Timestamp (System.currentTimeMillis())); 675 if(v0 != null) { 676 vt = (ValueTimestamp)vt.convertScale(Mode.getCurrentMode().convertOnlyToSmallerScale, v0.getInt()); 677 } 678 return vt; 679 } 680 case EXTRACT: { 681 int field = getDatePart(v0.getString()); 682 return ValueInt.get(getDatePart(v1.getTimestamp(), field)); 683 } 684 case FORMATDATETIME: { 685 if(v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) { 686 return ValueNull.INSTANCE; 687 } 688 String locale = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString(); 689 Value v3 = args.length <= 3 ? null : args[3].getValue(session); 690 String tz = v3 == null ? null : v3 == ValueNull.INSTANCE ? null : v3.getString(); 691 return ValueString.get(StringUtils.formatDateTime(v0.getTimestamp(), v1.getString(), locale, tz)); 692 } 693 case PARSEDATETIME: { 694 if(v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) { 695 return ValueNull.INSTANCE; 696 } 697 String locale = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString(); 698 Value v3 = args.length <= 3 ? null : args[3].getValue(session); 699 String tz = v3 == null ? null : v3 == ValueNull.INSTANCE ? null : v3.getString(); 700 java.util.Date d = StringUtils.parseDateTime(v0.getString(), v1.getString(), locale, tz); 701 return ValueTimestamp.getNoCopy(new Timestamp (d.getTime())); 702 } 703 case DATABASE: 705 return ValueString.get(database.getShortName()); 706 case USER: 707 case CURRENT_USER: 708 return ValueString.get(session.getUser().getName()); 709 case IDENTITY: 710 return ValueLong.get(session.getLastIdentity()); 711 case AUTOCOMMIT: 712 return ValueBoolean.get(session.getAutoCommit()); 713 case READONLY: 714 return ValueBoolean.get(database.getReadOnly()); 715 case DATABASE_PATH: { 716 String path = database.getDatabasePath(); 717 return path == null ? (Value)ValueNull.INSTANCE : ValueString.get(path); 718 } 719 case LOCK_TIMEOUT: 720 return ValueInt.get(session.getLockTimeout()); 721 case NULLIF: 722 return database.areEqual(v0, v1) ? ValueNull.INSTANCE : v0; 723 case CAST: 724 case CONVERT: { 726 v0 = v0.convertTo(dataType); 727 v0 = v0.convertScale(Mode.getCurrentMode().convertOnlyToSmallerScale, scale); 728 v0 = v0.convertPrecision(precision); 729 return v0; 730 } 731 case NEXTVAL: { 732 Sequence sequence = getSequence(session, v0, v1); 733 SequenceValue value = new SequenceValue(sequence); 734 return value.getValue(session); 735 } 736 case CURRVAL: { 737 Sequence sequence = getSequence(session, v0, v1); 738 return ValueLong.get(sequence.getCurrentValue()); 739 } 740 case CSVREAD: { 741 String fileName = v0.getString(); 742 String columnList = v1 == null ? null : v1.getString(); 743 String [] columns = StringUtils.arraySplit(columnList, ',', true); 744 String charset = v2 == null ? null : v2.getString(); 745 ValueResultSet vr = ValueResultSet.get(Csv.getInstance().read(fileName, columns, charset)); 746 return vr; 747 } 748 case CSVWRITE: { 749 Connection conn = session.createConnection(false); 750 String charset = v2 == null ? null : v2.getString(); 751 Csv.getInstance().write(conn, v0.getString(), v1.getString(), charset); 752 return ValueNull.INSTANCE; 753 } 754 case MEMORY_FREE: 755 session.getUser().checkAdmin(); 756 return ValueInt.get(MemoryUtils.getMemoryFree()); 757 case MEMORY_USED: 758 session.getUser().checkAdmin(); 759 return ValueInt.get(MemoryUtils.getMemoryUsed()); 760 case LOCK_MODE: 761 return ValueInt.get(database.getLockMode()); 762 case SCHEMA: 763 return ValueString.get(session.getCurrentSchemaName()); 764 case SESSION_ID: 765 return ValueInt.get(session.getId()); 766 default: 767 throw Message.getInternalError("type=" + info.type); 768 } 769 } 770 771 Sequence getSequence(Session session, Value v0, Value v1) throws SQLException { 772 String schemaName, sequenceName; 773 if(v1 == null) { 774 schemaName = session.getCurrentSchemaName(); 775 sequenceName = StringUtils.toUpperEnglish(v0.getString()); 776 } else { 777 schemaName = v0.getString(); 778 sequenceName = v1.getString(); 779 } 780 return database.getSchema(schemaName).getSequence(sequenceName); 781 } 782 783 private int length(Value v) throws SQLException { 784 switch(v.getType()) { 785 case Value.BLOB: 786 case Value.CLOB: 787 case Value.BYTES: 788 case Value.JAVA_OBJECT: 789 return (int)v.getPrecision(); 790 } 791 return v.getString().length(); 792 } 793 794 private byte[] getPaddedArrayCopy(byte[] data, int blockSize) { 795 int size = MathUtils.roundUp(data.length, blockSize); 796 byte[] newData = new byte[size]; 797 System.arraycopy(data, 0, newData, 0, data.length); 798 return newData; 799 } 800 801 private byte[] decrypt(String algorithm, byte[] key, byte[] data) throws SQLException { 802 BlockCipher cipher = CipherFactory.getBlockCipher(algorithm); 803 byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength()); 804 cipher.setKey(newKey); 805 byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN); 806 cipher.decrypt(newData, 0, newData.length); 807 return newData; 808 } 809 810 private byte[] encrypt(String algorithm, byte[] key, byte[] data) throws SQLException { 811 BlockCipher cipher = CipherFactory.getBlockCipher(algorithm); 812 byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength()); 813 cipher.setKey(newKey); 814 byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN); 815 cipher.encrypt(newData, 0, newData.length); 816 return newData; 817 } 818 819 private byte[] getHash(String algorithm, byte[] bytes, int iterations) throws SQLException { 820 SHA256 hash = CipherFactory.getHash(algorithm); 821 for(int i=0; i<iterations; i++) { 822 bytes = hash.getHash(bytes); 823 } 824 return bytes; 825 } 826 827 private static int getDatePart(Timestamp d, int field) { 828 Calendar c = Calendar.getInstance(); 829 c.setTime(d); 830 int value = c.get(field); 831 if(field == Calendar.MONTH) { 832 value++; 833 } 834 return value; 835 } 836 837 879 private static int getDatePart(String part) throws SQLException { 880 Integer p = (Integer ) datePart.get(StringUtils.toUpperEnglish(part)); 881 if(p==null) { 882 throw Message.getSQLException(Message.INVALID_VALUE_2, new String [] { "part", part }, null); 883 } 884 return p.intValue(); 885 } 886 887 private static Timestamp dateadd(String part, int count, Timestamp d) throws SQLException { 888 int field = getDatePart(part); 889 Calendar calendar = Calendar.getInstance(); 890 int nanos = d.getNanos() % 1000000; 891 calendar.setTime(d); 892 calendar.add(field, count); 893 calendar.get(Calendar.YEAR); 895 calendar.get(Calendar.HOUR_OF_DAY); 896 long t = calendar.getTime().getTime(); 897 Timestamp ts = new Timestamp (t); 898 ts.setNanos(ts.getNanos() + nanos); 899 return ts; 900 } 901 902 private static long datediff(String part, Timestamp d1, Timestamp d2) throws SQLException { 903 int field = getDatePart(part); 905 Calendar calendar = Calendar.getInstance(); 906 long t1 = d1.getTime(), t2 = d2.getTime(); 907 TimeZone zone = calendar.getTimeZone(); 909 calendar.setTime(d1); 910 t1 += zone.getOffset(calendar.get(Calendar.ERA), calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 911 calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK), calendar.get(Calendar.MILLISECOND)); 912 calendar.setTime(d2); 913 t2 += zone.getOffset(calendar.get(Calendar.ERA), calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 914 calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK), calendar.get(Calendar.MILLISECOND)); 915 switch (field) { 916 case Calendar.MILLISECOND: 917 return t2 - t1; 918 case Calendar.SECOND: 919 case Calendar.MINUTE: 920 case Calendar.HOUR: { 921 long hour = 60*60*1000; 923 long add = Math.min(t1/hour*hour, t2/hour*hour); 924 t1 -= add; 925 t2 -= add; 926 switch(field) { 927 case Calendar.SECOND: 928 return t2 / 1000 - t1 / 1000; 929 case Calendar.MINUTE: 930 return t2 / (60 * 1000) - t1 / (60 * 1000); 931 case Calendar.HOUR: 932 return t2/hour - t1/hour; 933 default: 934 throw Message.getInternalError("field:" + field); 935 } 936 } 937 case Calendar.DATE: 938 return t2 / (24 * 60 * 60 * 1000) - t1 / (24 * 60 * 60 * 1000); 939 } 940 calendar.setTime(new Timestamp (t1)); 941 int year1 = calendar.get(Calendar.YEAR); 942 int month1 = calendar.get(Calendar.MONTH); 943 calendar.setTime(new Timestamp (t2)); 944 int year2 = calendar.get(Calendar.YEAR); 945 int month2 = calendar.get(Calendar.MONTH); 946 int result = year2 - year1; 947 if (field == Calendar.MONTH) { 948 result = 12 * result + (month2 - month1); 949 } 950 return result; 951 } 952 953 private static String substring(String s, int start, int length) { 954 int len = s.length(); 955 start--; 956 if(start < 0) { 957 start = 0; 958 } 959 if(length < 0) { 960 length = 0; 961 } 962 start = (start > len) ? len : start; 963 if (start + length > len) { 964 length = len - start; 965 } 966 return s.substring(start, start + length); 967 } 968 969 private static String trim(String s, boolean leading, boolean trailing, String sp) { 970 char space = (sp == null || sp.length() < 1) ? ' ' : sp.charAt(0); 971 if(leading) { 973 int len = s.length(), i = 0; 974 while (i < len && s.charAt(i) == space) { 975 i++; 976 } 977 s = (i == 0) ? s : s.substring(i); 978 } 979 if(trailing) { 980 int endindex = s.length() - 1; 981 int i = endindex; 982 while (i >= 0 && s.charAt(i) == space) { 983 i--; 984 } 985 s = i == endindex ? s : s.substring(0, i + 1); 986 } 987 return s; 988 } 989 990 private static String replace(String s, String replace, String with) { 991 if(replace == null || replace.length()==0) { 992 return s; 994 } 995 StringBuffer buff = new StringBuffer (); 996 int start = 0; 997 int len = replace.length(); 998 while (true) { 999 int i = s.indexOf(replace, start); 1000 if (i == -1) { 1001 break; 1002 } 1003 buff.append(s.substring(start, i)); 1004 buff.append(with); 1005 start = i + len; 1006 } 1007 buff.append(s.substring(start)); 1008 return buff.toString(); 1009 } 1010 1011 private static String repeat(String s, int count) { 1012 StringBuffer buff = new StringBuffer (s.length() * count); 1013 while (count-- > 0) { 1014 buff.append(s); 1015 } 1016 return buff.toString(); 1017 } 1018 1019 private static String rawToHex(String s) { 1020 StringBuffer buff = new StringBuffer (4 * s.length()); 1021 for (int i = 0; i < s.length(); i++) { 1022 String hex = Integer.toHexString(s.charAt(i) & 0xffff); 1023 for (int j = hex.length(); j < 4; j++) { 1024 buff.append('0'); 1025 } 1026 buff.append(hex); 1027 } 1028 return buff.toString(); 1029 } 1030 1031 private static int locate(String search, String s, int start) { 1032 int i = (start < 0) ? 0 : start - 1; 1033 return s.indexOf(search, i) + 1; 1034 } 1035 1036 private static String right(String s, int count) { 1037 if (count < 0) { 1038 count = 0; 1039 } else if (count > s.length()) { 1040 count = s.length(); 1041 } 1042 return s.substring(s.length() - count); 1043 } 1044 1045 private static String left(String s, int count) { 1046 if (count < 0) { 1047 count = 0; 1048 } else if (count > s.length()) { 1049 count = s.length(); 1050 } 1051 return s.substring(0, count); 1052 } 1053 1054 private static String insert(String s1, int start, int length, String s2) { 1055 if (s1 == null) { 1056 return s2; 1057 } 1058 if (s2 == null) { 1059 return s1; 1060 } 1061 int len1 = s1.length(); 1062 int len2 = s2.length(); 1063 start--; 1064 if (start < 0 || length <= 0 || len2 == 0 || start > len1) { 1065 return s1; 1066 } 1067 if (start + length > len1) { 1068 length = len1 - start; 1069 } 1070 return s1.substring(0, start) + s2 + s1.substring(start + length); 1071 } 1072 1073 private static String hexToRaw(String s) throws SQLException { 1074 int len = s.length(); 1076 if (len % 4 != 0) { 1077 throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, s); 1078 } 1079 StringBuffer buff = new StringBuffer (len / 4); 1080 for (int i = 0; i < len; i += 4) { 1081 try { 1082 char raw = (char) Integer.parseInt(s.substring(i, i + 4), 16); 1083 buff.append(raw); 1084 } catch(NumberFormatException e) { 1085 throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, s); 1086 } 1087 } 1088 return buff.toString(); 1089 } 1090 1091 private static int getDifference(String s1, String s2) { 1092 s1 = getSoundex(s1); 1094 s2 = getSoundex(s2); 1095 int e = 0; 1096 for (int i = 0; i < 4; i++) { 1097 if (s1.charAt(i) == s2.charAt(i)) { 1098 e++; 1099 } 1100 } 1101 return e; 1102 } 1103 1104 private double roundmagic(double d) { 1105 if ((d < 0.0000000000001) && (d > -0.0000000000001)) { 1106 return 0.0; 1107 } 1108 if ((d > 1000000000000.) || (d < -1000000000000.)) { 1109 return d; 1110 } 1111 StringBuffer s = new StringBuffer (); 1112 s.append(d); 1113 if(s.toString().indexOf("E") >= 0) { 1114 return d; 1115 } 1116 int len = s.length(); 1117 if (len < 16) { 1118 return d; 1119 } 1120 if(s.toString().indexOf(".") > len-3) { 1121 return d; 1122 } 1123 s.delete(len-2, len); 1124 len -= 2; 1125 char c1 = s.charAt(len - 2); 1126 char c2 = s.charAt(len - 3); 1127 char c3 = s.charAt(len - 4); 1128 if ((c1 == '0') && (c2 == '0') && (c3 == '0')) { 1129 s.setCharAt(len - 1, '0'); 1130 } else if ((c1 == '9') && (c2 == '9') && (c3 == '9')) { 1131 s.setCharAt(len - 1, '9'); 1132 s.append('9'); 1133 s.append('9'); 1134 s.append('9'); 1135 } 1136 return Double.valueOf(s.toString()).doubleValue(); 1137 } 1138 1139 private static String getSoundex(String s) { 1140 int len = s.length(); 1141 char[] chars = new char[] { '0', '0', '0', '0' }; 1142 char lastdigit = '0'; 1143 for (int i = 0, j = 0; i < len && j < 4; i++) { 1144 char c = s.charAt(i); 1145 char newdigit = c > SOUNDEX_INDEX.length ? 0 : SOUNDEX_INDEX[c]; 1146 if(newdigit != 0) { 1147 if (j == 0) { 1148 chars[j++] = c; 1149 lastdigit = newdigit; 1150 } else if (newdigit <= '6') { 1151 if (newdigit != lastdigit) { 1152 chars[j++] = newdigit; 1153 lastdigit = newdigit; 1154 } 1155 } else if (newdigit == '7') { 1156 lastdigit = newdigit; 1157 } 1158 } 1159 } 1160 return new String (chars); 1161 } 1162 1163 public int getType() { 1164 return dataType; 1165 } 1166 1167 public void mapColumns(ColumnResolver resolver, int level) throws SQLException { 1168 for (int i = 0; i < args.length; i++) { 1169 args[i].mapColumns(resolver, level); 1170 } 1171 } 1172 1173 public void doneWithParameters() throws SQLException { 1174 if(info.parameterCount == VARARGS) { 1175 int len = varargs.size(); 1176 int min=0, max=Integer.MAX_VALUE; 1177 switch (info.type) { 1178 case COALESCE: 1179 min = 1; 1180 break; 1181 case NOW: 1182 case CURRENT_TIMESTAMP: 1183 case RAND: 1184 max = 1; 1185 break; 1186 case COMPRESS: 1187 case LTRIM: 1188 case RTRIM: 1189 case TRIM: 1190 max = 2; 1191 break; 1192 case REPLACE: 1193 case LOCATE: 1194 case INSTR: 1195 case SUBSTR: 1196 case SUBSTRING: 1197 min = 2; 1198 max = 3; 1199 break; 1200 case CASE: 1201 case CONCAT: 1202 min = 2; 1203 break; 1204 case CSVREAD: 1205 min = 1; 1206 break; 1207 case CSVWRITE: 1208 min = 2; 1209 break; 1210 case XMLNODE: 1211 min = 1; 1212 max = 3; 1213 break; 1214 case FORMATDATETIME: 1215 case PARSEDATETIME: 1216 min = 2; 1217 max = 4; 1218 break; 1219 case CURRVAL: 1220 case NEXTVAL: 1221 min = 1; 1222 max = 2; 1223 break; 1224 default: 1225 throw Message.getInternalError("type="+info.type); 1226 } 1227 boolean ok = (len >= min) && (len <= max); 1228 if(!ok) { 1229 throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, min + ".." + max); 1230 } 1231 args = new Expression[len]; 1232 varargs.toArray(args); 1233 varargs = null; 1234 } else { 1235 int len = args.length; 1236 if(len>0 && args[len-1] == null) { 1237 throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, ""+len); 1238 } 1239 } 1240 } 1241 1242 public void setDataType(int dataType, long precision, int scale) { 1243 this.dataType = dataType; 1244 this.precision = precision; 1245 this.scale = scale; 1246 } 1247 1248 public void setDataType(Column col) { 1249 dataType = col.getType(); 1250 precision = col.getPrecision(); 1251 scale = col.getScale(); 1252 } 1253 1254 public Expression optimize(Session session) throws SQLException { 1255 boolean allConst = info.isDeterministic; 1256 for(int i=0; i<args.length; i++) { 1257 Expression e = args[i].optimize(session); 1258 args[i] = e; 1259 if(!e.isConstant()) { 1260 allConst = false; 1261 } 1262 } 1263 Expression p0 = args.length < 1 ? null : args[0]; 1264 switch (info.type) { 1265 case COALESCE: { 1266 dataType = Value.STRING; 1267 scale = 0; 1268 precision = 0; 1269 for(int i=0; i<args.length; i++) { 1270 Expression e = args[i]; 1271 if(e != ValueExpression.NULL) { 1272 dataType = e.getType(); 1273 scale = e.getScale(); 1274 precision = e.getPrecision(); 1275 break; 1276 } 1277 } 1278 break; 1279 } 1280 case CASEWHEN: 1281 dataType = Value.getHigherOrder(args[1].getType(), args[2].getType()); 1282 precision = Math.max(args[1].getPrecision(), args[2].getPrecision()); 1283 scale = Math.max(args[1].getScale(), args[2].getScale()); 1284 break; 1285 case CAST: 1286 case CONVERT: 1287 break; 1289 case ABS: 1290 case FLOOR: 1291 case RADIANS: 1292 case ROUND: 1293 case TRUNCATE: 1294 case POWER: 1295 dataType = p0.getType(); 1296 scale = p0.getScale(); 1297 precision = p0.getPrecision(); 1298 break; 1299 default: 1300 dataType = info.dataType; 1301 scale = 0; 1302 precision = 0; 1303 } 1304 if(allConst) { 1305 return ValueExpression.get(getValue(session)); 1306 } 1307 return this; 1308 } 1309 1310 public void setEvaluatable(TableFilter tableFilter, boolean b) { 1311 for (int i = 0; i < args.length; i++) { 1312 Expression e = args[i]; 1313 if (e != null) { 1314 e.setEvaluatable(tableFilter, b); 1315 } 1316 } 1317 } 1318 1319 public int getScale() { 1320 return scale; 1321 } 1322 1323 public long getPrecision() { 1324 return precision; 1325 } 1326 1327 public String getSQL() { 1328 StringBuffer buff = new StringBuffer (); 1330 buff.append(info.name); 1331 buff.append('('); 1332 switch(info.type) { 1333 case CAST: 1334 case CONVERT: { 1335 buff.append(StringUtils.unEnclose(args[0].getSQL())); 1336 buff.append(" AS "); 1337 buff.append(new Column(null, dataType, precision, scale).getCreateSQL()); 1338 break; 1339 } 1340 case EXTRACT: { 1341 ValueString v = (ValueString)((ValueExpression)args[0]).getValue(null); 1342 buff.append(v.getString()); 1343 buff.append(" FROM "); 1344 buff.append(StringUtils.unEnclose(args[1].getSQL())); 1345 break; 1346 } 1347 default: { 1348 for (int i = 0; i < args.length; i++) { 1349 if (i > 0) { 1350 buff.append(", "); 1351 } 1352 Expression e = args[i]; 1353 buff.append(StringUtils.unEnclose(e.getSQL())); 1354 } 1355 } 1356 } 1357 buff.append(')'); 1358 return buff.toString(); 1359 } 1360 1361 public void updateAggregate(Session session) throws SQLException { 1362 for (int i = 0; i < args.length; i++) { 1363 Expression e = args[i]; 1364 if (e != null) { 1365 e.updateAggregate(session); 1366 } 1367 } 1368 } 1369 1370 public int getFunctionType() { 1371 return info.type; 1372 } 1373 1374 public String getName() { 1375 return info.name; 1376 } 1377 1378 public int getParameterCount() { 1379 return args.length; 1380 } 1381 1382 public ValueResultSet getValueForColumnList(Session session, Expression[] args) throws SQLException { 1383 if(info.type == CSVREAD) { 1384 String fileName = args[0].getValue(session).getString(); 1385 if(fileName == null) { 1386 throw Message.getSQLException(Message.PARAMETER_NOT_SET_1, "fileName"); 1387 } 1388 String columnList = args.length < 2 ? null : args[1].getValue(session).getString(); 1389 String [] columns = StringUtils.arraySplit(columnList, ',', true); 1390 String charset = args.length < 3 ? null : args[2].getValue(session).getString(); 1391 ResultSet rs = Csv.getInstance().read(fileName, columns, charset); 1392 ValueResultSet vr = ValueResultSet.getCopy(rs, 0); 1393 return vr; 1394 } 1395 return (ValueResultSet)getValueWithArgs(session, args); 1396 } 1397 1398 public Expression[] getArgs() { 1399 return args; 1400 } 1401 1402 public boolean isEverything(ExpressionVisitor visitor) { 1403 if(visitor.type == ExpressionVisitor.DETERMINISTIC && !info.isDeterministic) { 1404 return false; 1405 } 1406 for (int i = 0; i < args.length; i++) { 1407 Expression e = args[i]; 1408 if (e != null && !e.isEverything(visitor)) { 1409 return false; 1410 } 1411 } 1412 return true; 1413 } 1414 1415 public int getCost() { 1416 int cost = 3; 1417 for(int i=0; i<args.length; i++) { 1418 cost += args[i].getCost(); 1419 } 1420 return cost; 1421 } 1422 1423} 1424 | Popular Tags |