0001: /*
0002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
0003: * (http://h2database.com/html/license.html).
0004: * Initial Developer: H2 Group
0005: */
0006: package org.h2.expression;
0007:
0008: import java.io.IOException;
0009: import java.io.InputStream;
0010: import java.io.InputStreamReader;
0011: import java.io.Reader;
0012: import java.sql.Connection;
0013: import java.sql.Date;
0014: import java.sql.ResultSet;
0015: import java.sql.SQLException;
0016: import java.sql.Time;
0017: import java.sql.Timestamp;
0018: import java.text.SimpleDateFormat;
0019: import java.util.Calendar;
0020: import java.util.HashMap;
0021: import java.util.Locale;
0022: import java.util.TimeZone;
0023: import java.util.regex.PatternSyntaxException;
0024:
0025: import org.h2.command.Command;
0026: import org.h2.constant.ErrorCode;
0027: import org.h2.engine.Database;
0028: import org.h2.engine.Mode;
0029: import org.h2.engine.Session;
0030: import org.h2.message.Message;
0031: import org.h2.schema.Sequence;
0032: import org.h2.security.BlockCipher;
0033: import org.h2.security.CipherFactory;
0034: import org.h2.security.SHA256;
0035: import org.h2.table.Column;
0036: import org.h2.table.ColumnResolver;
0037: import org.h2.table.LinkSchema;
0038: import org.h2.table.TableFilter;
0039: import org.h2.tools.CompressTool;
0040: import org.h2.tools.Csv;
0041: import org.h2.util.AutoCloseInputStream;
0042: import org.h2.util.FileUtils;
0043: import org.h2.util.MathUtils;
0044: import org.h2.util.MemoryUtils;
0045: import org.h2.util.ObjectArray;
0046: import org.h2.util.ObjectUtils;
0047: import org.h2.util.RandomUtils;
0048: import org.h2.util.StringUtils;
0049: import org.h2.value.Value;
0050: import org.h2.value.ValueArray;
0051: import org.h2.value.ValueBoolean;
0052: import org.h2.value.ValueBytes;
0053: import org.h2.value.ValueDate;
0054: import org.h2.value.ValueDouble;
0055: import org.h2.value.ValueInt;
0056: import org.h2.value.ValueLob;
0057: import org.h2.value.ValueLong;
0058: import org.h2.value.ValueNull;
0059: import org.h2.value.ValueResultSet;
0060: import org.h2.value.ValueString;
0061: import org.h2.value.ValueTime;
0062: import org.h2.value.ValueTimestamp;
0063: import org.h2.value.ValueUuid;
0064:
0065: /**
0066: * This class implements most built-in functions of this database.
0067: */
0068: public class Function extends Expression implements FunctionCall {
0069: // TODO functions: add function hashcode(value)
0070:
0071: public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3,
0072: ATAN2 = 4, BITAND = 5, BITOR = 6, BITXOR = 7, CEILING = 8,
0073: COS = 9, COT = 10, DEGREES = 11, EXP = 12, FLOOR = 13,
0074: LOG = 14, LOG10 = 15, MOD = 16, PI = 17, POWER = 18,
0075: RADIANS = 19, RAND = 20, ROUND = 21, ROUNDMAGIC = 22,
0076: SIGN = 23, SIN = 24, SQRT = 25, TAN = 26, TRUNCATE = 27,
0077: SECURE_RAND = 28, HASH = 29, ENCRYPT = 30, DECRYPT = 31,
0078: COMPRESS = 32, EXPAND = 33, ZERO = 34, RANDOM_UUID = 35;
0079:
0080: public static final int ASCII = 50, BIT_LENGTH = 51, CHAR = 52,
0081: CHAR_LENGTH = 53, CONCAT = 54, DIFFERENCE = 55,
0082: HEXTORAW = 56, INSERT = 57, INSTR = 58, LCASE = 59,
0083: LEFT = 60, LENGTH = 61, LOCATE = 62, LTRIM = 63,
0084: OCTET_LENGTH = 64, RAWTOHEX = 65, REPEAT = 66,
0085: REPLACE = 67, RIGHT = 68, RTRIM = 69, SOUNDEX = 70,
0086: SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74,
0087: LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78,
0088: STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81,
0089: UTF8TOSTRING = 82, XMLATTR = 83, XMLNODE = 84,
0090: XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87,
0091: XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, LPAD = 91;
0092:
0093: public static final int CURDATE = 100, CURTIME = 101,
0094: DATEADD = 102, DATEDIFF = 103, DAYNAME = 104,
0095: DAYOFMONTH = 105, DAYOFWEEK = 106, DAYOFYEAR = 107,
0096: HOUR = 108, MINUTE = 109, MONTH = 110, MONTHNAME = 111,
0097: NOW = 112, QUARTER = 113, SECOND = 114, WEEK = 115,
0098: YEAR = 116, CURRENT_DATE = 117, CURRENT_TIME = 118,
0099: CURRENT_TIMESTAMP = 119, EXTRACT = 120,
0100: FORMATDATETIME = 121, PARSEDATETIME = 122;
0101:
0102: public static final int DATABASE = 150, USER = 151,
0103: CURRENT_USER = 152, IDENTITY = 153, AUTOCOMMIT = 154,
0104: READONLY = 155, DATABASE_PATH = 156, LOCK_TIMEOUT = 157;
0105:
0106: public static final int IFNULL = 200, CASEWHEN = 201,
0107: CONVERT = 202, CAST = 203, COALESCE = 204, NULLIF = 205,
0108: CASE = 206, NEXTVAL = 207, CURRVAL = 208, ARRAY_GET = 209,
0109: CSVREAD = 210, CSVWRITE = 211, MEMORY_FREE = 212,
0110: MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215,
0111: SESSION_ID = 216, ARRAY_LENGTH = 217, LINK_SCHEMA = 218,
0112: GREATEST = 219, LEAST = 220, CANCEL_SESSION = 221,
0113: SET = 222, TABLE = 223, TABLE_DISTINCT = 224,
0114: FILE_READ = 225;
0115:
0116: private static final int VAR_ARGS = -1;
0117:
0118: private static final HashMap FUNCTIONS = new HashMap();
0119: private static final HashMap DATE_PART = new HashMap();
0120: private static final SimpleDateFormat FORMAT_DAYNAME = new SimpleDateFormat(
0121: "EEEE", Locale.ENGLISH);
0122: private static final SimpleDateFormat FORMAT_MONTHNAME = new SimpleDateFormat(
0123: "MMMM", Locale.ENGLISH);
0124: private static final char[] SOUNDEX_INDEX = new char[128];
0125:
0126: private FunctionInfo info;
0127: protected Expression[] args;
0128: private ObjectArray varArgs;
0129: private int dataType, scale;
0130: private long precision;
0131: private int displaySize;
0132: private Database database;
0133:
0134: static {
0135: // DATE_PART
0136: DATE_PART.put("YY", ObjectUtils.getInteger(Calendar.YEAR));
0137: DATE_PART.put("YEAR", ObjectUtils.getInteger(Calendar.YEAR));
0138: DATE_PART.put("MM", ObjectUtils.getInteger(Calendar.MONTH));
0139: DATE_PART.put("MONTH", ObjectUtils.getInteger(Calendar.MONTH));
0140: DATE_PART.put("DD", ObjectUtils.getInteger(Calendar.DATE));
0141: DATE_PART.put("DAY", ObjectUtils.getInteger(Calendar.DATE));
0142: DATE_PART.put("HH", ObjectUtils
0143: .getInteger(Calendar.HOUR_OF_DAY));
0144: DATE_PART.put("HOUR", ObjectUtils
0145: .getInteger(Calendar.HOUR_OF_DAY));
0146: DATE_PART.put("MI", ObjectUtils.getInteger(Calendar.MINUTE));
0147: DATE_PART
0148: .put("MINUTE", ObjectUtils.getInteger(Calendar.MINUTE));
0149: DATE_PART.put("SS", ObjectUtils.getInteger(Calendar.SECOND));
0150: DATE_PART
0151: .put("SECOND", ObjectUtils.getInteger(Calendar.SECOND));
0152: DATE_PART.put("MS", ObjectUtils
0153: .getInteger(Calendar.MILLISECOND));
0154: DATE_PART.put("MILLISECOND", ObjectUtils
0155: .getInteger(Calendar.MILLISECOND));
0156:
0157: // SOUNDEX_INDEX
0158: String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
0159: char number = 0;
0160: for (int i = 0; i < index.length(); i++) {
0161: char c = index.charAt(i);
0162: if (c < '9') {
0163: number = c;
0164: } else {
0165: SOUNDEX_INDEX[c] = number;
0166: SOUNDEX_INDEX[Character.toLowerCase(c)] = number;
0167: }
0168: }
0169:
0170: // FUNCTIONS
0171: addFunction("ABS", ABS, 1, Value.NULL);
0172: addFunction("ACOS", ACOS, 1, Value.DOUBLE);
0173: addFunction("ASIN", ASIN, 1, Value.DOUBLE);
0174: addFunction("ATAN", ATAN, 1, Value.DOUBLE);
0175: addFunction("ATAN2", ATAN2, 2, Value.DOUBLE);
0176: addFunction("BITAND", BITAND, 2, Value.INT);
0177: addFunction("BITOR", BITOR, 2, Value.INT);
0178: addFunction("BITXOR", BITXOR, 2, Value.INT);
0179: addFunction("CEILING", CEILING, 1, Value.DOUBLE);
0180: addFunction("COS", COS, 1, Value.DOUBLE);
0181: addFunction("COT", COT, 1, Value.DOUBLE);
0182: addFunction("DEGREES", DEGREES, 1, Value.DOUBLE);
0183: addFunction("EXP", EXP, 1, Value.DOUBLE);
0184: addFunction("FLOOR", FLOOR, 1, Value.DOUBLE);
0185: addFunction("LOG", LOG, 1, Value.DOUBLE);
0186: addFunction("LOG10", LOG10, 1, Value.DOUBLE);
0187: addFunction("MOD", MOD, 2, Value.INT);
0188: addFunction("PI", PI, 0, Value.DOUBLE);
0189: addFunction("POWER", POWER, 2, Value.DOUBLE);
0190: addFunction("RADIANS", RADIANS, 1, Value.DOUBLE);
0191: // RAND without argument: get the next value
0192: // RAND with one argument: seed the random generator
0193: addFunctionNotConst("RAND", RAND, VAR_ARGS, Value.DOUBLE);
0194: addFunction("ROUND", ROUND, 2, Value.DOUBLE);
0195: addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE);
0196: addFunction("SIGN", SIGN, 1, Value.INT);
0197: addFunction("SIN", SIN, 1, Value.DOUBLE);
0198: addFunction("SQRT", SQRT, 1, Value.DOUBLE);
0199: addFunction("TAN", TAN, 1, Value.DOUBLE);
0200: addFunction("TRUNCATE", TRUNCATE, 2, Value.DOUBLE);
0201: addFunction("HASH", HASH, 3, Value.BYTES);
0202: addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES);
0203: addFunction("DECRYPT", DECRYPT, 3, Value.BYTES);
0204: addFunctionNotConst("SECURE_RAND", SECURE_RAND, 1, Value.BYTES);
0205: addFunction("COMPRESS", COMPRESS, VAR_ARGS, Value.BYTES);
0206: addFunction("EXPAND", EXPAND, 1, Value.BYTES);
0207: addFunction("ZERO", ZERO, 0, Value.INT);
0208: addFunctionNotConst("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID);
0209: addFunctionNotConst("SYS_GUID", RANDOM_UUID, 0, Value.UUID);
0210: // string
0211: addFunction("ASCII", ASCII, 1, Value.INT);
0212: addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.INT);
0213: addFunction("CHAR", CHAR, 1, Value.STRING);
0214: addFunction("CHR", CHAR, 1, Value.STRING);
0215: addFunction("CHAR_LENGTH", CHAR_LENGTH, 1, Value.INT);
0216: addFunction("CHARACTER_LENGTH", CHAR_LENGTH, 1, Value.INT); // same as
0217: // CHAR_LENGTH
0218: addFunctionWithNull("CONCAT", CONCAT, VAR_ARGS, Value.STRING);
0219: addFunction("DIFFERENCE", DIFFERENCE, 2, Value.INT);
0220: addFunction("HEXTORAW", HEXTORAW, 1, Value.STRING);
0221: addFunctionWithNull("INSERT", INSERT, 4, Value.STRING);
0222: addFunction("LCASE", LCASE, 1, Value.STRING);
0223: addFunction("LEFT", LEFT, 2, Value.STRING);
0224: addFunction("LENGTH", LENGTH, 1, Value.INT);
0225: addFunction("LOCATE", LOCATE, VAR_ARGS, Value.INT); // 2 or 3 arguments
0226: addFunction("POSITION", LOCATE, 2, Value.INT); // same as LOCATE with 2
0227: // arguments
0228: addFunction("INSTR", INSTR, VAR_ARGS, Value.INT);
0229: addFunction("LTRIM", LTRIM, VAR_ARGS, Value.STRING);
0230: addFunction("OCTET_LENGTH", OCTET_LENGTH, 1, Value.INT);
0231: addFunction("RAWTOHEX", RAWTOHEX, 1, Value.STRING);
0232: addFunction("REPEAT", REPEAT, 2, Value.STRING);
0233: addFunctionWithNull("REPLACE", REPLACE, VAR_ARGS, Value.STRING);
0234: addFunction("RIGHT", RIGHT, 2, Value.STRING);
0235: addFunction("RTRIM", RTRIM, VAR_ARGS, Value.STRING);
0236: addFunction("SOUNDEX", SOUNDEX, 1, Value.STRING);
0237: addFunction("SPACE", SPACE, 1, Value.STRING);
0238: addFunction("SUBSTR", SUBSTR, VAR_ARGS, Value.STRING);
0239: addFunction("SUBSTRING", SUBSTRING, VAR_ARGS, Value.STRING);
0240: addFunction("UCASE", UCASE, 1, Value.STRING);
0241: addFunction("LOWER", LOWER, 1, Value.STRING);
0242: addFunction("UPPER", UPPER, 1, Value.STRING);
0243: addFunction("POSITION", POSITION, 2, Value.INT);
0244: addFunction("TRIM", TRIM, VAR_ARGS, Value.STRING);
0245: addFunction("STRINGENCODE", STRINGENCODE, 1, Value.STRING);
0246: addFunction("STRINGDECODE", STRINGDECODE, 1, Value.STRING);
0247: addFunction("STRINGTOUTF8", STRINGTOUTF8, 1, Value.BYTES);
0248: addFunction("UTF8TOSTRING", UTF8TOSTRING, 1, Value.STRING);
0249: addFunction("XMLATTR", XMLATTR, 2, Value.STRING);
0250: addFunctionWithNull("XMLNODE", XMLNODE, VAR_ARGS, Value.STRING);
0251: addFunction("XMLCOMMENT", XMLCOMMENT, 1, Value.STRING);
0252: addFunction("XMLCDATA", XMLCDATA, 1, Value.STRING);
0253: addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING);
0254: addFunction("XMLTEXT", XMLTEXT, 1, Value.STRING);
0255: addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING);
0256: addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING);
0257: addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
0258:
0259: // date
0260: addFunctionNotConst("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE);
0261: addFunctionNotConst("CURDATE", CURDATE, 0, Value.DATE);
0262: addFunctionNotConst("CURRENT_TIME", CURRENT_TIME, 0, Value.TIME);
0263: addFunctionNotConst("CURTIME", CURTIME, 0, Value.TIME);
0264: addFunctionNotConst("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP,
0265: VAR_ARGS, Value.TIMESTAMP);
0266: addFunctionNotConst("NOW", NOW, VAR_ARGS, Value.TIMESTAMP);
0267: addFunction("DATEADD", DATEADD, 3, Value.TIMESTAMP);
0268: addFunction("DATEDIFF", DATEDIFF, 3, Value.LONG);
0269: addFunction("DAYNAME", DAYNAME, 1, Value.STRING);
0270: addFunction("DAY", DAYOFMONTH, 1, Value.INT);
0271: addFunction("DAYOFMONTH", DAYOFMONTH, 1, Value.INT);
0272: addFunction("DAYOFWEEK", DAYOFWEEK, 1, Value.INT);
0273: addFunction("DAYOFYEAR", DAYOFYEAR, 1, Value.INT);
0274: addFunction("HOUR", HOUR, 1, Value.INT);
0275: addFunction("MINUTE", MINUTE, 1, Value.INT);
0276: addFunction("MONTH", MONTH, 1, Value.INT);
0277: addFunction("MONTHNAME", MONTHNAME, 1, Value.STRING);
0278: addFunction("QUARTER", QUARTER, 1, Value.INT);
0279: addFunction("SECOND", SECOND, 1, Value.INT);
0280: addFunction("WEEK", WEEK, 1, Value.INT);
0281: addFunction("YEAR", YEAR, 1, Value.INT);
0282: addFunction("EXTRACT", EXTRACT, 2, Value.INT);
0283: addFunctionWithNull("FORMATDATETIME", FORMATDATETIME, VAR_ARGS,
0284: Value.STRING);
0285: addFunctionWithNull("PARSEDATETIME", PARSEDATETIME, VAR_ARGS,
0286: Value.TIMESTAMP);
0287: // system
0288: addFunctionNotConst("DATABASE", DATABASE, 0, Value.STRING);
0289: addFunctionNotConst("USER", USER, 0, Value.STRING);
0290: addFunctionNotConst("CURRENT_USER", CURRENT_USER, 0,
0291: Value.STRING);
0292: addFunctionNotConst("IDENTITY", IDENTITY, 0, Value.LONG);
0293: addFunctionNotConst("IDENTITY_VAL_LOCAL", IDENTITY, 0,
0294: Value.LONG);
0295: addFunctionNotConst("LAST_INSERT_ID", IDENTITY, 0, Value.LONG);
0296: addFunctionNotConst("AUTOCOMMIT", AUTOCOMMIT, 0, Value.BOOLEAN);
0297: addFunctionNotConst("READONLY", READONLY, 0, Value.BOOLEAN);
0298: addFunction("DATABASE_PATH", DATABASE_PATH, 0, Value.STRING);
0299: addFunction("LOCK_TIMEOUT", LOCK_TIMEOUT, 0, Value.INT);
0300: addFunctionWithNull("IFNULL", IFNULL, 2, Value.NULL);
0301: addFunctionWithNull("CASEWHEN", CASEWHEN, 3, Value.NULL);
0302: addFunctionWithNull("CONVERT", CONVERT, 1, Value.NULL);
0303: addFunctionWithNull("CAST", CAST, 1, Value.NULL);
0304: addFunctionWithNull("COALESCE", COALESCE, VAR_ARGS, Value.NULL);
0305: addFunctionWithNull("NVL", COALESCE, VAR_ARGS, Value.NULL);
0306: addFunctionWithNull("NULLIF", NULLIF, 2, Value.NULL);
0307: addFunctionWithNull("CASE", CASE, VAR_ARGS, Value.NULL);
0308: addFunctionNotConst("NEXTVAL", NEXTVAL, VAR_ARGS, Value.LONG);
0309: addFunctionNotConst("CURRVAL", CURRVAL, VAR_ARGS, Value.LONG);
0310: addFunction("ARRAY_GET", ARRAY_GET, 2, Value.NULL);
0311: addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET,
0312: false, false);
0313: addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false,
0314: false);
0315: addFunctionNotConst("MEMORY_FREE", MEMORY_FREE, 0, Value.INT);
0316: addFunctionNotConst("MEMORY_USED", MEMORY_USED, 0, Value.INT);
0317: addFunctionNotConst("LOCK_MODE", LOCK_MODE, 0, Value.INT);
0318: addFunctionNotConst("SCHEMA", SCHEMA, 0, Value.STRING);
0319: addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT);
0320: addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT);
0321: addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET);
0322: addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL);
0323: addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL);
0324: addFunction("CANCEL_SESSION", CANCEL_SESSION, 1, Value.BOOLEAN);
0325: addFunction("SET", SET, 2, Value.NULL, false, false);
0326: addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL,
0327: false, true);
0328:
0329: // TableFunction
0330: addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
0331: addFunctionWithNull("TABLE_DISTINCT", TABLE_DISTINCT, VAR_ARGS,
0332: Value.RESULT_SET);
0333: }
0334:
0335: private static void addFunction(String name, int type,
0336: int parameterCount, int dataType,
0337: boolean nullIfParameterIsNull, boolean isDeterm) {
0338: FunctionInfo info = new FunctionInfo();
0339: info.name = name;
0340: info.type = type;
0341: info.parameterCount = parameterCount;
0342: info.dataType = dataType;
0343: info.nullIfParameterIsNull = nullIfParameterIsNull;
0344: info.isDeterministic = isDeterm;
0345: FUNCTIONS.put(name, info);
0346: }
0347:
0348: private static void addFunctionNotConst(String name, int type,
0349: int parameterCount, int dataType) {
0350: addFunction(name, type, parameterCount, dataType, true, false);
0351: }
0352:
0353: private static void addFunction(String name, int type,
0354: int parameterCount, int dataType) {
0355: addFunction(name, type, parameterCount, dataType, true, true);
0356: }
0357:
0358: private static void addFunctionWithNull(String name, int type,
0359: int parameterCount, int dataType) {
0360: addFunction(name, type, parameterCount, dataType, false, true);
0361: }
0362:
0363: public static FunctionInfo getFunctionInfo(String name) {
0364: return (FunctionInfo) FUNCTIONS.get(name);
0365: }
0366:
0367: public static Function getFunction(Database database, String name)
0368: throws SQLException {
0369: FunctionInfo info = getFunctionInfo(name);
0370: if (info == null) {
0371: return null;
0372: }
0373: switch (info.type) {
0374: case TABLE:
0375: case TABLE_DISTINCT:
0376: return new TableFunction(database, info);
0377: default:
0378: return new Function(database, info);
0379: }
0380: }
0381:
0382: protected Function(Database database, FunctionInfo info) {
0383: this .database = database;
0384: this .info = info;
0385: if (info.parameterCount == VAR_ARGS) {
0386: varArgs = new ObjectArray();
0387: } else {
0388: args = new Expression[info.parameterCount];
0389: }
0390: }
0391:
0392: public void setParameter(int index, Expression param)
0393: throws SQLException {
0394: if (varArgs != null) {
0395: varArgs.add(param);
0396: } else {
0397: if (index >= args.length) {
0398: throw Message.getSQLException(
0399: ErrorCode.INVALID_PARAMETER_COUNT_2,
0400: new String[] { info.name, "" + args.length });
0401: }
0402: args[index] = param;
0403: }
0404: }
0405:
0406: private strictfp double log10(double value) {
0407: return roundmagic(StrictMath.log(value) / StrictMath.log(10));
0408: }
0409:
0410: public Value getValue(Session session) throws SQLException {
0411: return getValueWithArgs(session, args);
0412: }
0413:
0414: private Value getNullOrValue(Session session, Expression[] x, int i)
0415: throws SQLException {
0416: if (i < x.length) {
0417: Expression e = x[i];
0418: if (e != null) {
0419: return e.getValue(session);
0420: }
0421: }
0422: return null;
0423: }
0424:
0425: private Value getSimpleValue(Session session, Value v0,
0426: Expression[] args) throws SQLException {
0427: Value result;
0428: switch (info.type) {
0429: case ABS:
0430: result = v0.getSignum() > 0 ? v0 : v0.negate();
0431: break;
0432: case ACOS:
0433: result = ValueDouble.get(Math.acos(v0.getDouble()));
0434: break;
0435: case ASIN:
0436: result = ValueDouble.get(Math.asin(v0.getDouble()));
0437: break;
0438: case ATAN:
0439: result = ValueDouble.get(Math.atan(v0.getDouble()));
0440: break;
0441: case CEILING:
0442: result = ValueDouble.get(Math.ceil(v0.getDouble()));
0443: break;
0444: case COS:
0445: result = ValueDouble.get(Math.cos(v0.getDouble()));
0446: break;
0447: case COT: {
0448: double d = Math.tan(v0.getDouble());
0449: if (d == 0.0) {
0450: throw Message.getSQLException(
0451: ErrorCode.DIVISION_BY_ZERO_1, getSQL());
0452: }
0453: result = ValueDouble.get(1. / d);
0454: break;
0455: }
0456: case DEGREES:
0457: result = ValueDouble.get(Math.toDegrees(v0.getDouble()));
0458: break;
0459: case EXP:
0460: result = ValueDouble.get(Math.exp(v0.getDouble()));
0461: break;
0462: case FLOOR:
0463: result = ValueDouble.get(Math.floor(v0.getDouble()));
0464: break;
0465: case LOG:
0466: result = ValueDouble.get(Math.log(v0.getDouble()));
0467: break;
0468: case LOG10:
0469: result = ValueDouble.get(log10(v0.getDouble()));
0470: break;
0471: case PI:
0472: result = ValueDouble.get(Math.PI);
0473: break;
0474: case RADIANS:
0475: result = ValueDouble.get(Math.toRadians(v0.getDouble()));
0476: break;
0477: case RAND: {
0478: if (v0 != null) {
0479: session.getRandom().setSeed(v0.getInt());
0480: }
0481: // TODO function rand: if seed value is set,
0482: // return a random value? probably yes
0483: result = ValueDouble.get(session.getRandom().nextDouble());
0484: break;
0485: }
0486: case ROUNDMAGIC:
0487: result = ValueDouble.get(roundmagic(v0.getDouble()));
0488: break;
0489: case SIGN:
0490: result = ValueInt.get(v0.getSignum());
0491: break;
0492: case SIN:
0493: result = ValueDouble.get(Math.sin(v0.getDouble()));
0494: break;
0495: case SQRT:
0496: result = ValueDouble.get(Math.sqrt(v0.getDouble()));
0497: break;
0498: case TAN:
0499: result = ValueDouble.get(Math.tan(v0.getDouble()));
0500: break;
0501: case SECURE_RAND:
0502: result = ValueBytes.getNoCopy(RandomUtils.getSecureBytes(v0
0503: .getInt()));
0504: break;
0505: case EXPAND:
0506: result = ValueBytes.getNoCopy(CompressTool.getInstance()
0507: .expand(v0.getBytesNoCopy()));
0508: break;
0509: case ZERO:
0510: result = ValueInt.get(0);
0511: break;
0512: case RANDOM_UUID:
0513: result = ValueUuid.getNewRandom();
0514: break;
0515: // string
0516: case ASCII: {
0517: String s = v0.getString();
0518: if (s.length() == 0) {
0519: result = ValueNull.INSTANCE;
0520: } else {
0521: result = ValueInt.get(s.charAt(0));
0522: }
0523: break;
0524: }
0525: case BIT_LENGTH:
0526: result = ValueInt.get(16 * length(v0));
0527: break;
0528: case CHAR:
0529: result = ValueString
0530: .get(String.valueOf((char) v0.getInt()));
0531: break;
0532: case CHAR_LENGTH:
0533: case LENGTH:
0534: result = ValueInt.get(length(v0));
0535: break;
0536: case OCTET_LENGTH:
0537: result = ValueInt.get(2 * length(v0));
0538: break;
0539: case CONCAT: {
0540: result = ValueNull.INSTANCE;
0541: for (int i = 0; i < args.length; i++) {
0542: Value v = args[i].getValue(session);
0543: if (v == ValueNull.INSTANCE) {
0544: continue;
0545: }
0546: if (result == ValueNull.INSTANCE) {
0547: result = v;
0548: } else {
0549: result = ValueString.get(result.getString().concat(
0550: v.getString()));
0551: }
0552: }
0553: break;
0554: }
0555: case HEXTORAW:
0556: result = ValueString.get(hexToRaw(v0.getString()));
0557: break;
0558: case LOWER:
0559: case LCASE:
0560: // TODO this is locale specific, need to document or provide a way
0561: // to set the locale
0562: result = ValueString.get(v0.getString().toLowerCase());
0563: break;
0564: case RAWTOHEX:
0565: result = ValueString.get(rawToHex(v0.getString()));
0566: break;
0567: case SOUNDEX:
0568: result = ValueString.get(getSoundex(v0.getString()));
0569: break;
0570: case SPACE: {
0571: // TODO DOS attacks: limit len?
0572: int len = Math.max(0, v0.getInt());
0573: char[] chars = new char[len];
0574: for (int i = len - 1; i >= 0; i--) {
0575: chars[i] = ' ';
0576: }
0577: result = ValueString.get(new String(chars));
0578: break;
0579: }
0580: case UPPER:
0581: case UCASE:
0582: // TODO this is locale specific, need to document or provide a way
0583: // to set the locale
0584: result = ValueString.get(v0.getString().toUpperCase());
0585: break;
0586: case STRINGENCODE:
0587: result = ValueString.get(StringUtils.javaEncode(v0
0588: .getString()));
0589: break;
0590: case STRINGDECODE:
0591: result = ValueString.get(StringUtils.javaDecode(v0
0592: .getString()));
0593: break;
0594: case STRINGTOUTF8:
0595: result = ValueBytes.getNoCopy(StringUtils.utf8Encode(v0
0596: .getString()));
0597: break;
0598: case UTF8TOSTRING:
0599: result = ValueString.get(StringUtils.utf8Decode(v0
0600: .getBytesNoCopy()));
0601: break;
0602: case XMLCOMMENT:
0603: result = ValueString.get(StringUtils.xmlComment(v0
0604: .getString()));
0605: break;
0606: case XMLCDATA:
0607: result = ValueString.get(StringUtils.xmlCData(v0
0608: .getString()));
0609: break;
0610: case XMLSTARTDOC:
0611: result = ValueString.get(StringUtils.xmlStartDoc());
0612: break;
0613: case XMLTEXT:
0614: result = ValueString.get(StringUtils
0615: .xmlText(v0.getString()));
0616: break;
0617: case DAYNAME: {
0618: synchronized (FORMAT_DAYNAME) {
0619: result = ValueString.get(FORMAT_DAYNAME.format(v0
0620: .getDateNoCopy()));
0621: }
0622: break;
0623: }
0624: case DAYOFMONTH:
0625: result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(),
0626: Calendar.DAY_OF_MONTH));
0627: break;
0628: case DAYOFWEEK:
0629: result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(),
0630: Calendar.DAY_OF_WEEK));
0631: break;
0632: case DAYOFYEAR:
0633: result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(),
0634: Calendar.DAY_OF_YEAR));
0635: break;
0636: case HOUR:
0637: result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(),
0638: Calendar.HOUR_OF_DAY));
0639: break;
0640: case MINUTE:
0641: result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(),
0642: Calendar.MINUTE));
0643: break;
0644: case MONTH:
0645: result = ValueInt.get(getDatePart(v0.getTimestampNoCopy(),
0646: Calendar.MONTH));
0647: break;
0648: case MONTHNAME: {
0649: synchronized (FORMAT_MONTHNAME) {
0650: result = ValueString.get(FORMAT_MONTHNAME.format(v0
0651: .getDateNoCopy()));
0652: }
0653: break;
0654: }
0655: case QUARTER:
0656: result = ValueInt.get((getDatePart(v0.getTimestamp(),
0657: Calendar.MONTH) - 1) / 3 + 1);
0658: break;
0659: case SECOND:
0660: result = ValueInt.get(getDatePart(v0.getTimestamp(),
0661: Calendar.SECOND));
0662: break;
0663: case WEEK:
0664: result = ValueInt.get(getDatePart(v0.getTimestamp(),
0665: Calendar.WEEK_OF_YEAR));
0666: break;
0667: case YEAR:
0668: result = ValueInt.get(getDatePart(v0.getTimestamp(),
0669: Calendar.YEAR));
0670: break;
0671: case CURDATE:
0672: case CURRENT_DATE:
0673: // need to normalize
0674: result = ValueDate
0675: .get(new Date(System.currentTimeMillis()));
0676: break;
0677: case CURTIME:
0678: case CURRENT_TIME:
0679: // need to normalize
0680: result = ValueTime
0681: .get(new Time(System.currentTimeMillis()));
0682: break;
0683: case NOW:
0684: case CURRENT_TIMESTAMP: {
0685: ValueTimestamp vt = ValueTimestamp.getNoCopy(new Timestamp(
0686: System.currentTimeMillis()));
0687: if (v0 != null) {
0688: Mode mode = database.getMode();
0689: vt = (ValueTimestamp) vt.convertScale(
0690: mode.convertOnlyToSmallerScale, v0.getInt());
0691: }
0692: result = vt;
0693: break;
0694: }
0695: case DATABASE:
0696: result = ValueString.get(database.getShortName());
0697: break;
0698: case USER:
0699: case CURRENT_USER:
0700: result = ValueString.get(session.getUser().getName());
0701: break;
0702: case IDENTITY:
0703: result = session.getLastIdentity();
0704: break;
0705: case AUTOCOMMIT:
0706: result = ValueBoolean.get(session.getAutoCommit());
0707: break;
0708: case READONLY:
0709: result = ValueBoolean.get(database.getReadOnly());
0710: break;
0711: case DATABASE_PATH: {
0712: String path = database.getDatabasePath();
0713: result = path == null ? (Value) ValueNull.INSTANCE
0714: : ValueString.get(path);
0715: break;
0716: }
0717: case LOCK_TIMEOUT:
0718: result = ValueInt.get(session.getLockTimeout());
0719: break;
0720: case CAST:
0721: case CONVERT: {
0722: v0 = v0.convertTo(dataType);
0723: Mode mode = database.getMode();
0724: v0 = v0.convertScale(mode.convertOnlyToSmallerScale, scale);
0725: v0 = v0.convertPrecision(getPrecision());
0726: result = v0;
0727: break;
0728: }
0729: case MEMORY_FREE:
0730: session.getUser().checkAdmin();
0731: result = ValueInt.get(MemoryUtils.getMemoryFree());
0732: break;
0733: case MEMORY_USED:
0734: session.getUser().checkAdmin();
0735: result = ValueInt.get(MemoryUtils.getMemoryUsed());
0736: break;
0737: case LOCK_MODE:
0738: result = ValueInt.get(database.getLockMode());
0739: break;
0740: case SCHEMA:
0741: result = ValueString.get(session.getCurrentSchemaName());
0742: break;
0743: case SESSION_ID:
0744: result = ValueInt.get(session.getId());
0745: break;
0746: case IFNULL: {
0747: result = v0 == ValueNull.INSTANCE ? args[1]
0748: .getValue(session) : v0;
0749: break;
0750: }
0751: case CASEWHEN: {
0752: Expression expr;
0753: if (v0 == ValueNull.INSTANCE
0754: || !v0.getBoolean().booleanValue()) {
0755: expr = args[2];
0756: } else {
0757: expr = args[1];
0758: }
0759: Value v = expr.getValue(session);
0760: result = v.convertTo(dataType);
0761: break;
0762: }
0763: case COALESCE: {
0764: result = v0;
0765: for (int i = 0; i < args.length; i++) {
0766: Value v = i == 0 ? v0 : args[i].getValue(session);
0767: if (!(v == ValueNull.INSTANCE)) {
0768: result = v.convertTo(dataType);
0769: break;
0770: }
0771: }
0772: break;
0773: }
0774: case GREATEST:
0775: case LEAST: {
0776: result = ValueNull.INSTANCE;
0777: for (int i = 0; i < args.length; i++) {
0778: Value v = i == 0 ? v0 : args[i].getValue(session);
0779: if (!(v == ValueNull.INSTANCE)) {
0780: v = v.convertTo(dataType);
0781: if (result == ValueNull.INSTANCE) {
0782: result = v;
0783: } else {
0784: int comp = database.compareTypeSave(result, v);
0785: if (info.type == GREATEST && comp < 0) {
0786: result = v;
0787: } else if (info.type == LEAST && comp > 0) {
0788: result = v;
0789: }
0790: }
0791: }
0792: }
0793: break;
0794: }
0795: case CASE: {
0796: result = null;
0797: int i = 0;
0798: for (; i < args.length; i++) {
0799: Value when = args[i++].getValue(session);
0800: if (Boolean.TRUE.equals(when)) {
0801: result = args[i].getValue(session);
0802: break;
0803: }
0804: }
0805: if (result == null) {
0806: result = i < args.length ? args[i].getValue(session)
0807: : ValueNull.INSTANCE;
0808: }
0809: break;
0810: }
0811: case ARRAY_GET: {
0812: if (v0.getType() == Value.ARRAY) {
0813: Value v1 = args[1].getValue(session);
0814: int element = v1.getInt();
0815: Value[] list = ((ValueArray) v0).getList();
0816: if (element < 1 || element > list.length) {
0817: result = ValueNull.INSTANCE;
0818: } else {
0819: result = list[element - 1];
0820: }
0821: } else {
0822: result = ValueNull.INSTANCE;
0823: }
0824: break;
0825: }
0826: case ARRAY_LENGTH: {
0827: if (v0.getType() == Value.ARRAY) {
0828: Value[] list = ((ValueArray) v0).getList();
0829: result = ValueInt.get(list.length);
0830: } else {
0831: result = ValueNull.INSTANCE;
0832: }
0833: break;
0834: }
0835: case CANCEL_SESSION: {
0836: result = ValueBoolean.get(cancelStatement(session, v0
0837: .getInt()));
0838: break;
0839: }
0840: default:
0841: result = null;
0842: }
0843: return result;
0844: }
0845:
0846: private boolean cancelStatement(Session session, int targetSessionId)
0847: throws SQLException {
0848: session.getUser().checkAdmin();
0849: Session[] sessions = session.getDatabase().getSessions();
0850: for (int i = 0; i < sessions.length; i++) {
0851: Session s = sessions[i];
0852: if (s.getId() == targetSessionId) {
0853: Command c = s.getCurrentCommand();
0854: if (c == null) {
0855: return false;
0856: } else {
0857: c.cancel();
0858: return true;
0859: }
0860: }
0861: }
0862: return false;
0863: }
0864:
0865: public Value getValueWithArgs(Session session, Expression[] args)
0866: throws SQLException {
0867: if (info.nullIfParameterIsNull) {
0868: for (int i = 0; i < args.length; i++) {
0869: if (getNullOrValue(session, args, i) == ValueNull.INSTANCE) {
0870: return ValueNull.INSTANCE;
0871: }
0872: }
0873: }
0874: Value v0 = getNullOrValue(session, args, 0);
0875: Value resultSimple = getSimpleValue(session, v0, args);
0876: if (resultSimple != null) {
0877: return resultSimple;
0878: }
0879: Value v1 = getNullOrValue(session, args, 1);
0880: Value v2 = getNullOrValue(session, args, 2);
0881: Value v3 = getNullOrValue(session, args, 3);
0882: Value v4 = getNullOrValue(session, args, 4);
0883: Value v5 = getNullOrValue(session, args, 5);
0884: Value result;
0885: switch (info.type) {
0886: case ATAN2:
0887: result = ValueDouble.get(Math.atan2(v0.getDouble(), v1
0888: .getDouble()));
0889: break;
0890: case BITAND:
0891: result = ValueInt.get(v0.getInt() & v1.getInt());
0892: break;
0893: case BITOR:
0894: result = ValueInt.get(v0.getInt() | v1.getInt());
0895: break;
0896: case BITXOR:
0897: result = ValueInt.get(v0.getInt() ^ v1.getInt());
0898: break;
0899: case MOD: {
0900: int x = v1.getInt();
0901: if (x == 0.0) {
0902: throw Message.getSQLException(
0903: ErrorCode.DIVISION_BY_ZERO_1, getSQL());
0904: }
0905: result = ValueInt.get(v0.getInt() % x);
0906: break;
0907: }
0908: case POWER:
0909: result = ValueDouble.get(Math.pow(v0.getDouble(), v1
0910: .getDouble()));
0911: break;
0912: case ROUND: {
0913: double f = Math.pow(10., v1.getDouble());
0914: result = ValueDouble
0915: .get(Math.round(v0.getDouble() * f) / f);
0916: break;
0917: }
0918: case TRUNCATE: {
0919: double d = v0.getDouble();
0920: int p = v1.getInt();
0921: double f = Math.pow(10., p);
0922: double g = d * f;
0923: result = ValueDouble.get(((d < 0) ? Math.ceil(g) : Math
0924: .floor(g))
0925: / f);
0926: break;
0927: }
0928: case HASH:
0929: result = ValueBytes.getNoCopy(getHash(v0.getString(), v1
0930: .getBytesNoCopy(), v2.getInt()));
0931: break;
0932: case ENCRYPT:
0933: result = ValueBytes.getNoCopy(encrypt(v0.getString(), v1
0934: .getBytesNoCopy(), v2.getBytesNoCopy()));
0935: break;
0936: case DECRYPT:
0937: result = ValueBytes.getNoCopy(decrypt(v0.getString(), v1
0938: .getBytesNoCopy(), v2.getBytesNoCopy()));
0939: break;
0940: case COMPRESS: {
0941: String algorithm = null;
0942: if (v1 != null) {
0943: algorithm = v1.getString();
0944: }
0945: result = ValueBytes.getNoCopy(CompressTool.getInstance()
0946: .compress(v0.getBytesNoCopy(), algorithm));
0947: break;
0948: }
0949: case DIFFERENCE:
0950: result = ValueInt.get(getDifference(v0.getString(), v1
0951: .getString()));
0952: break;
0953: case INSERT: {
0954: if (v1 == ValueNull.INSTANCE || v2 == ValueNull.INSTANCE) {
0955: result = v1;
0956: } else {
0957: result = ValueString.get(insert(v0.getString(), v1
0958: .getInt(), v2.getInt(), v3.getString()));
0959: }
0960: break;
0961: }
0962: case LEFT:
0963: result = ValueString.get(left(v0.getString(), v1.getInt()));
0964: break;
0965: case LOCATE: {
0966: int start = v2 == null ? 0 : v2.getInt();
0967: result = ValueInt.get(locate(v0.getString(),
0968: v1.getString(), start));
0969: break;
0970: }
0971: case INSTR: {
0972: int start = v2 == null ? 0 : v2.getInt();
0973: result = ValueInt.get(locate(v1.getString(),
0974: v0.getString(), start));
0975: break;
0976: }
0977: case REPEAT: {
0978: int count = Math.max(0, v1.getInt());
0979: result = ValueString.get(repeat(v0.getString(), count));
0980: break;
0981: }
0982: case REPLACE: {
0983: String s0 = v0 == ValueNull.INSTANCE ? "" : v0.getString();
0984: String s1 = v1 == ValueNull.INSTANCE ? "" : v1.getString();
0985: String s2 = (v2 == null || v2 == ValueNull.INSTANCE) ? ""
0986: : v2.getString();
0987: result = ValueString.get(replace(s0, s1, s2));
0988: break;
0989: }
0990: case RIGHT:
0991: result = ValueString
0992: .get(right(v0.getString(), v1.getInt()));
0993: break;
0994: case LTRIM:
0995: result = ValueString.get(trim(v0.getString(), true, false,
0996: v1 == null ? " " : v1.getString()));
0997: break;
0998: case TRIM:
0999: result = ValueString.get(trim(v0.getString(), true, true,
1000: v1 == null ? " " : v1.getString()));
1001: break;
1002: case RTRIM:
1003: result = ValueString.get(trim(v0.getString(), false, true,
1004: v1 == null ? " " : v1.getString()));
1005: break;
1006: case SUBSTR:
1007: case SUBSTRING: {
1008: String s = v0.getString();
1009: int length = v2 == null ? s.length() : v2.getInt();
1010: result = ValueString.get(substring(s, v1.getInt(), length));
1011: break;
1012: }
1013: case POSITION:
1014: result = ValueInt.get(locate(v0.getString(),
1015: v1.getString(), 0));
1016: break;
1017: case XMLATTR:
1018: result = ValueString.get(StringUtils.xmlAttr(
1019: v0.getString(), v1.getString()));
1020: break;
1021: case XMLNODE: {
1022: String attr = v1 == null ? null
1023: : v1 == ValueNull.INSTANCE ? null : v1.getString();
1024: String content = v2 == null ? null
1025: : v2 == ValueNull.INSTANCE ? null : v2.getString();
1026: result = ValueString.get(StringUtils.xmlNode(
1027: v0.getString(), attr, content));
1028: break;
1029: }
1030: case REGEXP_REPLACE: {
1031: String regexp = v1.getString();
1032: try {
1033: result = ValueString.get(v0.getString().replaceAll(
1034: regexp, v2.getString()));
1035: } catch (PatternSyntaxException e) {
1036: throw Message.getSQLException(
1037: ErrorCode.LIKE_ESCAPE_ERROR_1,
1038: new String[] { regexp }, e);
1039: }
1040: break;
1041: }
1042: case RPAD:
1043: result = ValueString.get(StringUtils
1044: .pad(v0.getString(), v1.getInt(), v2 == null ? null
1045: : v2.getString(), true));
1046: break;
1047: case LPAD:
1048: result = ValueString.get(StringUtils.pad(v0.getString(), v1
1049: .getInt(), v2 == null ? null : v2.getString(),
1050: false));
1051: break;
1052: // date
1053: case DATEADD:
1054: result = ValueTimestamp.getNoCopy(dateadd(v0.getString(),
1055: v1.getInt(), v2.getTimestampNoCopy()));
1056: break;
1057: case DATEDIFF:
1058: result = ValueLong.get(datediff(v0.getString(), v1
1059: .getTimestampNoCopy(), v2.getTimestampNoCopy()));
1060: break;
1061: case EXTRACT: {
1062: int field = getDatePart(v0.getString());
1063: result = ValueInt
1064: .get(getDatePart(v1.getTimestamp(), field));
1065: break;
1066: }
1067: case FORMATDATETIME: {
1068: if (v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) {
1069: result = ValueNull.INSTANCE;
1070: } else {
1071: String locale = v2 == null ? null
1072: : v2 == ValueNull.INSTANCE ? null : v2
1073: .getString();
1074: String tz = v3 == null ? null
1075: : v3 == ValueNull.INSTANCE ? null : v3
1076: .getString();
1077: result = ValueString.get(StringUtils.formatDateTime(v0
1078: .getTimestamp(), v1.getString(), locale, tz));
1079: }
1080: break;
1081: }
1082: case PARSEDATETIME: {
1083: if (v0 == ValueNull.INSTANCE || v1 == ValueNull.INSTANCE) {
1084: result = ValueNull.INSTANCE;
1085: } else {
1086: String locale = v2 == null ? null
1087: : v2 == ValueNull.INSTANCE ? null : v2
1088: .getString();
1089: String tz = v3 == null ? null
1090: : v3 == ValueNull.INSTANCE ? null : v3
1091: .getString();
1092: java.util.Date d = StringUtils.parseDateTime(v0
1093: .getString(), v1.getString(), locale, tz);
1094: result = ValueTimestamp.getNoCopy(new Timestamp(d
1095: .getTime()));
1096: }
1097: break;
1098: }
1099: case NULLIF:
1100: result = database.areEqual(v0, v1) ? ValueNull.INSTANCE
1101: : v0;
1102: break;
1103: // system
1104: case NEXTVAL: {
1105: Sequence sequence = getSequence(session, v0, v1);
1106: SequenceValue value = new SequenceValue(sequence);
1107: result = value.getValue(session);
1108: break;
1109: }
1110: case CURRVAL: {
1111: Sequence sequence = getSequence(session, v0, v1);
1112: result = ValueLong.get(sequence.getCurrentValue());
1113: break;
1114: }
1115: case CSVREAD: {
1116: String fileName = v0.getString();
1117: String columnList = v1 == null ? null : v1.getString();
1118: String charset = v2 == null ? null : v2.getString();
1119: String fieldSeparatorRead = v3 == null ? null : v3
1120: .getString();
1121: String fieldDelimiter = v4 == null ? null : v4.getString();
1122: String escapeCharacter = v5 == null ? null : v5.getString();
1123: Value v6 = getNullOrValue(session, args, 6);
1124: String nullString = v6 == null ? null : v6.getString();
1125: Csv csv = Csv.getInstance();
1126: setCsvDelimiterEscape(csv, fieldSeparatorRead,
1127: fieldDelimiter, escapeCharacter);
1128: csv.setNullString(nullString);
1129: char fieldSeparator = csv.getFieldSeparatorRead();
1130: String[] columns = StringUtils.arraySplit(columnList,
1131: fieldSeparator, true);
1132: ValueResultSet vr = ValueResultSet.get(csv.read(fileName,
1133: columns, charset));
1134: result = vr;
1135: break;
1136: }
1137: case LINK_SCHEMA: {
1138: session.getUser().checkAdmin();
1139: Connection conn = session.createConnection(false);
1140: ResultSet rs = LinkSchema.linkSchema(conn, v0.getString(),
1141: v1.getString(), v2.getString(), v3.getString(), v4
1142: .getString(), v5.getString());
1143: result = ValueResultSet.get(rs);
1144: break;
1145: }
1146: case CSVWRITE: {
1147: session.getUser().checkAdmin();
1148: Connection conn = session.createConnection(false);
1149: String charset = v2 == null ? null : v2.getString();
1150: String fieldSeparatorWrite = v3 == null ? null : v3
1151: .getString();
1152: String fieldDelimiter = v4 == null ? null : v4.getString();
1153: String escapeCharacter = v5 == null ? null : v5.getString();
1154: Value v6 = getNullOrValue(session, args, 6);
1155: String nullString = v6 == null ? null : v6.getString();
1156: Value v7 = getNullOrValue(session, args, 7);
1157: String lineSeparator = v7 == null ? null : v7.getString();
1158: Csv csv = Csv.getInstance();
1159: setCsvDelimiterEscape(csv, fieldSeparatorWrite,
1160: fieldDelimiter, escapeCharacter);
1161: csv.setNullString(nullString);
1162: if (lineSeparator != null) {
1163: csv.setLineSeparator(lineSeparator);
1164: }
1165: int rows = csv.write(conn, v0.getString(), v1.getString(),
1166: charset);
1167: result = ValueInt.get(rows);
1168: break;
1169: }
1170: case SET: {
1171: Variable var = (Variable) args[0];
1172: session.setVariable(var.getName(), v1);
1173: result = v1;
1174: break;
1175: }
1176: case FILE_READ: {
1177: session.getUser().checkAdmin();
1178: String fileName = v0.getString();
1179: boolean blob = args.length == 1;
1180: try {
1181: InputStream in = new AutoCloseInputStream(FileUtils
1182: .openFileInputStream(fileName));
1183: if (blob) {
1184: result = ValueLob.createBlob(in, -1, database);
1185: } else {
1186: Reader reader;
1187: if (v1 == ValueNull.INSTANCE) {
1188: reader = new InputStreamReader(in);
1189: } else {
1190: reader = new InputStreamReader(in, v1
1191: .getString());
1192: }
1193: result = ValueLob.createClob(reader, -1, database);
1194: }
1195: } catch (IOException e) {
1196: throw Message.convertIOException(e, fileName);
1197: }
1198: break;
1199: }
1200: default:
1201: throw Message.getInternalError("type=" + info.type);
1202: }
1203: return result;
1204: }
1205:
1206: private Sequence getSequence(Session session, Value v0, Value v1)
1207: throws SQLException {
1208: String schemaName, sequenceName;
1209: if (v1 == null) {
1210: schemaName = session.getCurrentSchemaName();
1211: sequenceName = StringUtils.toUpperEnglish(v0.getString());
1212: } else {
1213: schemaName = v0.getString();
1214: sequenceName = v1.getString();
1215: }
1216: return database.getSchema(schemaName).getSequence(sequenceName);
1217: }
1218:
1219: private int length(Value v) throws SQLException {
1220: switch (v.getType()) {
1221: case Value.BLOB:
1222: case Value.CLOB:
1223: case Value.BYTES:
1224: case Value.JAVA_OBJECT:
1225: return (int) v.getPrecision();
1226: default:
1227: return v.getString().length();
1228: }
1229: }
1230:
1231: private byte[] getPaddedArrayCopy(byte[] data, int blockSize) {
1232: int size = MathUtils.roundUp(data.length, blockSize);
1233: byte[] newData = new byte[size];
1234: System.arraycopy(data, 0, newData, 0, data.length);
1235: return newData;
1236: }
1237:
1238: private byte[] decrypt(String algorithm, byte[] key, byte[] data)
1239: throws SQLException {
1240: BlockCipher cipher = CipherFactory.getBlockCipher(algorithm);
1241: byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength());
1242: cipher.setKey(newKey);
1243: byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN);
1244: cipher.decrypt(newData, 0, newData.length);
1245: return newData;
1246: }
1247:
1248: private byte[] encrypt(String algorithm, byte[] key, byte[] data)
1249: throws SQLException {
1250: BlockCipher cipher = CipherFactory.getBlockCipher(algorithm);
1251: byte[] newKey = getPaddedArrayCopy(key, cipher.getKeyLength());
1252: cipher.setKey(newKey);
1253: byte[] newData = getPaddedArrayCopy(data, BlockCipher.ALIGN);
1254: cipher.encrypt(newData, 0, newData.length);
1255: return newData;
1256: }
1257:
1258: private byte[] getHash(String algorithm, byte[] bytes,
1259: int iterations) throws SQLException {
1260: SHA256 hash = CipherFactory.getHash(algorithm);
1261: for (int i = 0; i < iterations; i++) {
1262: bytes = hash.getHash(bytes);
1263: }
1264: return bytes;
1265: }
1266:
1267: private static int getDatePart(Timestamp d, int field) {
1268: Calendar c = Calendar.getInstance();
1269: c.setTime(d);
1270: int value = c.get(field);
1271: if (field == Calendar.MONTH) {
1272: value++;
1273: }
1274: return value;
1275: }
1276:
1277: // private static long datediffRound(String part, Date d1, Date d2)
1278: // throws SQLException {
1279: // // diff (yy, 31.12.2004, 1.1.2005) = 0
1280: // Integer p = (Integer) datePart.get(StringUtils.toUpperEnglish(part));
1281: // if (p == null) {
1282: // throw Message.getSQLException(ErrorCode.INVALID_VALUE_2,
1283: // new String[] { "part", part }, null);
1284: // }
1285: // int field = p.intValue();
1286: // long t1 = d1.getTime(), t2 = d2.getTime();
1287: // switch (field) {
1288: // case Calendar.MILLISECOND:
1289: // return t2 - t1;
1290: // case Calendar.SECOND:
1291: // return (t2 - t1) / 1000;
1292: // case Calendar.MINUTE:
1293: // return (t2 - t1) / 1000 / 60;
1294: // case Calendar.HOUR_OF_DAY:
1295: // return (t2 - t1) / 1000 / 60 / 60;
1296: // case Calendar.DATE:
1297: // return (t2 - t1) / 1000 / 60 / 60 / 24;
1298: // }
1299: // Calendar g1 = Calendar.getInstance();
1300: // g1.setTimeInMillis(t1);
1301: // int year1 = g1.get(Calendar.YEAR);
1302: // Calendar g2 = Calendar.getInstance();
1303: // g2.setTimeInMillis(t2);
1304: // int year2 = g2.get(Calendar.YEAR);
1305: // int result = year2 - year1;
1306: // if (field == Calendar.MONTH) {
1307: // int month1 = g1.get(Calendar.MONTH);
1308: // int month2 = g2.get(Calendar.MONTH);
1309: // result = 12 * result + (month2 - month1);
1310: // g2.set(Calendar.MONTH, month1);
1311: // }
1312: // g2.set(Calendar.YEAR, year1);
1313: // if (result > 0 && g1.after(g2)) {
1314: // result--;
1315: // } else if (result < 0 && g1.before(g2)) {
1316: // result++;
1317: // }
1318: // return result;
1319: // }
1320:
1321: private static int getDatePart(String part) throws SQLException {
1322: Integer p = (Integer) DATE_PART.get(StringUtils
1323: .toUpperEnglish(part));
1324: if (p == null) {
1325: throw Message.getSQLException(ErrorCode.INVALID_VALUE_2,
1326: new String[] { "date part", part });
1327: }
1328: return p.intValue();
1329: }
1330:
1331: private static Timestamp dateadd(String part, int count, Timestamp d)
1332: throws SQLException {
1333: int field = getDatePart(part);
1334: Calendar calendar = Calendar.getInstance();
1335: int nanos = d.getNanos() % 1000000;
1336: calendar.setTime(d);
1337: calendar.add(field, count);
1338: long t = calendar.getTime().getTime();
1339: Timestamp ts = new Timestamp(t);
1340: ts.setNanos(ts.getNanos() + nanos);
1341: return ts;
1342: }
1343:
1344: private static long datediff(String part, Timestamp d1, Timestamp d2)
1345: throws SQLException {
1346: // diff (yy, 31.12.2004, 1.1.2005) = 1
1347: int field = getDatePart(part);
1348: Calendar calendar = Calendar.getInstance();
1349: long t1 = d1.getTime(), t2 = d2.getTime();
1350: // need to convert to UTC, otherwise we get inconsistent results with
1351: // certain timezones (those that are 30 minutes off)
1352: TimeZone zone = calendar.getTimeZone();
1353: calendar.setTime(d1);
1354: t1 += zone.getOffset(calendar.get(Calendar.ERA), calendar
1355: .get(Calendar.YEAR), calendar.get(Calendar.MONTH),
1356: calendar.get(Calendar.DAY_OF_MONTH), calendar
1357: .get(Calendar.DAY_OF_WEEK), calendar
1358: .get(Calendar.MILLISECOND));
1359: calendar.setTime(d2);
1360: t2 += zone.getOffset(calendar.get(Calendar.ERA), calendar
1361: .get(Calendar.YEAR), calendar.get(Calendar.MONTH),
1362: calendar.get(Calendar.DAY_OF_MONTH), calendar
1363: .get(Calendar.DAY_OF_WEEK), calendar
1364: .get(Calendar.MILLISECOND));
1365: switch (field) {
1366: case Calendar.MILLISECOND:
1367: return t2 - t1;
1368: case Calendar.SECOND:
1369: case Calendar.MINUTE:
1370: case Calendar.HOUR_OF_DAY: {
1371: // first 'normalize' the numbers so both are not negative
1372: long hour = 60 * 60 * 1000;
1373: long add = Math.min(t1 / hour * hour, t2 / hour * hour);
1374: t1 -= add;
1375: t2 -= add;
1376: switch (field) {
1377: case Calendar.SECOND:
1378: return t2 / 1000 - t1 / 1000;
1379: case Calendar.MINUTE:
1380: return t2 / (60 * 1000) - t1 / (60 * 1000);
1381: case Calendar.HOUR_OF_DAY:
1382: return t2 / hour - t1 / hour;
1383: default:
1384: throw Message.getInternalError("field:" + field);
1385: }
1386: }
1387: case Calendar.DATE:
1388: return t2 / (24 * 60 * 60 * 1000) - t1
1389: / (24 * 60 * 60 * 1000);
1390: default:
1391: break;
1392: }
1393: calendar.setTime(new Timestamp(t1));
1394: int year1 = calendar.get(Calendar.YEAR);
1395: int month1 = calendar.get(Calendar.MONTH);
1396: calendar.setTime(new Timestamp(t2));
1397: int year2 = calendar.get(Calendar.YEAR);
1398: int month2 = calendar.get(Calendar.MONTH);
1399: int result = year2 - year1;
1400: if (field == Calendar.MONTH) {
1401: result = 12 * result + (month2 - month1);
1402: }
1403: return result;
1404: }
1405:
1406: private static String substring(String s, int start, int length) {
1407: int len = s.length();
1408: start--;
1409: if (start < 0) {
1410: start = 0;
1411: }
1412: if (length < 0) {
1413: length = 0;
1414: }
1415: start = (start > len) ? len : start;
1416: if (start + length > len) {
1417: length = len - start;
1418: }
1419: return s.substring(start, start + length);
1420: }
1421:
1422: private static String trim(String s, boolean leading,
1423: boolean trailing, String sp) {
1424: char space = (sp == null || sp.length() < 1) ? ' ' : sp
1425: .charAt(0);
1426: // TODO function trim: HSQLDB says 'tabs are not removed', but they are.
1427: // check what other databases do
1428: if (leading) {
1429: int len = s.length(), i = 0;
1430: while (i < len && s.charAt(i) == space) {
1431: i++;
1432: }
1433: s = (i == 0) ? s : s.substring(i);
1434: }
1435: if (trailing) {
1436: int endIndex = s.length() - 1;
1437: int i = endIndex;
1438: while (i >= 0 && s.charAt(i) == space) {
1439: i--;
1440: }
1441: s = i == endIndex ? s : s.substring(0, i + 1);
1442: }
1443: return s;
1444: }
1445:
1446: private static String replace(String s, String replace, String with) {
1447: if (replace == null || replace.length() == 0) {
1448: // avoid out of memory
1449: return s;
1450: }
1451: StringBuffer buff = new StringBuffer(s.length());
1452: int start = 0;
1453: int len = replace.length();
1454: while (true) {
1455: int i = s.indexOf(replace, start);
1456: if (i == -1) {
1457: break;
1458: }
1459: buff.append(s.substring(start, i));
1460: buff.append(with);
1461: start = i + len;
1462: }
1463: buff.append(s.substring(start));
1464: return buff.toString();
1465: }
1466:
1467: private static String repeat(String s, int count) {
1468: StringBuffer buff = new StringBuffer(s.length() * count);
1469: while (count-- > 0) {
1470: buff.append(s);
1471: }
1472: return buff.toString();
1473: }
1474:
1475: private static String rawToHex(String s) {
1476: StringBuffer buff = new StringBuffer(4 * s.length());
1477: for (int i = 0; i < s.length(); i++) {
1478: String hex = Integer.toHexString(s.charAt(i) & 0xffff);
1479: for (int j = hex.length(); j < 4; j++) {
1480: buff.append('0');
1481: }
1482: buff.append(hex);
1483: }
1484: return buff.toString();
1485: }
1486:
1487: private static int locate(String search, String s, int start) {
1488: if (start < 0) {
1489: int i = s.length() + start;
1490: return s.lastIndexOf(search, i) + 1;
1491: } else {
1492: int i = (start == 0) ? 0 : start - 1;
1493: return s.indexOf(search, i) + 1;
1494: }
1495: }
1496:
1497: private static String right(String s, int count) {
1498: if (count < 0) {
1499: count = 0;
1500: } else if (count > s.length()) {
1501: count = s.length();
1502: }
1503: return s.substring(s.length() - count);
1504: }
1505:
1506: private static String left(String s, int count) {
1507: if (count < 0) {
1508: count = 0;
1509: } else if (count > s.length()) {
1510: count = s.length();
1511: }
1512: return s.substring(0, count);
1513: }
1514:
1515: private static String insert(String s1, int start, int length,
1516: String s2) {
1517: if (s1 == null) {
1518: return s2;
1519: }
1520: if (s2 == null) {
1521: return s1;
1522: }
1523: int len1 = s1.length();
1524: int len2 = s2.length();
1525: start--;
1526: if (start < 0 || length <= 0 || len2 == 0 || start > len1) {
1527: return s1;
1528: }
1529: if (start + length > len1) {
1530: length = len1 - start;
1531: }
1532: return s1.substring(0, start) + s2
1533: + s1.substring(start + length);
1534: }
1535:
1536: private static String hexToRaw(String s) throws SQLException {
1537: // TODO function hextoraw compatibility with oracle
1538: int len = s.length();
1539: if (len % 4 != 0) {
1540: throw Message.getSQLException(
1541: ErrorCode.DATA_CONVERSION_ERROR_1, s);
1542: }
1543: StringBuffer buff = new StringBuffer(len / 4);
1544: for (int i = 0; i < len; i += 4) {
1545: try {
1546: char raw = (char) Integer.parseInt(s
1547: .substring(i, i + 4), 16);
1548: buff.append(raw);
1549: } catch (NumberFormatException e) {
1550: throw Message.getSQLException(
1551: ErrorCode.DATA_CONVERSION_ERROR_1, s);
1552: }
1553: }
1554: return buff.toString();
1555: }
1556:
1557: private static int getDifference(String s1, String s2) {
1558: // TODO function difference: compatibility with SQL Server and HSQLDB
1559: s1 = getSoundex(s1);
1560: s2 = getSoundex(s2);
1561: int e = 0;
1562: for (int i = 0; i < 4; i++) {
1563: if (s1.charAt(i) == s2.charAt(i)) {
1564: e++;
1565: }
1566: }
1567: return e;
1568: }
1569:
1570: private double roundmagic(double d) {
1571: if ((d < 0.0000000000001) && (d > -0.0000000000001)) {
1572: return 0.0;
1573: }
1574: if ((d > 1000000000000.) || (d < -1000000000000.)) {
1575: return d;
1576: }
1577: StringBuffer s = new StringBuffer();
1578: s.append(d);
1579: if (s.toString().indexOf("E") >= 0) {
1580: return d;
1581: }
1582: int len = s.length();
1583: if (len < 16) {
1584: return d;
1585: }
1586: if (s.toString().indexOf(".") > len - 3) {
1587: return d;
1588: }
1589: s.delete(len - 2, len);
1590: len -= 2;
1591: char c1 = s.charAt(len - 2);
1592: char c2 = s.charAt(len - 3);
1593: char c3 = s.charAt(len - 4);
1594: if ((c1 == '0') && (c2 == '0') && (c3 == '0')) {
1595: s.setCharAt(len - 1, '0');
1596: } else if ((c1 == '9') && (c2 == '9') && (c3 == '9')) {
1597: s.setCharAt(len - 1, '9');
1598: s.append('9');
1599: s.append('9');
1600: s.append('9');
1601: }
1602: return Double.valueOf(s.toString()).doubleValue();
1603: }
1604:
1605: private static String getSoundex(String s) {
1606: int len = s.length();
1607: char[] chars = new char[] { '0', '0', '0', '0' };
1608: char lastDigit = '0';
1609: for (int i = 0, j = 0; i < len && j < 4; i++) {
1610: char c = s.charAt(i);
1611: char newDigit = c > SOUNDEX_INDEX.length ? 0
1612: : SOUNDEX_INDEX[c];
1613: if (newDigit != 0) {
1614: if (j == 0) {
1615: chars[j++] = c;
1616: lastDigit = newDigit;
1617: } else if (newDigit <= '6') {
1618: if (newDigit != lastDigit) {
1619: chars[j++] = newDigit;
1620: lastDigit = newDigit;
1621: }
1622: } else if (newDigit == '7') {
1623: lastDigit = newDigit;
1624: }
1625: }
1626: }
1627: return new String(chars);
1628: }
1629:
1630: public int getType() {
1631: return dataType;
1632: }
1633:
1634: public void mapColumns(ColumnResolver resolver, int level)
1635: throws SQLException {
1636: for (int i = 0; i < args.length; i++) {
1637: args[i].mapColumns(resolver, level);
1638: }
1639: }
1640:
1641: protected void checkParameterCount(int len) throws SQLException {
1642: int min = 0, max = Integer.MAX_VALUE;
1643: switch (info.type) {
1644: case COALESCE:
1645: case CSVREAD:
1646: case LEAST:
1647: case GREATEST:
1648: min = 1;
1649: break;
1650: case NOW:
1651: case CURRENT_TIMESTAMP:
1652: case RAND:
1653: max = 1;
1654: break;
1655: case COMPRESS:
1656: case LTRIM:
1657: case RTRIM:
1658: case TRIM:
1659: case FILE_READ:
1660: min = 1;
1661: max = 2;
1662: break;
1663: case REPLACE:
1664: case LOCATE:
1665: case INSTR:
1666: case SUBSTR:
1667: case SUBSTRING:
1668: case LPAD:
1669: case RPAD:
1670: min = 2;
1671: max = 3;
1672: break;
1673: case CASE:
1674: case CONCAT:
1675: case CSVWRITE:
1676: min = 2;
1677: break;
1678: case XMLNODE:
1679: min = 1;
1680: max = 3;
1681: break;
1682: case FORMATDATETIME:
1683: case PARSEDATETIME:
1684: min = 2;
1685: max = 4;
1686: break;
1687: case CURRVAL:
1688: case NEXTVAL:
1689: min = 1;
1690: max = 2;
1691: break;
1692: default:
1693: throw Message.getInternalError("type=" + info.type);
1694: }
1695: boolean ok = (len >= min) && (len <= max);
1696: if (!ok) {
1697: throw Message.getSQLException(
1698: ErrorCode.INVALID_PARAMETER_COUNT_2, new String[] {
1699: info.name, min + ".." + max });
1700: }
1701: }
1702:
1703: public void doneWithParameters() throws SQLException {
1704: if (info.parameterCount == VAR_ARGS) {
1705: int len = varArgs.size();
1706: checkParameterCount(len);
1707: args = new Expression[len];
1708: varArgs.toArray(args);
1709: varArgs = null;
1710: } else {
1711: int len = args.length;
1712: if (len > 0 && args[len - 1] == null) {
1713: throw Message.getSQLException(
1714: ErrorCode.INVALID_PARAMETER_COUNT_2,
1715: new String[] { info.name, "" + len });
1716: }
1717: }
1718: }
1719:
1720: /**
1721: * Set the result data type of this function.
1722: *
1723: * @param dataType the data type
1724: * @param precision the precision
1725: * @param scale the scale
1726: * @param displaySize the display size
1727: */
1728: public void setDataType(int dataType, long precision, int scale,
1729: int displaySize) {
1730: this .dataType = dataType;
1731: this .precision = precision;
1732: this .displaySize = displaySize;
1733: this .scale = scale;
1734: }
1735:
1736: public void setDataType(Column col) {
1737: dataType = col.getType();
1738: precision = col.getPrecision();
1739: displaySize = col.getDisplaySize();
1740: scale = col.getScale();
1741: }
1742:
1743: public Expression optimize(Session session) throws SQLException {
1744: boolean allConst = info.isDeterministic;
1745: for (int i = 0; i < args.length; i++) {
1746: Expression e = args[i].optimize(session);
1747: args[i] = e;
1748: if (!e.isConstant()) {
1749: allConst = false;
1750: }
1751: }
1752: Expression p0 = args.length < 1 ? null : args[0];
1753: switch (info.type) {
1754: case IFNULL:
1755: case NULLIF:
1756: case COALESCE:
1757: case LEAST:
1758: case GREATEST: {
1759: dataType = Value.UNKNOWN;
1760: scale = 0;
1761: precision = 0;
1762: displaySize = 0;
1763: for (int i = 0; i < args.length; i++) {
1764: Expression e = args[i];
1765: if (e != ValueExpression.NULL
1766: && e.getType() != Value.UNKNOWN) {
1767: dataType = Value.getHigherOrder(dataType, e
1768: .getType());
1769: scale = Math.max(scale, e.getScale());
1770: precision = Math.max(precision, e.getPrecision());
1771: displaySize = Math.max(displaySize, e
1772: .getDisplaySize());
1773: }
1774: }
1775: if (dataType == Value.UNKNOWN) {
1776: dataType = Value.STRING;
1777: scale = 0;
1778: precision = Integer.MAX_VALUE;
1779: displaySize = Integer.MAX_VALUE;
1780: }
1781: break;
1782: }
1783: case CASEWHEN:
1784: dataType = Value.getHigherOrder(args[1].getType(), args[2]
1785: .getType());
1786: precision = Math.max(args[1].getPrecision(), args[2]
1787: .getPrecision());
1788: displaySize = Math.max(args[1].getDisplaySize(), args[2]
1789: .getDisplaySize());
1790: scale = Math.max(args[1].getScale(), args[2].getScale());
1791: break;
1792: case CAST:
1793: case CONVERT:
1794: // data type, precision and scale is already set
1795: break;
1796: case ABS:
1797: case FLOOR:
1798: case RADIANS:
1799: case ROUND:
1800: case TRUNCATE:
1801: case POWER:
1802: case ARRAY_GET:
1803: dataType = p0.getType();
1804: scale = p0.getScale();
1805: precision = p0.getPrecision();
1806: displaySize = p0.getDisplaySize();
1807: if (dataType == Value.NULL) {
1808: dataType = Value.INT;
1809: precision = ValueInt.PRECISION;
1810: displaySize = ValueInt.DISPLAY_SIZE;
1811: scale = 0;
1812: }
1813: break;
1814: case SET: {
1815: Expression p1 = args[1];
1816: dataType = p1.getType();
1817: precision = p1.getPrecision();
1818: scale = p1.getScale();
1819: displaySize = p1.getDisplaySize();
1820: if (!(p0 instanceof Variable)) {
1821: throw Message.getSQLException(
1822: ErrorCode.CAN_ONLY_ASSIGN_TO_VARIABLE_1, p0
1823: .getSQL());
1824: }
1825: break;
1826: }
1827: case FILE_READ: {
1828: if (args.length == 1) {
1829: dataType = Value.BLOB;
1830: } else {
1831: dataType = Value.CLOB;
1832: }
1833: precision = Integer.MAX_VALUE;
1834: scale = 0;
1835: displaySize = Integer.MAX_VALUE;
1836: break;
1837: }
1838: default:
1839: dataType = info.dataType;
1840: precision = 0;
1841: displaySize = 0;
1842: scale = 0;
1843: }
1844: if (allConst) {
1845: return ValueExpression.get(getValue(session));
1846: }
1847: return this ;
1848: }
1849:
1850: public void setEvaluatable(TableFilter tableFilter, boolean b) {
1851: for (int i = 0; i < args.length; i++) {
1852: Expression e = args[i];
1853: if (e != null) {
1854: e.setEvaluatable(tableFilter, b);
1855: }
1856: }
1857: }
1858:
1859: public int getScale() {
1860: return scale;
1861: }
1862:
1863: public long getPrecision() {
1864: if (precision == 0) {
1865: calculatePrecisionAndDisplaySize();
1866: }
1867: return precision;
1868: }
1869:
1870: public int getDisplaySize() {
1871: if (precision == 0) {
1872: calculatePrecisionAndDisplaySize();
1873: }
1874: return displaySize;
1875: }
1876:
1877: private void calculatePrecisionAndDisplaySize() {
1878: switch (info.type) {
1879: case ENCRYPT:
1880: case DECRYPT:
1881: precision = args[2].getPrecision();
1882: displaySize = args[2].getDisplaySize();
1883: break;
1884: case COMPRESS:
1885: precision = args[0].getPrecision();
1886: displaySize = args[0].getDisplaySize();
1887: break;
1888: case CHAR:
1889: precision = 1;
1890: displaySize = 1;
1891: break;
1892: case CONCAT:
1893: precision = 0;
1894: displaySize = 0;
1895: for (int i = 0; i < args.length; i++) {
1896: precision += args[i].getPrecision();
1897: displaySize = MathUtils
1898: .convertLongToInt((long) displaySize
1899: + args[i].getDisplaySize());
1900: if (precision < 0) {
1901: precision = Long.MAX_VALUE;
1902: }
1903: }
1904: break;
1905: case HEXTORAW:
1906: precision = (args[0].getPrecision() + 3) / 4;
1907: displaySize = MathUtils.convertLongToInt(precision);
1908: break;
1909: case LCASE:
1910: case LTRIM:
1911: case RIGHT:
1912: case RTRIM:
1913: case UCASE:
1914: case LOWER:
1915: case UPPER:
1916: case TRIM:
1917: case STRINGDECODE:
1918: case UTF8TOSTRING:
1919: precision = args[0].getPrecision();
1920: displaySize = args[0].getDisplaySize();
1921: break;
1922: case RAWTOHEX:
1923: precision = args[0].getPrecision() * 4;
1924: displaySize = MathUtils.convertLongToInt(precision);
1925: break;
1926: case SOUNDEX:
1927: precision = 4;
1928: displaySize = (int) precision;
1929: break;
1930: case DAYNAME:
1931: case MONTHNAME:
1932: precision = 20; // day and month names may be long in some languages
1933: displaySize = (int) precision;
1934: break;
1935: }
1936: }
1937:
1938: public String getSQL() {
1939: StringBuffer buff = new StringBuffer();
1940: buff.append(info.name);
1941: buff.append('(');
1942: switch (info.type) {
1943: case CAST: {
1944: buff.append(args[0].getSQL());
1945: buff.append(" AS ");
1946: buff.append(new Column(null, dataType, precision, scale,
1947: displaySize).getCreateSQL());
1948: break;
1949: }
1950: case CONVERT: {
1951: buff.append(args[0].getSQL());
1952: buff.append(",");
1953: buff.append(new Column(null, dataType, precision, scale,
1954: displaySize).getCreateSQL());
1955: break;
1956: }
1957: case EXTRACT: {
1958: ValueString v = (ValueString) ((ValueExpression) args[0])
1959: .getValue(null);
1960: buff.append(v.getString());
1961: buff.append(" FROM ");
1962: buff.append(args[1].getSQL());
1963: break;
1964: }
1965: default: {
1966: for (int i = 0; i < args.length; i++) {
1967: if (i > 0) {
1968: buff.append(", ");
1969: }
1970: Expression e = args[i];
1971: buff.append(e.getSQL());
1972: }
1973: }
1974: }
1975: buff.append(')');
1976: return buff.toString();
1977: }
1978:
1979: public void updateAggregate(Session session) throws SQLException {
1980: for (int i = 0; i < args.length; i++) {
1981: Expression e = args[i];
1982: if (e != null) {
1983: e.updateAggregate(session);
1984: }
1985: }
1986: }
1987:
1988: public int getFunctionType() {
1989: return info.type;
1990: }
1991:
1992: public String getName() {
1993: return info.name;
1994: }
1995:
1996: public int getParameterCount() {
1997: return args.length;
1998: }
1999:
2000: public ValueResultSet getValueForColumnList(Session session,
2001: Expression[] args) throws SQLException {
2002: switch (info.type) {
2003: case CSVREAD: {
2004: String fileName = args[0].getValue(session).getString();
2005: if (fileName == null) {
2006: throw Message.getSQLException(
2007: ErrorCode.PARAMETER_NOT_SET_1, "fileName");
2008: }
2009: String columnList = args.length < 2 ? null : args[1]
2010: .getValue(session).getString();
2011: String charset = args.length < 3 ? null : args[2].getValue(
2012: session).getString();
2013: String fieldSeparatorRead = args.length < 4 ? null
2014: : args[3].getValue(session).getString();
2015: String fieldDelimiter = args.length < 5 ? null : args[4]
2016: .getValue(session).getString();
2017: String escapeCharacter = args.length < 6 ? null : args[5]
2018: .getValue(session).getString();
2019: Csv csv = Csv.getInstance();
2020: setCsvDelimiterEscape(csv, fieldSeparatorRead,
2021: fieldDelimiter, escapeCharacter);
2022: char fieldSeparator = csv.getFieldSeparatorRead();
2023: String[] columns = StringUtils.arraySplit(columnList,
2024: fieldSeparator, true);
2025: ResultSet rs = csv.read(fileName, columns, charset);
2026: ValueResultSet vr = ValueResultSet.getCopy(rs, 0);
2027: return vr;
2028: }
2029: default:
2030: break;
2031: }
2032: return (ValueResultSet) getValueWithArgs(session, args);
2033: }
2034:
2035: private void setCsvDelimiterEscape(Csv csv, String fieldSeparator,
2036: String fieldDelimiter, String escapeCharacter) {
2037: if (fieldSeparator != null) {
2038: csv.setFieldSeparatorWrite(fieldSeparator);
2039: if (fieldSeparator.length() > 0) {
2040: char fs = fieldSeparator.charAt(0);
2041: csv.setFieldSeparatorRead(fs);
2042: }
2043: }
2044: if (fieldDelimiter != null) {
2045: char fd = fieldDelimiter.length() == 0 ? 0 : fieldDelimiter
2046: .charAt(0);
2047: csv.setFieldDelimiter(fd);
2048: }
2049: if (escapeCharacter != null) {
2050: char ec = escapeCharacter.length() == 0 ? 0
2051: : escapeCharacter.charAt(0);
2052: csv.setEscapeCharacter(ec);
2053: }
2054: }
2055:
2056: public Expression[] getArgs() {
2057: return args;
2058: }
2059:
2060: public boolean isEverything(ExpressionVisitor visitor) {
2061: if (visitor.type == ExpressionVisitor.DETERMINISTIC
2062: && !info.isDeterministic) {
2063: return false;
2064: }
2065: for (int i = 0; i < args.length; i++) {
2066: Expression e = args[i];
2067: if (e != null && !e.isEverything(visitor)) {
2068: return false;
2069: }
2070: }
2071: return true;
2072: }
2073:
2074: public int getCost() {
2075: int cost = 3;
2076: for (int i = 0; i < args.length; i++) {
2077: cost += args[i].getCost();
2078: }
2079: return cost;
2080: }
2081:
2082: }
|