帆软使用的第三方框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

3872 lines
139 KiB

/* Copyright (c) 2001-2016, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.fr.third.org.hsqldb;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.fr.third.org.hsqldb.error.ErrorCode;
import com.fr.third.org.hsqldb.lib.ArrayUtil;
import com.fr.third.org.hsqldb.lib.StringConverter;
import com.fr.third.org.hsqldb.lib.StringUtil;
import com.fr.third.org.hsqldb.map.ValuePool;
import com.fr.third.org.hsqldb.types.ArrayType;
import com.fr.third.org.hsqldb.types.BinaryType;
import com.fr.third.org.hsqldb.types.BlobData;
import com.fr.third.org.hsqldb.types.ClobData;
import com.fr.third.org.hsqldb.types.IntervalMonthData;
import com.fr.third.org.hsqldb.types.IntervalSecondData;
import com.fr.third.org.hsqldb.types.IntervalType;
import com.fr.third.org.hsqldb.types.TimeData;
import com.fr.third.org.hsqldb.types.TimestampData;
import com.fr.third.org.hsqldb.error.Error;
import com.fr.third.org.hsqldb.lib.HsqlArrayList;
import com.fr.third.org.hsqldb.lib.IntKeyIntValueHashMap;
import com.fr.third.org.hsqldb.map.BitMap;
import com.fr.third.org.hsqldb.persist.Crypto;
import com.fr.third.org.hsqldb.persist.HsqlDatabaseProperties;
import com.fr.third.org.hsqldb.types.BinaryData;
import com.fr.third.org.hsqldb.types.CharacterType;
import com.fr.third.org.hsqldb.types.DTIType;
import com.fr.third.org.hsqldb.types.DateTimeType;
import com.fr.third.org.hsqldb.types.LobData;
import com.fr.third.org.hsqldb.types.NumberType;
import com.fr.third.org.hsqldb.types.Type;
import com.fr.third.org.hsqldb.types.Types;
/**
* Implementation of HSQLDB functions that are not defined by the
* SQL standard.<p>
*
* Some functions are translated into equivalent SQL Standard functions.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.3.4
* @since 1.9.0
*/
public class FunctionCustom extends FunctionSQL {
public static final String[] openGroupNumericFunctions = {
"ABS", "ACOS", "ASIN", "ATAN", "ATAN2", "BITAND", "BITOR", "BITXOR",
"CEILING", "COS", "COT", "DEGREES", "EXP", "FLOOR", "LOG", "LOG10",
"MOD", "PI", "POWER", "RADIANS", "RAND", "ROUND", "ROUNDMAGIC", "SIGN",
"SIN", "SQRT", "TAN", "TRUNCATE"
};
public static final String[] openGroupStringFunctions = {
"ASCII", "CHAR", "CONCAT", "DIFFERENCE", "HEXTORAW", "INSERT", "LCASE",
"LEFT", "LENGTH", "LOCATE", "LTRIM", "RAWTOHEX", "REPEAT", "REPLACE",
"RIGHT", "RTRIM", "SOUNDEX", "SPACE", "SUBSTR", "UCASE",
};
public static final String[] openGroupDateTimeFunctions = {
"CURDATE", "CURTIME", "DATEDIFF", "DAYNAME", "DAYOFMONTH", "DAYOFWEEK",
"DAYOFYEAR", "HOUR", "MINUTE", "MONTH", "MONTHNAME", "NOW", "QUARTER",
"SECOND", "SECONDS_SINCE_MIDNIGHT", "TIMESTAMPADD", "TIMESTAMPDIFF",
"TO_CHAR", "WEEK", "YEAR"
};
public static final String[] openGroupSystemFunctions = {
"DATABASE", "IFNULL", "USER"
};
//
private static final int FUNC_ACOS = 71;
private static final int FUNC_ACTION_ID = 72;
private static final int FUNC_ADD_MONTHS = 73;
private static final int FUNC_ASCII = 74;
private static final int FUNC_ASIN = 75;
private static final int FUNC_ATAN = 76;
private static final int FUNC_ATAN2 = 77;
private static final int FUNC_BITAND = 78;
private static final int FUNC_BITANDNOT = 79;
private static final int FUNC_BITNOT = 80;
private static final int FUNC_BITOR = 81;
private static final int FUNC_BITXOR = 82;
private static final int FUNC_CHAR = 83;
private static final int FUNC_CONCAT = 84;
private static final int FUNC_COS = 85;
private static final int FUNC_COT = 86;
private static final int FUNC_CRYPT_KEY = 87;
private static final int FUNC_DATABASE = 88;
private static final int FUNC_DATABASE_ISOLATION_LEVEL = 89;
private static final int FUNC_DATABASE_NAME = 90;
private static final int FUNC_DATABASE_TIMEZONE = 91;
private static final int FUNC_DATABASE_VERSION = 92;
private static final int FUNC_DATE_ADD = 93;
private static final int FUNC_DATE_SUB = 94;
private static final int FUNC_DATEADD = 95;
private static final int FUNC_DATEDIFF = 96;
private static final int FUNC_DAYS = 97;
private static final int FUNC_DBTIMEZONE = 98;
private static final int FUNC_DEGREES = 99;
private static final int FUNC_DIAGNOSTICS = 100;
private static final int FUNC_DIFFERENCE = 101;
private static final int FUNC_FROM_TZ = 102;
private static final int FUNC_HEXTORAW = 103;
private static final int FUNC_IDENTITY = 104;
private static final int FUNC_INSTR = 105;
private static final int FUNC_ISAUTOCOMMIT = 106;
private static final int FUNC_ISOLATION_LEVEL = 107;
private static final int FUNC_ISREADONLYDATABASE = 108;
private static final int FUNC_ISREADONLYDATABASEFILES = 109;
private static final int FUNC_ISREADONLYSESSION = 110;
private static final int FUNC_LAST_DAY = 111;
private static final int FUNC_LEFT = 112;
private static final int FUNC_LOAD_FILE = 113;
private static final int FUNC_LOB_ID = 114;
private static final int FUNC_LOCATE = 115;
private static final int FUNC_LOG10 = 116;
private static final int FUNC_LPAD = 117;
private static final int FUNC_LTRIM = 118;
private static final int FUNC_MONTHS_BETWEEN = 119;
private static final int FUNC_NEW_TIME = 120;
private static final int FUNC_NEXT_DAY = 121;
private static final int FUNC_NUMTODSINTERVAL = 122;
private static final int FUNC_NUMTOYMINTERVAL = 123;
private static final int FUNC_PI = 124;
private static final int FUNC_POSITION_ARRAY = 125;
private static final int FUNC_RADIANS = 126;
private static final int FUNC_RAND = 127;
private static final int FUNC_RAWTOHEX = 128;
private static final int FUNC_REGEXP_MATCHES = 129;
private static final int FUNC_REGEXP_REPLACE = 130;
private static final int FUNC_REGEXP_SUBSTRING = 131;
private static final int FUNC_REGEXP_SUBSTRING_ARRAY = 132;
private static final int FUNC_REPEAT = 133;
private static final int FUNC_REPLACE = 134;
private static final int FUNC_REVERSE = 135;
private static final int FUNC_RIGHT = 136;
private static final int FUNC_ROUND = 137;
private static final int FUNC_ROUNDMAGIC = 138;
private static final int FUNC_RPAD = 139;
private static final int FUNC_RTRIM = 140;
private static final int FUNC_SECONDS_MIDNIGHT = 141;
private static final int FUNC_SEQUENCE_ARRAY = 142;
private static final int FUNC_SESSION_ID = 143;
private static final int FUNC_SESSION_ISOLATION_LEVEL = 144;
private static final int FUNC_SESSION_TIMEZONE = 145;
private static final int FUNC_SESSIONTIMEZONE = 146;
private static final int FUNC_SIGN = 147;
private static final int FUNC_SIN = 148;
private static final int FUNC_SOUNDEX = 149;
private static final int FUNC_SORT_ARRAY = 150;
private static final int FUNC_SPACE = 151;
private static final int FUNC_SUBSTR = 152;
private static final int FUNC_SYS_EXTRACT_UTC = 153;
private static final int FUNC_SYSDATE = 154;
private static final int FUNC_SYSTIMESTAMP = 155;
private static final int FUNC_TAN = 156;
private static final int FUNC_TIMESTAMP = 157;
private static final int FUNC_TIMESTAMP_WITH_ZONE = 158;
private static final int FUNC_TIMESTAMPADD = 159;
private static final int FUNC_TIMESTAMPDIFF = 160;
private static final int FUNC_TIMEZONE = 161;
private static final int FUNC_TO_CHAR = 162;
private static final int FUNC_TO_DATE = 163;
private static final int FUNC_TO_DSINTERVAL = 164;
private static final int FUNC_TO_YMINTERVAL = 165;
private static final int FUNC_TO_NUMBER = 166;
private static final int FUNC_TO_TIMESTAMP = 167;
private static final int FUNC_TO_TIMESTAMP_TZ = 168;
private static final int FUNC_TRANSACTION_CONTROL = 169;
private static final int FUNC_TRANSACTION_ID = 170;
private static final int FUNC_TRANSACTION_SIZE = 171;
private static final int FUNC_TRANSLATE = 172;
private static final int FUNC_TRUNC = 173;
private static final int FUNC_TRUNCATE = 174;
private static final int FUNC_UUID = 175;
private static final int FUNC_UNIX_TIMESTAMP = 176;
private static final int FUNC_UNIX_MILLIS = 177;
private static final int FUNC_SQLCODE = 182;
private static final int FUNC_SQLERRM = 183;
//
static final IntKeyIntValueHashMap customRegularFuncMap =
new IntKeyIntValueHashMap();
//J-
static {
nonDeterministicFuncSet.add(FUNC_ACTION_ID);
nonDeterministicFuncSet.add(FUNC_CRYPT_KEY);
nonDeterministicFuncSet.add(FUNC_DATABASE);
nonDeterministicFuncSet.add(FUNC_DATABASE_ISOLATION_LEVEL);
nonDeterministicFuncSet.add(FUNC_DATABASE_TIMEZONE);
nonDeterministicFuncSet.add(FUNC_IDENTITY);
nonDeterministicFuncSet.add(FUNC_ISAUTOCOMMIT);
nonDeterministicFuncSet.add(FUNC_ISREADONLYSESSION);
nonDeterministicFuncSet.add(FUNC_ISREADONLYDATABASE);
nonDeterministicFuncSet.add(FUNC_ISREADONLYDATABASEFILES);
nonDeterministicFuncSet.add(FUNC_ISOLATION_LEVEL);
nonDeterministicFuncSet.add(FUNC_SESSION_ID);
nonDeterministicFuncSet.add(FUNC_SESSION_ISOLATION_LEVEL);
nonDeterministicFuncSet.add(FUNC_SESSION_TIMEZONE);
nonDeterministicFuncSet.add(FUNC_SESSIONTIMEZONE);
nonDeterministicFuncSet.add(FUNC_SYSDATE);
nonDeterministicFuncSet.add(FUNC_SYSTIMESTAMP);
nonDeterministicFuncSet.add(FUNC_TIMESTAMP);
nonDeterministicFuncSet.add(FUNC_TIMEZONE);
nonDeterministicFuncSet.add(FUNC_TRANSACTION_CONTROL);
nonDeterministicFuncSet.add(FUNC_TRANSACTION_ID);
nonDeterministicFuncSet.add(FUNC_TRANSACTION_SIZE);
nonDeterministicFuncSet.add(FUNC_UUID);
nonDeterministicFuncSet.add(FUNC_UNIX_TIMESTAMP);
nonDeterministicFuncSet.add(FUNC_UNIX_MILLIS);
//
customRegularFuncMap.put(Tokens.ACOS, FUNC_ACOS);
customRegularFuncMap.put(Tokens.ACTION_ID, FUNC_ACTION_ID);
customRegularFuncMap.put(Tokens.ADD_MONTHS, FUNC_ADD_MONTHS);
customRegularFuncMap.put(Tokens.ARRAY_SORT, FUNC_SORT_ARRAY);
customRegularFuncMap.put(Tokens.ASCII, FUNC_ASCII);
customRegularFuncMap.put(Tokens.ASIN, FUNC_ASIN);
customRegularFuncMap.put(Tokens.ATAN, FUNC_ATAN);
customRegularFuncMap.put(Tokens.ATAN2, FUNC_ATAN2);
customRegularFuncMap.put(Tokens.BITAND, FUNC_BITAND);
customRegularFuncMap.put(Tokens.BITANDNOT, FUNC_BITANDNOT);
customRegularFuncMap.put(Tokens.BITLENGTH, FUNC_BIT_LENGTH);
customRegularFuncMap.put(Tokens.BITNOT, FUNC_BITNOT);
customRegularFuncMap.put(Tokens.BITOR, FUNC_BITOR);
customRegularFuncMap.put(Tokens.BITXOR, FUNC_BITXOR);
customRegularFuncMap.put(Tokens.CHAR, FUNC_CHAR);
customRegularFuncMap.put(Tokens.CHR, FUNC_CHAR);
customRegularFuncMap.put(Tokens.CONCAT_WORD, FUNC_CONCAT);
customRegularFuncMap.put(Tokens.COS, FUNC_COS);
customRegularFuncMap.put(Tokens.COT, FUNC_COT);
customRegularFuncMap.put(Tokens.CRYPT_KEY, FUNC_CRYPT_KEY);
customRegularFuncMap.put(Tokens.CURDATE, FUNC_CURRENT_DATE);
customRegularFuncMap.put(Tokens.CURTIME, FUNC_LOCALTIME);
customRegularFuncMap.put(Tokens.DATABASE, FUNC_DATABASE);
customRegularFuncMap.put(Tokens.DATABASE_NAME, FUNC_DATABASE_NAME);
customRegularFuncMap.put(Tokens.DATABASE_ISOLATION_LEVEL, FUNC_DATABASE_ISOLATION_LEVEL);
customRegularFuncMap.put(Tokens.DATABASE_TIMEZONE, FUNC_DATABASE_TIMEZONE);
customRegularFuncMap.put(Tokens.DATABASE_VERSION, FUNC_DATABASE_VERSION);
customRegularFuncMap.put(Tokens.DATE_ADD, FUNC_DATE_ADD);
customRegularFuncMap.put(Tokens.DATE_SUB, FUNC_DATE_SUB);
customRegularFuncMap.put(Tokens.DATEADD, FUNC_DATEADD);
customRegularFuncMap.put(Tokens.DATEDIFF, FUNC_DATEDIFF);
customRegularFuncMap.put(Tokens.DAY, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.DAYNAME, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.DAYOFMONTH, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.DAYOFWEEK, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.DAYOFYEAR, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.DAYS, FUNC_DAYS);
customRegularFuncMap.put(Tokens.DBTIMEZONE, FUNC_DBTIMEZONE);
customRegularFuncMap.put(Tokens.DEGREES, FUNC_DEGREES);
customRegularFuncMap.put(Tokens.DIAGNOSTICS, FUNC_DIAGNOSTICS);
customRegularFuncMap.put(Tokens.DIFFERENCE, FUNC_DIFFERENCE);
customRegularFuncMap.put(Tokens.FROM_TZ, FUNC_FROM_TZ);
customRegularFuncMap.put(Tokens.HEXTORAW, FUNC_HEXTORAW);
customRegularFuncMap.put(Tokens.HOUR, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.IDENTITY, FUNC_IDENTITY);
customRegularFuncMap.put(Tokens.INSERT, FUNC_OVERLAY_CHAR);
customRegularFuncMap.put(Tokens.INSTR, FUNC_POSITION_CHAR);
customRegularFuncMap.put(Tokens.IS_AUTOCOMMIT, FUNC_ISAUTOCOMMIT);
customRegularFuncMap.put(Tokens.IS_READONLY_DATABASE, FUNC_ISREADONLYDATABASE);
customRegularFuncMap.put(Tokens.IS_READONLY_DATABASE_FILES, FUNC_ISREADONLYDATABASEFILES);
customRegularFuncMap.put(Tokens.IS_READONLY_SESSION, FUNC_ISREADONLYSESSION);
customRegularFuncMap.put(Tokens.ISOLATION_LEVEL, FUNC_ISOLATION_LEVEL);
customRegularFuncMap.put(Tokens.LAST_DAY, FUNC_LAST_DAY);
customRegularFuncMap.put(Tokens.LCASE, FUNC_FOLD_LOWER);
customRegularFuncMap.put(Tokens.LEFT, FUNC_LEFT);
customRegularFuncMap.put(Tokens.LENGTH, FUNC_CHAR_LENGTH);
customRegularFuncMap.put(Tokens.LOAD_FILE, FUNC_LOAD_FILE);
customRegularFuncMap.put(Tokens.LOB_ID, FUNC_LOB_ID);
customRegularFuncMap.put(Tokens.LOCATE, FUNC_POSITION_CHAR);
customRegularFuncMap.put(Tokens.LOG, FUNC_LN);
customRegularFuncMap.put(Tokens.LOG10, FUNC_LOG10);
customRegularFuncMap.put(Tokens.LPAD, FUNC_LPAD);
customRegularFuncMap.put(Tokens.LTRIM, FUNC_TRIM_CHAR);
customRegularFuncMap.put(Tokens.MINUTE, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.MONTH, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.MONTHNAME, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.MONTHS_BETWEEN, FUNC_MONTHS_BETWEEN);
customRegularFuncMap.put(Tokens.NEW_TIME, FUNC_NEW_TIME);
// customRegularFuncMap.put(Tokens.NEXT_DAY, FUNC_NEXT_DAY);
customRegularFuncMap.put(Tokens.NUMTODSINTERVAL, FUNC_NUMTODSINTERVAL);
customRegularFuncMap.put(Tokens.NUMTOYMINTERVAL, FUNC_NUMTOYMINTERVAL);
customRegularFuncMap.put(Tokens.OCTETLENGTH, FUNC_OCTET_LENGTH);
customRegularFuncMap.put(Tokens.PI, FUNC_PI);
customRegularFuncMap.put(Tokens.POSITION_ARRAY, FUNC_POSITION_ARRAY);
customRegularFuncMap.put(Tokens.QUARTER, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.RADIANS, FUNC_RADIANS);
customRegularFuncMap.put(Tokens.RAND, FUNC_RAND);
customRegularFuncMap.put(Tokens.RAWTOHEX, FUNC_RAWTOHEX);
customRegularFuncMap.put(Tokens.REGEXP_MATCHES, FUNC_REGEXP_MATCHES);
customRegularFuncMap.put(Tokens.REGEXP_REPLACE, FUNC_REGEXP_REPLACE);
customRegularFuncMap.put(Tokens.REGEXP_SUBSTRING, FUNC_REGEXP_SUBSTRING);
customRegularFuncMap.put(Tokens.REGEXP_SUBSTRING_ARRAY, FUNC_REGEXP_SUBSTRING_ARRAY);
customRegularFuncMap.put(Tokens.REPEAT, FUNC_REPEAT);
customRegularFuncMap.put(Tokens.REPLACE, FUNC_REPLACE);
customRegularFuncMap.put(Tokens.REVERSE, FUNC_REVERSE);
customRegularFuncMap.put(Tokens.RIGHT, FUNC_RIGHT);
customRegularFuncMap.put(Tokens.ROUND, FUNC_ROUND);
customRegularFuncMap.put(Tokens.ROUNDMAGIC, FUNC_ROUNDMAGIC);
customRegularFuncMap.put(Tokens.RPAD, FUNC_RPAD);
customRegularFuncMap.put(Tokens.RTRIM, FUNC_TRIM_CHAR);
customRegularFuncMap.put(Tokens.SECOND, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.SECONDS_MIDNIGHT, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.SEQUENCE_ARRAY, FUNC_SEQUENCE_ARRAY);
customRegularFuncMap.put(Tokens.SESSION_ID, FUNC_SESSION_ID);
customRegularFuncMap.put(Tokens.SESSION_ISOLATION_LEVEL, FUNC_SESSION_ISOLATION_LEVEL);
customRegularFuncMap.put(Tokens.SESSION_TIMEZONE, FUNC_SESSION_TIMEZONE);
customRegularFuncMap.put(Tokens.SESSIONTIMEZONE, FUNC_SESSIONTIMEZONE);
customRegularFuncMap.put(Tokens.SIGN, FUNC_SIGN);
customRegularFuncMap.put(Tokens.SIN, FUNC_SIN);
customRegularFuncMap.put(Tokens.SORT_ARRAY, FUNC_SORT_ARRAY);
customRegularFuncMap.put(Tokens.SOUNDEX, FUNC_SOUNDEX);
customRegularFuncMap.put(Tokens.SPACE, FUNC_SPACE);
customRegularFuncMap.put(Tokens.SUBSTR, FUNC_SUBSTRING_CHAR);
customRegularFuncMap.put(Tokens.SYS_EXTRACT_UTC, FUNC_SYS_EXTRACT_UTC);
customRegularFuncMap.put(Tokens.SYSDATE, FUNC_SYSDATE);
customRegularFuncMap.put(Tokens.SYSTIMESTAMP, FUNC_SYSTIMESTAMP);
customRegularFuncMap.put(Tokens.TAN, FUNC_TAN);
customRegularFuncMap.put(Tokens.TIMESTAMP, FUNC_TIMESTAMP);
customRegularFuncMap.put(Tokens.TIMESTAMP_WITH_ZONE, FUNC_TIMESTAMP_WITH_ZONE);
customRegularFuncMap.put(Tokens.TIMESTAMPADD, FUNC_TIMESTAMPADD);
customRegularFuncMap.put(Tokens.TIMESTAMPDIFF, FUNC_TIMESTAMPDIFF);
customRegularFuncMap.put(Tokens.TIMEZONE, FUNC_TIMEZONE);
customRegularFuncMap.put(Tokens.TO_CHAR, FUNC_TO_CHAR);
customRegularFuncMap.put(Tokens.TO_DATE, FUNC_TO_DATE);
customRegularFuncMap.put(Tokens.TO_DSINTERVAL, FUNC_TO_DSINTERVAL);
customRegularFuncMap.put(Tokens.TO_YMINTERVAL, FUNC_TO_YMINTERVAL);
customRegularFuncMap.put(Tokens.TO_NUMBER, FUNC_TO_NUMBER);
customRegularFuncMap.put(Tokens.TO_TIMESTAMP, FUNC_TO_TIMESTAMP);
// customRegularFuncMap.put(Tokens.TO_TIMESTAMP_TZ, FUNC_TO_TIMESTAMP_TZ);
customRegularFuncMap.put(Tokens.TRANSACTION_CONTROL, FUNC_TRANSACTION_CONTROL);
customRegularFuncMap.put(Tokens.TRANSACTION_ID, FUNC_TRANSACTION_ID);
customRegularFuncMap.put(Tokens.TRANSACTION_SIZE, FUNC_TRANSACTION_SIZE);
customRegularFuncMap.put(Tokens.TRANSLATE, FUNC_TRANSLATE);
customRegularFuncMap.put(Tokens.TRUNC, FUNC_TRUNC);
customRegularFuncMap.put(Tokens.TRUNCATE, FUNC_TRUNCATE);
customRegularFuncMap.put(Tokens.UCASE, FUNC_FOLD_UPPER);
customRegularFuncMap.put(Tokens.UNIX_MILLIS, FUNC_UNIX_MILLIS);
customRegularFuncMap.put(Tokens.UNIX_TIMESTAMP, FUNC_UNIX_TIMESTAMP);
customRegularFuncMap.put(Tokens.UUID, FUNC_UUID);
customRegularFuncMap.put(Tokens.WEEK, FUNC_EXTRACT);
customRegularFuncMap.put(Tokens.YEAR, FUNC_EXTRACT);
}
//J+
static final IntKeyIntValueHashMap customValueFuncMap =
new IntKeyIntValueHashMap();
static {
customValueFuncMap.put(Tokens.TODAY, FUNC_CURRENT_DATE);
customValueFuncMap.put(Tokens.NOW, FUNC_LOCALTIMESTAMP);
}
private int extractSpec;
private Pattern pattern;
private IntKeyIntValueHashMap charLookup;
public static FunctionSQL newCustomFunction(String token, int tokenType) {
int id = customRegularFuncMap.get(tokenType, -1);
if (id == -1) {
id = customValueFuncMap.get(tokenType, -1);
}
if (id == -1) {
return null;
}
switch (tokenType) {
case Tokens.BITLENGTH :
case Tokens.LCASE :
case Tokens.LENGTH :
case Tokens.LOG :
case Tokens.OCTETLENGTH :
case Tokens.UCASE :
return new FunctionSQL(id);
case Tokens.CURDATE :
case Tokens.CURTIME :
case Tokens.TODAY :
case Tokens.NOW : {
FunctionSQL function = new FunctionSQL(id);
function.parseList = optionalNoParamList;
return function;
}
case Tokens.SUBSTR : {
FunctionSQL function = new FunctionSQL(id);
function.parseList = tripleParamList;
return function;
}
}
FunctionCustom function = new FunctionCustom(id);
if (id == FUNC_TRIM_CHAR) {
switch (tokenType) {
case Tokens.LTRIM :
function.extractSpec = Tokens.LEADING;
break;
case Tokens.RTRIM :
function.extractSpec = Tokens.TRAILING;
break;
default :
}
}
if (id == FUNC_EXTRACT) {
switch (tokenType) {
case Tokens.DAYNAME :
function.extractSpec = Tokens.DAY_NAME;
break;
case Tokens.MONTHNAME :
function.extractSpec = Tokens.MONTH_NAME;
break;
case Tokens.DAYOFMONTH :
function.extractSpec = Tokens.DAY_OF_MONTH;
break;
case Tokens.DAYOFWEEK :
function.extractSpec = Tokens.DAY_OF_WEEK;
break;
case Tokens.DAYOFYEAR :
function.extractSpec = Tokens.DAY_OF_YEAR;
break;
case Tokens.WEEK :
function.extractSpec = Tokens.WEEK_OF_YEAR;
break;
default :
function.extractSpec = tokenType;
}
}
if (function.name == null) {
function.name = token;
}
return function;
}
public static boolean isRegularFunction(int tokenType) {
return customRegularFuncMap.get(tokenType, -1) != -1;
}
public static boolean isValueFunction(int tokenType) {
return customValueFuncMap.get(tokenType, -1) != -1;
}
private FunctionCustom(int id) {
super();
this.funcType = id;
isDeterministic = !nonDeterministicFuncSet.contains(id);
switch (id) {
case FUNC_SQLCODE :
case FUNC_SQLERRM :
parseList = optionalNoParamList;
break;
case FUNC_SYSDATE :
case FUNC_SYSTIMESTAMP :
parseList = optionalNoParamList;
break;
case FUNC_ACTION_ID :
case FUNC_DATABASE :
case FUNC_DATABASE_ISOLATION_LEVEL :
case FUNC_DATABASE_NAME :
case FUNC_DATABASE_TIMEZONE :
case FUNC_DATABASE_VERSION :
case FUNC_DBTIMEZONE :
case FUNC_ISAUTOCOMMIT :
case FUNC_ISOLATION_LEVEL :
case FUNC_ISREADONLYDATABASE :
case FUNC_ISREADONLYDATABASEFILES :
case FUNC_ISREADONLYSESSION :
case FUNC_PI :
case FUNC_SESSION_ID :
case FUNC_SESSION_ISOLATION_LEVEL :
case FUNC_SESSION_TIMEZONE :
case FUNC_SESSIONTIMEZONE :
case FUNC_TIMEZONE :
case FUNC_TRANSACTION_CONTROL :
case FUNC_TRANSACTION_ID :
case FUNC_TRANSACTION_SIZE :
parseList = emptyParamList;
break;
case FUNC_ACOS :
case FUNC_ASCII :
case FUNC_ASIN :
case FUNC_ATAN :
case FUNC_BITNOT :
case FUNC_CHAR :
case FUNC_COS :
case FUNC_COT :
case FUNC_DEGREES :
case FUNC_DAYS :
case FUNC_HEXTORAW :
case FUNC_LAST_DAY :
case FUNC_LOB_ID :
case FUNC_LOG10 :
case FUNC_RADIANS :
case FUNC_RAWTOHEX :
case FUNC_REVERSE :
case FUNC_ROUNDMAGIC :
case FUNC_SIGN :
case FUNC_SIN :
case FUNC_SOUNDEX :
case FUNC_SPACE :
case FUNC_SYS_EXTRACT_UTC :
case FUNC_TAN :
case FUNC_TIMESTAMP_WITH_ZONE :
case FUNC_TO_DSINTERVAL :
case FUNC_TO_YMINTERVAL :
case FUNC_TO_NUMBER :
parseList = singleParamList;
break;
case FUNC_ADD_MONTHS :
case FUNC_ATAN2 :
case FUNC_CONCAT :
case FUNC_CRYPT_KEY :
case FUNC_BITAND :
case FUNC_BITANDNOT :
case FUNC_BITOR :
case FUNC_BITXOR :
case FUNC_DIFFERENCE :
case FUNC_FROM_TZ :
case FUNC_LEFT :
case FUNC_MONTHS_BETWEEN :
case FUNC_NEXT_DAY :
case FUNC_NUMTODSINTERVAL :
case FUNC_NUMTOYMINTERVAL :
case FUNC_REGEXP_MATCHES :
case FUNC_REGEXP_SUBSTRING :
case FUNC_REGEXP_SUBSTRING_ARRAY :
case FUNC_REPEAT :
case FUNC_RIGHT :
case FUNC_TO_CHAR :
parseList = doubleParamList;
break;
case FUNC_LOAD_FILE :
case FUNC_ROUND :
case FUNC_TIMESTAMP :
case FUNC_TO_DATE :
case FUNC_TO_TIMESTAMP :
case FUNC_TO_TIMESTAMP_TZ :
case FUNC_TRUNC :
case FUNC_TRUNCATE :
parseList = optionalDoubleParamList;
break;
case FUNC_DATEDIFF :
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.QUESTION, Tokens.COMMA,
Tokens.QUESTION, Tokens.X_OPTION, 2, Tokens.COMMA,
Tokens.QUESTION, Tokens.CLOSEBRACKET
};
break;
case FUNC_DATE_ADD :
case FUNC_DATE_SUB :
parseList = doubleParamList;
break;
case FUNC_DATEADD :
case FUNC_NEW_TIME :
case FUNC_SEQUENCE_ARRAY :
case FUNC_TRANSLATE :
parseList = tripleParamList;
break;
case FUNC_LPAD :
case FUNC_RPAD :
case FUNC_POSITION_CHAR :
case FUNC_REPLACE :
case FUNC_REGEXP_REPLACE :
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.QUESTION, Tokens.COMMA,
Tokens.QUESTION, Tokens.X_OPTION, 2, Tokens.COMMA,
Tokens.QUESTION, Tokens.CLOSEBRACKET
};
break;
case FUNC_UNIX_MILLIS :
case FUNC_UNIX_TIMESTAMP :
case FUNC_UUID :
parseList = optionalSingleParamList;
break;
case FUNC_EXTRACT :
name = Tokens.T_EXTRACT;
parseList = singleParamList;
break;
case FUNC_TRIM_CHAR :
name = Tokens.T_TRIM;
parseList = singleParamList;
break;
case FUNC_OVERLAY_CHAR :
name = Tokens.T_OVERLAY;
parseList = quadParamList;
break;
case FUNC_IDENTITY :
name = Tokens.T_IDENTITY;
parseList = emptyParamList;
break;
case FUNC_DIAGNOSTICS :
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.ROW_COUNT, Tokens.CLOSEBRACKET
};
break;
case FUNC_POSITION_ARRAY :
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.QUESTION, Tokens.IN,
Tokens.QUESTION, Tokens.X_OPTION, 2, Tokens.FROM,
Tokens.QUESTION, Tokens.CLOSEBRACKET
};
break;
case FUNC_SORT_ARRAY :
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.QUESTION, Tokens.X_OPTION, 4,
Tokens.X_KEYSET, 2, Tokens.ASC, Tokens.DESC,
Tokens.X_OPTION, 5, Tokens.NULLS, Tokens.X_KEYSET, 2,
Tokens.FIRST, Tokens.LAST, Tokens.CLOSEBRACKET
};
break;
case FUNC_TIMESTAMPADD :
name = Tokens.T_TIMESTAMPADD;
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.X_KEYSET, 10,
Tokens.SQL_TSI_FRAC_SECOND, Tokens.SQL_TSI_MILLI_SECOND,
Tokens.SQL_TSI_SECOND, Tokens.SQL_TSI_MINUTE,
Tokens.SQL_TSI_HOUR, Tokens.SQL_TSI_DAY,
Tokens.SQL_TSI_WEEK, Tokens.SQL_TSI_MONTH,
Tokens.SQL_TSI_QUARTER, Tokens.SQL_TSI_YEAR, Tokens.COMMA,
Tokens.QUESTION, Tokens.COMMA, Tokens.QUESTION,
Tokens.CLOSEBRACKET
};
break;
case FUNC_TIMESTAMPDIFF :
name = Tokens.T_TIMESTAMPDIFF;
parseList = new short[] {
Tokens.OPENBRACKET, Tokens.X_KEYSET, 10,
Tokens.SQL_TSI_FRAC_SECOND, Tokens.SQL_TSI_MILLI_SECOND,
Tokens.SQL_TSI_SECOND, Tokens.SQL_TSI_MINUTE,
Tokens.SQL_TSI_HOUR, Tokens.SQL_TSI_DAY,
Tokens.SQL_TSI_WEEK, Tokens.SQL_TSI_MONTH,
Tokens.SQL_TSI_QUARTER, Tokens.SQL_TSI_YEAR, Tokens.COMMA,
Tokens.QUESTION, Tokens.COMMA, Tokens.QUESTION,
Tokens.CLOSEBRACKET
};
break;
case FUNC_RAND :
parseList = optionalSingleParamList;
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "FunctionCustom");
}
}
public void setArguments(Expression[] nodes) {
switch (funcType) {
case FUNC_POSITION_CHAR : {
Expression[] newNodes = new Expression[4];
if (Tokens.T_LOCATE.equals(name)) {
// LOCATE
newNodes[0] = nodes[0];
newNodes[1] = nodes[1];
newNodes[3] = nodes[2];
nodes = newNodes;
} else if (Tokens.T_INSTR.equals(name)) {
newNodes[0] = nodes[1];
newNodes[1] = nodes[0];
newNodes[3] = nodes[2];
nodes = newNodes;
}
break;
}
case FUNC_OVERLAY_CHAR : {
Expression start = nodes[1];
Expression length = nodes[2];
nodes[1] = nodes[3];
nodes[2] = start;
nodes[3] = length;
break;
}
case FUNC_EXTRACT : {
Expression[] newNodes = new Expression[2];
newNodes[0] =
new ExpressionValue(ValuePool.getInt(extractSpec),
Type.SQL_INTEGER);
newNodes[1] = nodes[0];
nodes = newNodes;
break;
}
case FUNC_TRIM_CHAR : {
Expression[] newNodes = new Expression[3];
newNodes[0] =
new ExpressionValue(ValuePool.getInt(extractSpec),
Type.SQL_INTEGER);
newNodes[1] = new ExpressionValue(" ", Type.SQL_CHAR);
newNodes[2] = nodes[0];
nodes = newNodes;
}
}
super.setArguments(nodes);
}
public Expression getFunctionExpression() {
switch (funcType) {
case FUNC_CONCAT :
return new ExpressionArithmetic(OpTypes.CONCAT,
nodes[LEFT],
nodes[RIGHT]);
}
return super.getFunctionExpression();
}
Object getValue(Session session, Object[] data) {
switch (funcType) {
case FUNC_SQLCODE :
return 0;
case FUNC_SQLERRM :
return "Error";
case FUNC_POSITION_CHAR :
case FUNC_EXTRACT :
case FUNC_TRIM_CHAR :
case FUNC_OVERLAY_CHAR :
return super.getValue(session, data);
case FUNC_DATABASE :
return session.getDatabase().getPath();
case FUNC_DATABASE_NAME :
return session.getDatabase().getNameString();
case FUNC_ISAUTOCOMMIT :
return session.isAutoCommit() ? Boolean.TRUE
: Boolean.FALSE;
case FUNC_ISREADONLYSESSION :
return session.isReadOnlyDefault() ? Boolean.TRUE
: Boolean.FALSE;
case FUNC_ISREADONLYDATABASE :
return session.getDatabase().databaseReadOnly ? Boolean.TRUE
: Boolean.FALSE;
case FUNC_ISREADONLYDATABASEFILES :
return session.getDatabase().isFilesReadOnly() ? Boolean.TRUE
: Boolean.FALSE;
case FUNC_ISOLATION_LEVEL : {
return Session.getIsolationString(session.isolationLevel);
}
case FUNC_SESSION_ISOLATION_LEVEL :
return Session.getIsolationString(
session.isolationLevelDefault);
case FUNC_DATABASE_ISOLATION_LEVEL :
return Session.getIsolationString(
session.database.defaultIsolationLevel);
case FUNC_TRANSACTION_CONTROL :
switch (session.database.txManager.getTransactionControl()) {
case TransactionManager.MVCC :
return Tokens.T_MVCC;
case TransactionManager.MVLOCKS :
return Tokens.T_MVLOCKS;
case TransactionManager.LOCKS :
default :
return Tokens.T_LOCKS;
}
case FUNC_TIMEZONE :
return new IntervalSecondData(session.getZoneSeconds(), 0);
case FUNC_SESSION_TIMEZONE :
return new IntervalSecondData(session.sessionTimeZoneSeconds,
0);
case FUNC_DATABASE_TIMEZONE :
int sec =
HsqlDateTime.getZoneSeconds(HsqlDateTime.tempCalDefault);
return new IntervalSecondData(sec, 0);
case FUNC_DATABASE_VERSION :
return HsqlDatabaseProperties.THIS_FULL_VERSION;
case FUNC_SESSION_ID : {
return Long.valueOf(session.getId());
}
case FUNC_ACTION_ID : {
return Long.valueOf(session.actionTimestamp);
}
case FUNC_TRANSACTION_ID : {
return Long.valueOf(session.transactionTimestamp);
}
case FUNC_TRANSACTION_SIZE : {
return Long.valueOf(session.actionIndex);
}
case FUNC_LOB_ID : {
LobData lob = (LobData) data[0];
if (lob == null) {
return null;
}
return Long.valueOf(lob.getId());
}
case FUNC_IDENTITY : {
Number id = session.getLastIdentity();
if (id instanceof Long) {
return id;
} else {
return ValuePool.getLong(id.longValue());
}
}
case FUNC_DIAGNOSTICS : {
return session.sessionContext
.diagnosticsVariables[exprSubType];
}
case FUNC_SEQUENCE_ARRAY : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
HsqlArrayList list = new HsqlArrayList();
Object current = data[0];
Type type = nodes[0].getDataType();
boolean ascending = type.compare(session, data[1], data[0])
>= 0;
while (true) {
int compare = type.compare(session, current, data[1]);
if (ascending) {
if (compare > 0) {
break;
}
} else if (compare < 0) {
break;
}
list.add(current);
Object newValue = type.add(session, current, data[2],
nodes[2].getDataType());
compare = type.compare(session, current, newValue);
if (ascending) {
if (compare >= 0) {
break;
}
} else if (compare <= 0) {
break;
}
current = newValue;
}
Object[] array = list.toArray();
return array;
}
case FUNC_TIMESTAMPADD : {
if (data[1] == null || data[2] == null) {
return null;
}
data[1] = Type.SQL_BIGINT.convertToType(session, data[1],
nodes[1].getDataType());
int part = ((Number) nodes[0].valueData).intValue();
long units = ((Number) data[1]).longValue();
TimestampData source = (TimestampData) data[2];
IntervalType t;
Object o;
switch (part) {
case Tokens.SQL_TSI_FRAC_SECOND : {
long seconds = units / DTIType.limitNanoseconds;
int nanos = (int) (units % DTIType.limitNanoseconds);
t = Type.SQL_INTERVAL_SECOND_MAX_FRACTION;
o = new IntervalSecondData(seconds, nanos, t);
return dataType.add(session, source, o, t);
}
case Tokens.SQL_TSI_MILLI_SECOND : {
long seconds = units / 1000;
int nanos = (int) (units % 1000) * 1000000;
t = Type.SQL_INTERVAL_SECOND_MAX_FRACTION;
o = new IntervalSecondData(seconds, nanos, t);
return dataType.add(session, source, o, t);
}
case Tokens.SQL_TSI_SECOND :
t = Type.SQL_INTERVAL_SECOND_MAX_PRECISION;
o = IntervalSecondData.newIntervalSeconds(units, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_MINUTE :
t = Type.SQL_INTERVAL_MINUTE_MAX_PRECISION;
o = IntervalSecondData.newIntervalMinute(units, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_HOUR :
t = Type.SQL_INTERVAL_HOUR_MAX_PRECISION;
o = IntervalSecondData.newIntervalHour(units, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_DAY :
t = Type.SQL_INTERVAL_DAY_MAX_PRECISION;
o = IntervalSecondData.newIntervalDay(units, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_WEEK :
t = Type.SQL_INTERVAL_DAY_MAX_PRECISION;
o = IntervalSecondData.newIntervalDay(units * 7, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_MONTH :
t = Type.SQL_INTERVAL_MONTH_MAX_PRECISION;
o = IntervalMonthData.newIntervalMonth(units, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_QUARTER :
t = Type.SQL_INTERVAL_MONTH_MAX_PRECISION;
o = IntervalMonthData.newIntervalMonth(units * 3, t);
return dataType.add(session, source, o, t);
case Tokens.SQL_TSI_YEAR :
t = Type.SQL_INTERVAL_YEAR_MAX_PRECISION;
o = IntervalMonthData.newIntervalMonth(units * 12, t);
return dataType.add(session, source, o, t);
default :
throw Error.runtimeError(ErrorCode.U_S0500,
"FunctionCustom");
}
}
case FUNC_TIMESTAMPDIFF : {
if (data[1] == null || data[2] == null) {
return null;
}
int part = ((Number) nodes[0].valueData).intValue();
TimestampData a = (TimestampData) data[2];
TimestampData b = (TimestampData) data[1];
if (nodes[2].dataType.isDateTimeTypeWithZone()) {
a = (TimestampData) Type.SQL_TIMESTAMP.convertToType(
session, a, Type.SQL_TIMESTAMP_WITH_TIME_ZONE);
}
if (nodes[1].dataType.isDateTimeTypeWithZone()) {
b = (TimestampData) Type.SQL_TIMESTAMP.convertToType(
session, b, Type.SQL_TIMESTAMP_WITH_TIME_ZONE);
}
IntervalType t;
switch (part) {
case Tokens.SQL_TSI_FRAC_SECOND : {
t = Type.SQL_INTERVAL_SECOND_MAX_PRECISION;
IntervalSecondData interval =
(IntervalSecondData) t.subtract(session, a, b,
null);
return new Long(
DTIType.limitNanoseconds * interval.getSeconds()
+ interval.getNanos());
}
case Tokens.SQL_TSI_MILLI_SECOND : {
t = Type.SQL_INTERVAL_SECOND_MAX_PRECISION;
IntervalSecondData interval =
(IntervalSecondData) t.subtract(session, a, b,
null);
return new Long(1000 * interval.getSeconds()
+ interval.getNanos() / 1000000);
}
case Tokens.SQL_TSI_SECOND :
t = Type.SQL_INTERVAL_SECOND_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)));
case Tokens.SQL_TSI_MINUTE :
t = Type.SQL_INTERVAL_MINUTE_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)));
case Tokens.SQL_TSI_HOUR :
t = Type.SQL_INTERVAL_HOUR_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)));
case Tokens.SQL_TSI_DAY :
t = Type.SQL_INTERVAL_DAY_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)));
case Tokens.SQL_TSI_WEEK :
t = Type.SQL_INTERVAL_DAY_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)) / 7);
case Tokens.SQL_TSI_MONTH :
t = Type.SQL_INTERVAL_MONTH_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)));
case Tokens.SQL_TSI_QUARTER :
t = Type.SQL_INTERVAL_MONTH_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)) / 3);
case Tokens.SQL_TSI_YEAR :
t = Type.SQL_INTERVAL_YEAR_MAX_PRECISION;
return new Long(
t.convertToLongEndUnits(
t.subtract(session, a, b, null)));
default :
throw Error.runtimeError(ErrorCode.U_S0500,
"FunctionCustom");
}
}
case FUNC_DATE_ADD : {
if (data[0] == null || data[1] == null) {
return null;
}
return dataType.add(session, data[0], data[1],
nodes[RIGHT].dataType);
}
case FUNC_DATE_SUB : {
if (data[0] == null || data[1] == null) {
return null;
}
return dataType.subtract(session, data[0], data[1],
nodes[RIGHT].dataType);
}
case FUNC_DAYS : {
if (data[0] == null) {
return null;
}
IntervalSecondData diff =
(IntervalSecondData) Type.SQL_INTERVAL_DAY_MAX_PRECISION
.subtract(session, data[0],
DateTimeType.epochTimestamp, Type.SQL_DATE);
return ValuePool.getInt((int) (diff.getSeconds()
/ (24 * 60 * 60) + 1));
}
case FUNC_ROUND :
case FUNC_TRUNC : {
int interval = Types.SQL_INTERVAL_DAY;
if (data[0] == null) {
return null;
}
if (dataType.isDateTimeType()) {
DateTimeType type = (DateTimeType) dataType;
if (nodes.length > 1 && nodes[1] != null) {
if (data[1] == null) {
return null;
}
interval = HsqlDateTime.toStandardIntervalPart(
(String) data[1]);
}
if (interval < 0) {
throw Error.error(ErrorCode.X_42566, (String) data[1]);
}
return funcType == FUNC_ROUND
? type.round(data[0], interval)
: type.truncate(data[0], interval);
}
}
// fall through
case FUNC_TRUNCATE : {
int offset = 0;
if (data[0] == null) {
return null;
}
if (nodes.length > 1) {
if (data[1] == null) {
return null;
}
data[1] = Type.SQL_INTEGER.convertToType(session, data[1],
nodes[1].getDataType());
offset = ((Number) data[1]).intValue();
}
return funcType == FUNC_ROUND
? ((NumberType) dataType).round(data[0], offset)
: ((NumberType) dataType).truncate(data[0], offset);
}
case FUNC_TO_CHAR : {
if (data[0] == null || data[1] == null) {
return null;
}
SimpleDateFormat format = session.getSimpleDateFormatGMT();
Date date =
(Date) ((DateTimeType) nodes[0].dataType)
.convertSQLToJavaGMT(session, data[0]);
return HsqlDateTime.toFormattedDate(date, (String) data[1],
format);
}
case FUNC_TO_NUMBER : {
if (data[0] == null) {
return null;
}
return dataType.convertToType(session, data[0],
nodes[0].dataType);
}
case FUNC_TO_DATE :
case FUNC_TO_TIMESTAMP : {
if (data[0] == null || data[1] == null) {
return null;
}
SimpleDateFormat format = session.getSimpleDateFormatGMT();
TimestampData value = HsqlDateTime.toDate((String) data[0],
(String) data[1], format);
if (funcType == FUNC_TO_DATE) {
value.clearNanos();
}
return value;
}
case FUNC_TIMESTAMP : {
boolean unary = nodes[1] == null;
if (data[0] == null) {
return null;
}
if (unary) {
if (nodes[0].dataType.isNumberType()) {
return new TimestampData(
((Number) data[0]).longValue());
}
try {
return Type.SQL_TIMESTAMP.convertToType(session,
data[0], nodes[0].dataType);
} catch (HsqlException e) {
return Type.SQL_DATE.convertToType(session, data[0],
nodes[0].dataType);
}
}
if (data[1] == null) {
return null;
}
TimestampData date =
(TimestampData) Type.SQL_DATE.convertToType(session,
data[0], nodes[0].dataType);
TimeData time = (TimeData) Type.SQL_TIME.convertToType(session,
data[1], nodes[1].dataType);
return new TimestampData(date.getSeconds()
+ time.getSeconds(), time.getNanos());
}
case FUNC_TIMESTAMP_WITH_ZONE : {
Calendar calendar = session.getCalendar();
long seconds;
int nanos = 0;
int zone;
if (data[0] == null) {
return null;
}
if (nodes[0].dataType.isNumberType()) {
seconds = ((Number) data[0]).longValue();
} else if (nodes[0].dataType.typeCode == Types.SQL_TIMESTAMP) {
seconds = ((TimestampData) data[0]).getSeconds();
seconds =
HsqlDateTime.convertMillisToCalendar(
calendar, seconds * 1000) / 1000;
} else if (nodes[0].dataType.typeCode
== Types.SQL_TIMESTAMP_WITH_TIME_ZONE) {
seconds = ((TimestampData) data[0]).getSeconds();
} else {
throw Error.error(ErrorCode.X_42566, (String) data[1]);
}
synchronized (calendar) {
calendar.setTimeInMillis(seconds * 1000);
zone = HsqlDateTime.getZoneSeconds(calendar);
}
return new TimestampData(seconds, nanos, zone);
}
case FUNC_PI :
return new Double(Math.PI);
case FUNC_RAND : {
if (nodes[0] == null) {
return new Double(session.random());
} else {
data[0] = Type.SQL_BIGINT.convertToType(session, data[0],
nodes[0].getDataType());
long seed = ((Number) data[0]).longValue();
return new Double(session.random(seed));
}
}
case FUNC_UUID : {
if (nodes[0] == null) {
UUID uuid = java.util.UUID.randomUUID();
long hi = uuid.getMostSignificantBits();
long lo = uuid.getLeastSignificantBits();
return new BinaryData(ArrayUtil.toByteArray(hi, lo),
false);
} else {
if (data[0] == null) {
return null;
}
try {
if (dataType.isBinaryType()) {
byte[] bytes =
StringConverter.toBinaryUUID((String) data[0]);
return new BinaryData(bytes, false);
} else {
return StringConverter.toStringUUID(
((BinaryData) data[0]).getBytes());
}
} catch (NumberFormatException e) {
throw Error.error(ErrorCode.X_22026);
}
}
}
case FUNC_UNIX_MILLIS : {
TimestampData ts;
if (nodes[0] == null) {
ts = session.getCurrentTimestamp(true);
} else {
if (data[0] == null) {
return null;
}
ts = (TimestampData) data[0];
}
long millis = ts.getSeconds() * 1000 + ts.getNanos() / 1000000;
return Long.valueOf(millis);
}
case FUNC_UNIX_TIMESTAMP : {
TimestampData ts;
if (nodes[0] == null) {
ts = session.getCurrentTimestamp(true);
} else {
if (data[0] == null) {
return null;
}
ts = (TimestampData) data[0];
}
return Long.valueOf(ts.getSeconds());
}
case FUNC_ACOS : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.acos(d));
}
case FUNC_ASIN : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.asin(d));
}
case FUNC_ATAN : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.atan(d));
}
case FUNC_COS : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.cos(d));
}
case FUNC_COT : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
double c = 1.0 / java.lang.Math.tan(d);
return new Double(c);
}
case FUNC_DEGREES : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.toDegrees(d));
}
case FUNC_SIN : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.sin(d));
}
case FUNC_TAN : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.tan(d));
}
case FUNC_LOG10 : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.log10(d));
}
case FUNC_RADIANS : {
if (data[0] == null) {
return null;
}
double d = NumberType.toDouble(data[0]);
return new Double(java.lang.Math.toRadians(d));
}
//
case FUNC_SIGN : {
if (data[0] == null) {
return null;
}
int val =
((NumberType) nodes[0].dataType).compareToZero(data[0]);
return ValuePool.getInt(val);
}
case FUNC_ATAN2 : {
if (data[0] == null) {
return null;
}
double a = NumberType.toDouble(data[0]);
double b = NumberType.toDouble(data[1]);
return new Double(java.lang.Math.atan2(a, b));
}
case FUNC_ASCII : {
String arg;
if (data[0] == null) {
return null;
}
if (nodes[0].dataType.isLobType()) {
arg = ((ClobData) data[0]).getSubString(session, 0, 1);
} else {
arg = (String) data[0];
}
if (arg.length() == 0) {
return null;
}
return ValuePool.getInt(arg.charAt(0));
}
case FUNC_CHAR :
if (data[0] == null) {
return null;
}
data[0] = Type.SQL_INTEGER.convertToType(session, data[0],
nodes[0].getDataType());
int arg = ((Number) data[0]).intValue();
if (Character.isValidCodePoint(arg)
&& Character.isValidCodePoint((char) arg)) {
return String.valueOf((char) arg);
}
throw Error.error(ErrorCode.X_22511);
case FUNC_ROUNDMAGIC : {
int offset = 0;
if (data[0] == null) {
return null;
}
if (nodes.length > 1) {
if (data[1] == null) {
return null;
}
offset = ((Number) data[1]).intValue();
}
return ((NumberType) dataType).round(data[0], offset);
}
case FUNC_SOUNDEX : {
if (data[0] == null) {
return null;
}
String s = (String) data[0];
return new String(soundex(s), 0, 4);
}
case FUNC_BITAND :
case FUNC_BITANDNOT :
case FUNC_BITNOT :
case FUNC_BITOR :
case FUNC_BITXOR : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
if (dataType.isNumberType()) {
long v = 0;
long a;
long b = 0;
data[0] = Type.SQL_BIGINT.convertToType(session, data[0],
nodes[0].getDataType());
a = ((Number) data[0]).longValue();
if (funcType != FUNC_BITNOT) {
data[1] = Type.SQL_BIGINT.convertToType(session,
data[1], nodes[1].getDataType());
b = ((Number) data[1]).longValue();
}
switch (funcType) {
case FUNC_BITAND :
v = a & b;
break;
case FUNC_BITANDNOT :
v = a & ~b;
break;
case FUNC_BITNOT :
v = ~a;
break;
case FUNC_BITOR :
v = a | b;
break;
case FUNC_BITXOR :
v = a ^ b;
break;
default :
}
switch (dataType.typeCode) {
case Types.SQL_NUMERIC :
case Types.SQL_DECIMAL :
return BigDecimal.valueOf(v);
case Types.SQL_BIGINT :
return ValuePool.getLong(v);
case Types.SQL_INTEGER :
case Types.SQL_SMALLINT :
case Types.TINYINT :
return ValuePool.getInt((int) v);
default :
throw Error.error(ErrorCode.X_42561);
}
} else {
byte[] a = ((BinaryData) data[0]).getBytes();
byte[] b = null;
byte[] v;
if (funcType != FUNC_BITNOT) {
b = ((BinaryData) data[1]).getBytes();
}
switch (funcType) {
case FUNC_BITAND :
v = BitMap.and(a, b);
break;
case FUNC_BITANDNOT :
b = BitMap.not(b);
v = BitMap.and(a, b);
break;
case FUNC_BITNOT :
v = BitMap.not(a);
break;
case FUNC_BITOR :
v = BitMap.or(a, b);
break;
case FUNC_BITXOR :
v = BitMap.xor(a, b);
break;
default :
throw Error.error(ErrorCode.X_42561);
}
return new BinaryData(v, dataType.precision);
}
}
case FUNC_DIFFERENCE : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
char[] s1 = soundex((String) data[0]);
char[] s2 = soundex((String) data[1]);
int e = 0;
if (s1[0] == s2[0]) {
e++;
}
int js = 1;
for (int i = 1; i < 4; i++) {
for (int j = js; j < 4; j++) {
if (s1[j] == s2[i]) {
e++;
js = j + 1;
break;
}
}
}
return ValuePool.getInt(e);
}
case FUNC_HEXTORAW : {
if (data[0] == null) {
return null;
}
return dataType.convertToType(session, data[0],
nodes[0].dataType);
}
case FUNC_RAWTOHEX : {
if (data[0] == null) {
return null;
}
BlobData binary = (BlobData) data[0];
byte[] bytes = binary.getBytes(session, 0,
(int) binary.length(session));
return StringConverter.byteArrayToHexString(bytes);
}
case FUNC_REPEAT : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
data[1] = Type.SQL_INTEGER.convertToType(session, data[1],
nodes[1].getDataType());
String string = (String) data[0];
int i = ((Number) data[1]).intValue();
StringBuffer sb = new StringBuffer(string.length() * i);
while (i-- > 0) {
sb.append(string);
}
return sb.toString();
}
case FUNC_REPLACE : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
String string = (String) data[0];
String find = (String) data[1];
String replace = (String) data[2];
StringBuffer sb = new StringBuffer();
int start = 0;
if (find.length() == 0) {
return string;
}
while (true) {
int i = string.indexOf(find, start);
if (i == -1) {
sb.append(string.substring(start));
break;
}
sb.append(string.substring(start, i));
sb.append(replace);
start = i + find.length();
}
return sb.toString();
}
case FUNC_LEFT :
case FUNC_RIGHT : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
int count = ((Number) data[1]).intValue();
return ((CharacterType) dataType).substring(session, data[0],
0, count, true, funcType == FUNC_RIGHT);
}
case FUNC_SPACE : {
if (data[0] == null) {
return null;
}
data[0] = Type.SQL_INTEGER.convertToType(session, data[0],
nodes[0].getDataType());
int count = ((Number) data[0]).intValue();
char[] array = new char[count];
ArrayUtil.fillArray(array, 0, ' ');
return String.valueOf(array);
}
case FUNC_REVERSE : {
if (data[0] == null) {
return null;
}
StringBuffer sb = new StringBuffer((String) data[0]);
sb = sb.reverse();
return sb.toString();
}
case FUNC_REGEXP_MATCHES :
case FUNC_REGEXP_REPLACE :
case FUNC_REGEXP_SUBSTRING :
case FUNC_REGEXP_SUBSTRING_ARRAY : {
for (int i = 0; i < data.length; i++) {
if (data[i] == null) {
return null;
}
}
Pattern currentPattern = pattern;
if (currentPattern == null) {
String matchPattern = (String) data[1];
currentPattern = Pattern.compile(matchPattern);
}
Matcher matcher = currentPattern.matcher((String) data[0]);
switch (funcType) {
case FUNC_REGEXP_MATCHES : {
boolean match = matcher.matches();
return Boolean.valueOf(match);
}
case FUNC_REGEXP_REPLACE : {
String replace = (String) data[2];
String result = matcher.replaceAll(replace);
return result;
}
case FUNC_REGEXP_SUBSTRING : {
boolean match = matcher.find();
if (match) {
return matcher.group();
} else {
return null;
}
}
case FUNC_REGEXP_SUBSTRING_ARRAY : {
HsqlArrayList list = new HsqlArrayList();
while (matcher.find()) {
list.add(matcher.group());
}
return list.toArray();
}
}
}
case FUNC_CRYPT_KEY : {
byte[] bytes = Crypto.getNewKey((String) data[0],
(String) data[1]);
return StringConverter.byteArrayToHexString(bytes);
}
case FUNC_LOAD_FILE : {
String fileName = (String) data[0];
if (fileName == null) {
return null;
}
switch (dataType.typeCode) {
case Types.SQL_CLOB :
return session.sessionData.createClobFromFile(fileName,
(String) data[1]);
case Types.SQL_BLOB :
default :
return session.sessionData.createBlobFromFile(
fileName);
}
}
case FUNC_LPAD :
case FUNC_RPAD : {
if (data[0] == null || data[1] == null) {
return null;
}
String value;
if (nodes[0].dataType.typeCode == Types.SQL_CLOB) {
value = (String) Type.SQL_VARCHAR.convertToType(session,
data[0], nodes[0].dataType);
} else if (nodes[0].dataType.isCharacterType()) {
value = (String) data[0];
} else {
value = nodes[0].dataType.convertToString(data[0]);
}
int length = ((Integer) Type.SQL_INTEGER.convertToType(session,
data[1], nodes[1].dataType)).intValue();
String pad = " ";
if (nodes[2] != null) {
pad = nodes[2].dataType.convertToString(data[2]);
if (pad.length() == 0) {
pad = " ";
}
}
value = (String) Type.SQL_VARCHAR.trim(session, value, ' ',
true, true);
value = StringUtil.toPaddedString(value, length, pad,
funcType == FUNC_RPAD);
if (dataType.isLobType()) {
return dataType.convertToType(session, value,
Type.SQL_VARCHAR);
} else {
return value;
}
}
case FUNC_POSITION_ARRAY : {
if (data[1] == null) {
return null;
}
if (data[2] == null) {
return null;
}
Object[] array = (Object[]) data[1];
ArrayType dt = (ArrayType) nodes[1].dataType;
Type elementType = dt.collectionBaseType();
int start = ((Number) Type.SQL_INTEGER.convertToType(session,
data[2], nodes[2].dataType)).intValue();
if (start <= 0) {
throw Error.error(ErrorCode.X_22003);
}
start--;
for (int i = start; i < array.length; i++) {
if (elementType.compare(session, data[0], array[i]) == 0) {
return ValuePool.getInt(i + 1);
}
}
return ValuePool.INTEGER_0;
}
case FUNC_SORT_ARRAY : {
if (data[0] == null) {
return null;
}
ArrayType dt = (ArrayType) dataType;
SortAndSlice exprSort = new SortAndSlice();
exprSort.prepareSingleColumn(1);
exprSort.sortDescending[0] = ((Number) data[1]).intValue()
== Tokens.DESC;
exprSort.sortNullsLast[0] = ((Number) data[2]).intValue()
== Tokens.LAST;
Object array = ArrayUtil.duplicateArray(data[0]);
dt.sort(session, array, exprSort);
return array;
}
case FUNC_ADD_MONTHS : {
if (data[0] == null) {
return null;
}
if (data[1] == null) {
return null;
}
TimestampData ts = (TimestampData) data[0];
int months = ((Number) data[1]).intValue();
return Type.SQL_TIMESTAMP_NO_FRACTION.addMonthsSpecial(session,
ts, months);
}
case FUNC_DBTIMEZONE : {
TimestampData timestamp = session.getSystemTimestamp(true);
IntervalSecondData zone =
new IntervalSecondData(timestamp.getZone(), 0);
return Type.SQL_INTERVAL_HOUR_TO_MINUTE.convertToString(zone);
}
case FUNC_FROM_TZ : {
if (data[0] == null || data[1] == null) {
return null;
}
TimestampData timestamp = (TimestampData) data[0];
IntervalSecondData zone =
(IntervalSecondData) Type.SQL_INTERVAL_HOUR_TO_MINUTE
.convertToDefaultType(session, data[1]);
return new TimestampData(
timestamp.getSeconds() - zone.getSeconds(),
timestamp.getNanos(), (int) zone.getSeconds());
}
case FUNC_LAST_DAY : {
if (data[0] == null) {
return null;
}
return Type.SQL_TIMESTAMP_NO_FRACTION.getLastDayOfMonth(
session, data[0]);
}
case FUNC_MONTHS_BETWEEN : {
if (data[0] == null || data[1] == null) {
return null;
}
return DateTimeType.subtractMonthsSpecial(session,
(TimestampData) data[0], (TimestampData) data[1]);
}
case FUNC_NEW_TIME : {
if (data[0] == null || data[1] == null || data[2] == null) {
return null;
}
IntervalSecondData zone1 =
(IntervalSecondData) Type.SQL_INTERVAL_HOUR_TO_MINUTE
.convertToDefaultType(session, data[1]);
IntervalSecondData zone2 =
(IntervalSecondData) Type.SQL_INTERVAL_HOUR_TO_MINUTE
.convertToDefaultType(session, data[1]);
Object val =
Type.SQL_TIMESTAMP_WITH_TIME_ZONE.changeZone(data[0],
Type.SQL_TIMESTAMP, (int) zone2.getSeconds(),
(int) zone1.getSeconds());
return Type.SQL_TIMESTAMP.convertToType(session, val,
Type.SQL_TIMESTAMP_WITH_TIME_ZONE);
}
case FUNC_NEXT_DAY : {
if (data[0] == null || data[1] == null) {
return null;
}
}
case FUNC_NUMTODSINTERVAL : {
if (data[0] == null || data[1] == null) {
return null;
}
Object st = Type.SQL_VARCHAR.trim(session, data[1], ' ', true,
true);
st = Type.SQL_VARCHAR.upper(session, st);
st = Type.SQL_VARCHAR.convertToDefaultType(session, st);
int token = Tokens.get((String) st);
int typeCode = IntervalType.getFieldNameTypeForToken(token);
switch (typeCode) {
case Types.SQL_INTERVAL_DAY :
case Types.SQL_INTERVAL_HOUR :
case Types.SQL_INTERVAL_MINUTE :
case Types.SQL_INTERVAL_SECOND :
break;
default :
throw Error.error(ErrorCode.X_42566);
}
double value = ((Number) data[0]).doubleValue();
return IntervalSecondData.newInterval(value, typeCode);
}
case FUNC_NUMTOYMINTERVAL : {
if (data[0] == null || data[1] == null) {
return null;
}
Object st = Type.SQL_VARCHAR.trim(session, data[1], ' ', true,
true);
st = Type.SQL_VARCHAR.upper(session, st);
st = Type.SQL_VARCHAR.convertToDefaultType(session, st);
int token = Tokens.get((String) st);
int typeCode = IntervalType.getFieldNameTypeForToken(token);
switch (typeCode) {
case Types.SQL_INTERVAL_YEAR :
case Types.SQL_INTERVAL_MONTH :
break;
default :
throw Error.error(ErrorCode.X_42566);
}
double value = ((Number) data[0]).doubleValue();
return IntervalMonthData.newInterval(value, typeCode);
}
case FUNC_SESSIONTIMEZONE : {
IntervalSecondData zone =
new IntervalSecondData(session.sessionTimeZoneSeconds, 0);
return Type.SQL_INTERVAL_HOUR_TO_MINUTE.convertToString(zone);
}
case FUNC_SYS_EXTRACT_UTC : {
if (data[0] == null) {
return null;
}
return Type.SQL_TIMESTAMP_WITH_TIME_ZONE.changeZone(data[0],
Type.SQL_TIMESTAMP_WITH_TIME_ZONE, 0, 0);
}
case FUNC_SYSDATE : {
TimestampData timestamp = session.getSystemTimestamp(false);
return Type.SQL_TIMESTAMP_NO_FRACTION.convertToType(session,
timestamp, Type.SQL_TIMESTAMP);
//
}
case FUNC_SYSTIMESTAMP : {
return session.getSystemTimestamp(true);
}
case FUNC_TO_DSINTERVAL : {
if (data[0] == null) {
return null;
}
return Type.SQL_INTERVAL_DAY_TO_SECOND.convertToType(session,
data[0], Type.SQL_VARCHAR);
}
case FUNC_TO_YMINTERVAL : {
if (data[0] == null) {
return null;
}
return Type.SQL_INTERVAL_YEAR_TO_MONTH_MAX_PRECISION
.convertToType(session, data[0], Type.SQL_VARCHAR);
}
case FUNC_TO_TIMESTAMP_TZ : {
if (data[0] == null || data[1] == null) {
return null;
}
}
case FUNC_TRANSLATE : {
if (data[0] == null || data[1] == null || data[2] == null) {
return null;
}
IntKeyIntValueHashMap map = charLookup;
if (map == null) {
map = getTranslationMap((String) data[1],
(String) data[2]);
}
return translateWithMap((String) data[0], map);
}
default :
throw Error.runtimeError(ErrorCode.U_S0500, "FunctionCustom");
}
}
public void resolveTypes(Session session, Expression parent) {
for (int i = 0; i < nodes.length; i++) {
if (nodes[i] != null) {
nodes[i].resolveTypes(session, this);
}
}
switch (funcType) {
case FUNC_SQLCODE :
dataType = Type.SQL_INTEGER;
return;
case FUNC_SQLERRM :
dataType = Type.SQL_VARCHAR_DEFAULT;
return;
case FUNC_POSITION_CHAR :
case FUNC_EXTRACT :
case FUNC_TRIM_CHAR :
case FUNC_OVERLAY_CHAR :
super.resolveTypes(session, parent);
return;
case FUNC_DATABASE :
dataType = Type.SQL_VARCHAR_DEFAULT;
return;
case FUNC_DATABASE_NAME :
dataType = Type.SQL_VARCHAR_DEFAULT;
return;
case FUNC_ISAUTOCOMMIT :
case FUNC_ISREADONLYSESSION :
case FUNC_ISREADONLYDATABASE :
case FUNC_ISREADONLYDATABASEFILES :
dataType = Type.SQL_BOOLEAN;
return;
case FUNC_ISOLATION_LEVEL :
case FUNC_SESSION_ISOLATION_LEVEL :
case FUNC_DATABASE_ISOLATION_LEVEL :
case FUNC_TRANSACTION_CONTROL :
case FUNC_DATABASE_VERSION :
dataType = Type.SQL_VARCHAR_DEFAULT;
return;
case FUNC_TIMEZONE :
case FUNC_SESSION_TIMEZONE :
case FUNC_DATABASE_TIMEZONE :
dataType = Type.SQL_INTERVAL_HOUR_TO_MINUTE;
return;
case FUNC_SESSION_ID :
case FUNC_ACTION_ID :
case FUNC_TRANSACTION_ID :
case FUNC_TRANSACTION_SIZE :
case FUNC_LOB_ID :
case FUNC_IDENTITY :
dataType = Type.SQL_BIGINT;
return;
case FUNC_DIAGNOSTICS : {
exprSubType = ExpressionColumn.idx_row_count;
dataType = Type.SQL_INTEGER;
return;
}
case FUNC_SEQUENCE_ARRAY : {
if (nodes[0].dataType == null) {
nodes[0].dataType = nodes[1].dataType;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = nodes[0].dataType;
}
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_INTEGER;
nodes[1].dataType = Type.SQL_INTEGER;
}
if (nodes[0].dataType.isNumberType()) {
if (nodes[2].dataType == null) {
nodes[2].dataType = nodes[0].dataType;
}
} else if (nodes[0].dataType.isDateTimeType()) {
if (nodes[2].dataType == null) {
throw Error.error(ErrorCode.X_42561);
}
if (!nodes[2].dataType.isIntervalType()) {
throw Error.error(ErrorCode.X_42561);
}
}
dataType =
new ArrayType(nodes[0].getDataType(),
ArrayType.defaultLargeArrayCardinality);
return;
}
case FUNC_DATEADD : {
int part;
if (nodes[0].dataType == null) {
throw Error.error(ErrorCode.X_42575);
}
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
part = getTSIToken((String) nodes[0].valueData);
nodes[0].valueData = ValuePool.getInt(part);
nodes[0].dataType = Type.SQL_INTEGER;
funcType = FUNC_TIMESTAMPADD;
}
// fall through
case FUNC_TIMESTAMPADD :
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_BIGINT;
}
if (nodes[2].dataType == null) {
nodes[2].dataType = Type.SQL_TIMESTAMP;
}
if (!nodes[1].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
if (nodes[2].dataType.typeCode != Types.SQL_DATE
&& nodes[2].dataType.typeCode != Types.SQL_TIMESTAMP
&& nodes[2].dataType.typeCode
!= Types.SQL_TIMESTAMP_WITH_TIME_ZONE) {
throw Error.error(ErrorCode.X_42561);
}
dataType = nodes[2].dataType;
return;
case FUNC_DATEDIFF : {
int part;
if (nodes[2] == null) {
nodes[2] = nodes[0];
nodes[0] = new ExpressionValue(
ValuePool.getInt(Tokens.SQL_TSI_DAY),
Type.SQL_INTEGER);
} else {
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
part = getTSIToken((String) nodes[0].valueData);
nodes[0].valueData = ValuePool.getInt(part);
nodes[0].dataType = Type.SQL_INTEGER;
}
funcType = FUNC_TIMESTAMPDIFF;
}
// fall through
case FUNC_TIMESTAMPDIFF : {
if (nodes[1].dataType == null) {
nodes[1].dataType = nodes[2].dataType;
}
if (nodes[2].dataType == null) {
nodes[2].dataType = nodes[1].dataType;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_TIMESTAMP;
nodes[2].dataType = Type.SQL_TIMESTAMP;
}
switch (nodes[1].dataType.typeCode) {
case Types.SQL_DATE :
if (nodes[2].dataType.typeCode == Types.SQL_TIME
|| nodes[2].dataType.typeCode
== Types.SQL_TIME_WITH_TIME_ZONE) {
throw Error.error(ErrorCode.X_42563);
}
switch (((Integer) nodes[0].valueData).intValue()) {
case Tokens.SQL_TSI_DAY :
case Tokens.SQL_TSI_WEEK :
case Tokens.SQL_TSI_MONTH :
case Tokens.SQL_TSI_QUARTER :
case Tokens.SQL_TSI_YEAR :
break;
default :
throw Error.error(ErrorCode.X_42563);
}
break;
case Types.SQL_TIMESTAMP :
case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
if (nodes[2].dataType.typeCode == Types.SQL_TIME
|| nodes[2].dataType.typeCode
== Types.SQL_TIME_WITH_TIME_ZONE) {
throw Error.error(ErrorCode.X_42563);
}
break;
default :
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_BIGINT;
return;
}
case FUNC_DATE_ADD :
case FUNC_DATE_SUB : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DATE;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_INTEGER;
}
if (nodes[LEFT].dataType.isCharacterType()) {
nodes[LEFT] =
new ExpressionOp(nodes[LEFT],
Type.SQL_TIMESTAMP);
}
if (nodes[RIGHT].dataType.isIntegralType()) {
nodes[RIGHT] =
new ExpressionOp(nodes[RIGHT],
Type.SQL_INTERVAL_DAY);
}
nodes[0].resolveTypes(session, this);
nodes[1].resolveTypes(session, this);
dataType = nodes[0].dataType;
return;
}
case FUNC_DAYS : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DATE;
}
switch (nodes[0].dataType.typeCode) {
case Types.SQL_DATE :
case Types.SQL_TIMESTAMP :
case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
break;
default :
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_INTEGER;
return;
}
case FUNC_ROUND :
case FUNC_TRUNC : {
boolean single = nodes.length == 1 || nodes[1] == null;
if (nodes[0].dataType == null) {
if (single) {
if (parent instanceof ExpressionLogical
|| parent instanceof ExpressionArithmetic) {
for (int i = 0; i < parent.nodes.length; i++) {
if (parent.nodes[i].dataType != null) {
nodes[0].dataType =
parent.nodes[i].dataType;
break;
}
}
}
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DECIMAL;
}
if (nodes[0].dataType.isNumberType()) {
nodes[0].dataType = Type.SQL_DECIMAL;
}
} else {
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_INTEGER;
}
if (nodes[1].dataType.isNumberType()) {
nodes[0].dataType = Type.SQL_DECIMAL;
} else {
nodes[0].dataType = Type.SQL_TIMESTAMP;
}
}
}
if (nodes[0].dataType.isDateTimeType()) {
if (!single) {
if (!nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42566);
}
}
dataType = nodes[0].dataType;
break;
} else if (nodes[0].dataType.isNumberType()) {
//
} else {
throw Error.error(ErrorCode.X_42561);
}
}
// fall through
case FUNC_TRUNCATE : {
Number offset = null;
if (nodes[0].dataType == null) {
throw Error.error(ErrorCode.X_42567);
}
if (!nodes[0].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42563);
}
if (nodes[1] == null) {
nodes[1] = new ExpressionValue(ValuePool.INTEGER_0,
Type.SQL_INTEGER);
offset = ValuePool.INTEGER_0;
} else {
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_INTEGER;
} else if (!nodes[1].dataType.isIntegralType()) {
throw Error.error(ErrorCode.X_42563);
}
if (nodes[1].opType == OpTypes.VALUE) {
offset = (Number) nodes[1].getValue(session);
}
}
dataType = nodes[0].dataType;
if (offset != null) {
int scale = offset.intValue();
if (scale < 0) {
scale = 0;
} else if (scale > dataType.scale) {
scale = dataType.scale;
}
if (dataType.typeCode == Types.SQL_DECIMAL
|| dataType.typeCode == Types.SQL_NUMERIC) {
if (scale != dataType.scale) {
dataType = new NumberType(dataType.typeCode,
dataType.precision
- dataType.scale
+ scale, scale);
}
}
}
return;
}
case FUNC_TO_CHAR : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
if (!nodes[0].dataType.isDateTimeType()) {
throw Error.error(ErrorCode.X_42563);
}
// fixed maximum as format is a variable
dataType = CharacterType.getCharacterType(Types.SQL_VARCHAR,
64);
return;
}
case FUNC_TO_NUMBER : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
/*
if (nodes[1] != null) {
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
}
*/
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
// fixed maximum as format is a variable
dataType = Type.SQL_DECIMAL_DEFAULT;
return;
}
case FUNC_TO_DATE :
case FUNC_TO_TIMESTAMP : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (nodes[1] == null) {
String format = "DD-MON-YYYY HH24:MI:SS";
if (funcType == FUNC_TO_TIMESTAMP) {
format = "DD-MON-YYYY HH24:MI:SS.FF";
}
nodes[1] = new ExpressionValue(format, Type.SQL_VARCHAR);
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[0].dataType.isCharacterType()
|| !nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = funcType == FUNC_TO_DATE
? Type.SQL_TIMESTAMP_NO_FRACTION
: Type.SQL_TIMESTAMP;
return;
}
case FUNC_TIMESTAMP : {
Type argType = nodes[0].dataType;
if (nodes[1] == null) {
if (argType == null) {
argType = nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (argType.isCharacterType()
|| argType.typeCode == Types.SQL_TIMESTAMP
|| argType.typeCode
== Types.SQL_TIMESTAMP_WITH_TIME_ZONE) {}
else if (argType.isNumberType()) {}
else {
throw Error.error(ErrorCode.X_42561);
}
} else {
if (argType == null) {
if (nodes[1].dataType == null) {
argType = nodes[0].dataType = nodes[1].dataType =
Type.SQL_VARCHAR_DEFAULT;
} else {
if (nodes[1].dataType.isCharacterType()) {
argType = nodes[0].dataType =
Type.SQL_VARCHAR_DEFAULT;
} else {
argType = nodes[0].dataType = Type.SQL_DATE;
}
}
}
if (nodes[1].dataType == null) {
if (argType.isCharacterType()) {
nodes[1].dataType = Type.SQL_VARCHAR_DEFAULT;
} else if (argType.typeCode == Types.SQL_DATE) {
nodes[1].dataType = Type.SQL_TIME;
}
}
if ((argType.typeCode == Types.SQL_DATE && nodes[1]
.dataType.typeCode == Types.SQL_TIME) || argType
.isCharacterType() && nodes[1].dataType
.isCharacterType()) {}
else {
throw Error.error(ErrorCode.X_42561);
}
}
dataType = Type.SQL_TIMESTAMP;
return;
}
case FUNC_TIMESTAMP_WITH_ZONE : {
Type argType = nodes[0].dataType;
if (argType == null) {
argType = nodes[0].dataType = Type.SQL_BIGINT;
}
if (argType.typeCode == Types.SQL_TIMESTAMP
|| argType.typeCode
== Types.SQL_TIMESTAMP_WITH_TIME_ZONE) {}
else if (argType.isNumberType()) {}
else {
throw Error.error(ErrorCode.X_42561);
}
dataType = Type.SQL_TIMESTAMP_WITH_TIME_ZONE;
return;
}
case FUNC_PI :
dataType = Type.SQL_DOUBLE;
break;
case FUNC_UUID : {
if (nodes[0] == null) {
dataType = Type.SQL_BINARY_16;
} else {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
dataType = Type.SQL_BINARY_16;
} else if (nodes[0].dataType.isCharacterType()) {
dataType = Type.SQL_BINARY_16;
} else if (nodes[0].dataType.isBinaryType()
&& !nodes[0].dataType.isLobType()) {
dataType = Type.SQL_CHAR_16;
} else {
throw Error.error(ErrorCode.X_42563);
}
}
break;
}
case FUNC_UNIX_MILLIS :
case FUNC_UNIX_TIMESTAMP : {
if (nodes[0] != null) {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP;
} else if (!nodes[0].dataType.isDateTimeType()
|| nodes[0].dataType.typeCode == Types.SQL_TIME
|| nodes[0].dataType.typeCode
== Types.SQL_TIME_WITH_TIME_ZONE) {
throw Error.error(ErrorCode.X_42563);
}
}
dataType = Type.SQL_BIGINT;
break;
}
case FUNC_RAND : {
if (nodes[0] != null) {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_BIGINT;
} else if (!nodes[0].dataType.isExactNumberType()) {
throw Error.error(ErrorCode.X_42563);
}
}
dataType = Type.SQL_DOUBLE;
break;
}
case FUNC_ACOS :
case FUNC_ASIN :
case FUNC_ATAN :
case FUNC_COS :
case FUNC_COT :
case FUNC_DEGREES :
case FUNC_SIN :
case FUNC_TAN :
case FUNC_LOG10 :
case FUNC_RADIANS :
case FUNC_ROUNDMAGIC : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DOUBLE;
}
if (!nodes[0].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = Type.SQL_DOUBLE;
break;
}
case FUNC_SIGN : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DOUBLE;
}
if (!nodes[0].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = Type.SQL_INTEGER;
break;
}
case FUNC_ATAN2 : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DOUBLE;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_DOUBLE;
}
if (!nodes[0].dataType.isNumberType()
|| !nodes[1].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = Type.SQL_DOUBLE;
break;
}
case FUNC_SOUNDEX : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = CharacterType.getCharacterType(Types.SQL_VARCHAR,
4);
break;
}
case FUNC_BITAND :
case FUNC_BITANDNOT :
case FUNC_BITNOT :
case FUNC_BITOR :
case FUNC_BITXOR : {
if (nodes[0].dataType == null) {
nodes[0].dataType = nodes[1].dataType;
}
if (funcType == FUNC_BITNOT) {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_INTEGER;
}
dataType = nodes[0].dataType;
} else {
dataType = nodes[0].dataType;
if (nodes[1].dataType == null) {
nodes[1].dataType = nodes[0].dataType;
}
for (int i = 0; i < nodes.length; i++) {
if (nodes[i].dataType == null) {
nodes[i].dataType = Type.SQL_INTEGER;
}
}
dataType =
nodes[0].dataType.getAggregateType(nodes[1].dataType);
}
switch (dataType.typeCode) {
case Types.SQL_DOUBLE :
case Types.SQL_DECIMAL :
case Types.SQL_NUMERIC :
case Types.SQL_BIGINT :
case Types.SQL_INTEGER :
case Types.SQL_SMALLINT :
case Types.TINYINT :
break;
case Types.SQL_BIT :
case Types.SQL_BIT_VARYING :
break;
default :
throw Error.error(ErrorCode.X_42561);
}
break;
}
case FUNC_ASCII : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = Type.SQL_INTEGER;
break;
}
case FUNC_CHAR : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_INTEGER;
}
if (!nodes[0].dataType.isExactNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = CharacterType.getCharacterType(Types.SQL_VARCHAR,
1);
break;
}
case FUNC_DIFFERENCE : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
dataType = Type.SQL_INTEGER;
break;
}
case FUNC_HEXTORAW : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = nodes[0].dataType.precision == 0
? Type.SQL_VARBINARY_DEFAULT
: BinaryType.getBinaryType(
Types.SQL_VARBINARY,
nodes[0].dataType.precision / 2);
break;
}
case FUNC_RAWTOHEX : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARBINARY;
}
if (!nodes[0].dataType.isBinaryType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = nodes[0].dataType.precision == 0
? Type.SQL_VARCHAR_DEFAULT
: CharacterType.getCharacterType(Types.SQL_VARCHAR,
nodes[0].dataType.precision * 2);
break;
}
case FUNC_REPEAT : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
boolean isChar = nodes[0].dataType.isCharacterType();
if (!isChar && !nodes[0].dataType.isBinaryType()) {
throw Error.error(ErrorCode.X_42561);
}
if (!nodes[1].dataType.isExactNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = isChar ? Type.SQL_VARCHAR_DEFAULT
: Type.SQL_VARBINARY_DEFAULT;
break;
}
case FUNC_REPLACE : {
if (nodes[2] == null) {
nodes[2] = new ExpressionValue("", Type.SQL_VARCHAR);
}
for (int i = 0; i < nodes.length; i++) {
if (nodes[i].dataType == null) {
nodes[i].dataType = Type.SQL_VARCHAR;
} else if (!nodes[i].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
}
dataType = Type.SQL_VARCHAR_DEFAULT;
break;
}
case FUNC_LEFT :
case FUNC_RIGHT : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_INTEGER;
}
if (!nodes[1].dataType.isExactNumberType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = nodes[0].dataType.precision == 0
? Type.SQL_VARCHAR_DEFAULT
: ((CharacterType) nodes[0].dataType)
.getCharacterType(nodes[0].dataType.precision);
break;
}
case FUNC_SPACE : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_INTEGER;
}
if (!nodes[0].dataType.isIntegralType()) {
throw Error.error(ErrorCode.X_42561);
}
dataType = Type.SQL_VARCHAR_DEFAULT;
break;
}
case FUNC_REVERSE : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
dataType = nodes[0].dataType;
if (!dataType.isCharacterType() || dataType.isLobType()) {
throw Error.error(ErrorCode.X_42561);
}
break;
}
case FUNC_REGEXP_REPLACE :
if (nodes[2] == null) {
nodes[2] = new ExpressionValue("", Type.SQL_VARCHAR);
}
case FUNC_REGEXP_MATCHES :
case FUNC_REGEXP_SUBSTRING :
case FUNC_REGEXP_SUBSTRING_ARRAY : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[0].dataType.isCharacterType()
|| !nodes[1].dataType.isCharacterType()
|| nodes[1].dataType.isLobType()) {
throw Error.error(ErrorCode.X_42561);
}
if (nodes[1].exprSubType == OpTypes.VALUE) {
String matchPattern = (String) nodes[1].getValue(session);
pattern = Pattern.compile(matchPattern);
}
switch (funcType) {
case FUNC_REGEXP_MATCHES :
dataType = Type.SQL_BOOLEAN;
break;
case FUNC_REGEXP_REPLACE :
dataType = Type.SQL_VARCHAR_DEFAULT;
break;
case FUNC_REGEXP_SUBSTRING :
dataType = Type.SQL_VARCHAR_DEFAULT;
break;
case FUNC_REGEXP_SUBSTRING_ARRAY :
dataType = Type.getDefaultArrayType(Types.SQL_VARCHAR);
break;
default :
}
break;
}
case FUNC_CRYPT_KEY : {
for (int i = 0; i < nodes.length; i++) {
if (nodes[i].dataType == null) {
nodes[i].dataType = Type.SQL_VARCHAR;
} else if (!nodes[i].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
}
dataType = Type.SQL_VARCHAR_DEFAULT;
break;
}
case FUNC_LOAD_FILE : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[0].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
if (nodes[1] == null) {
dataType = Type.SQL_BLOB;
} else {
dataType = Type.SQL_CLOB;
if (nodes[1].dataType == null
|| !nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
}
break;
}
case FUNC_LPAD :
case FUNC_RPAD : {
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_INTEGER;
}
if (!nodes[1].dataType.isIntegralType()) {
throw Error.error(ErrorCode.X_42561);
}
if (nodes[2] != null) {
if (nodes[2].dataType == null) {
nodes[2].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[2].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42561);
}
}
dataType = nodes[0].dataType;
if (dataType.typeCode != Types.SQL_CLOB) {
dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (nodes[1].opType == OpTypes.VALUE) {
Number value = (Number) nodes[1].getValue(session);
if (value != null) {
dataType = ((CharacterType) dataType).getCharacterType(
value.longValue());
}
}
break;
}
case FUNC_POSITION_ARRAY : {
if (nodes[1].dataType == null) {
throw Error.error(ErrorCode.X_42567);
}
if (!nodes[1].dataType.isArrayType()) {
throw Error.error(ErrorCode.X_42563);
}
if (nodes[0].dataType == null) {
nodes[0].dataType = nodes[1].dataType.collectionBaseType();
}
if (!nodes[1].dataType.collectionBaseType().canCompareDirect(
nodes[0].dataType)) {
throw Error.error(ErrorCode.X_42563);
}
if (nodes[2] == null) {
nodes[2] = new ExpressionValue(ValuePool.INTEGER_1,
Type.SQL_INTEGER);
}
if (nodes[2].dataType == null) {
nodes[2].dataType = Type.SQL_INTEGER;
}
if (!nodes[2].dataType.isIntegralType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_INTEGER;
break;
}
case FUNC_SORT_ARRAY : {
if (nodes[0].dataType == null) {
throw Error.error(ErrorCode.X_42567);
}
if (!nodes[0].dataType.isArrayType()) {
throw Error.error(ErrorCode.X_42563);
}
if (nodes[1] == null) {
nodes[1] =
new ExpressionValue(ValuePool.getInt(Tokens.ASC),
Type.SQL_INTEGER);
}
if (nodes[2] == null) {
nodes[2] =
new ExpressionValue(ValuePool.getInt(Tokens.FIRST),
Type.SQL_INTEGER);
}
dataType = nodes[0].dataType;
break;
}
case FUNC_ADD_MONTHS :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
}
if (!nodes[0].dataType.isDateOrTimestampType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
break;
case FUNC_DBTIMEZONE :
dataType = CharacterType.getCharacterType(Types.SQL_VARCHAR,
6);
break;
case FUNC_FROM_TZ :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
dataType = Type.SQL_TIMESTAMP_WITH_TIME_ZONE;
break;
case FUNC_LAST_DAY :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
}
if (!nodes[0].dataType.isDateOrTimestampType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
break;
case FUNC_MONTHS_BETWEEN :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
}
if (!nodes[0].dataType.isDateOrTimestampType()) {
throw Error.error(ErrorCode.X_42563);
}
if (!nodes[1].dataType.isDateOrTimestampType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_DECIMAL_DEFAULT;
break;
case FUNC_NEW_TIME :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
if (nodes[2].dataType == null) {
nodes[2].dataType = Type.SQL_VARCHAR;
}
dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
break;
case FUNC_NEXT_DAY :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
break;
case FUNC_NUMTODSINTERVAL :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DOUBLE;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42563);
}
if (!nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_INTERVAL_DAY_TO_SECOND_MAX_PRECISION;
break;
case FUNC_NUMTOYMINTERVAL :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_DOUBLE;
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isNumberType()) {
throw Error.error(ErrorCode.X_42563);
}
if (!nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42563);
}
dataType = Type.SQL_INTERVAL_YEAR_TO_MONTH_MAX_PRECISION;
break;
case FUNC_SESSIONTIMEZONE :
dataType = CharacterType.getCharacterType(Types.SQL_VARCHAR,
6);
break;
case FUNC_SYS_EXTRACT_UTC :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_TIMESTAMP_WITH_TIME_ZONE;
}
dataType = Type.SQL_TIMESTAMP;
break;
case FUNC_SYSDATE :
dataType = Type.SQL_TIMESTAMP_NO_FRACTION;
break;
case FUNC_SYSTIMESTAMP :
dataType = Type.SQL_TIMESTAMP_WITH_TIME_ZONE;
break;
case FUNC_TO_DSINTERVAL :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
dataType = Type.SQL_INTERVAL_DAY_TO_SECOND_MAX_PRECISION;
break;
case FUNC_TO_YMINTERVAL :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR;
}
dataType = Type.SQL_INTERVAL_YEAR_TO_MONTH_MAX_PRECISION;
break;
case FUNC_TO_TIMESTAMP_TZ :
if (nodes[0].dataType == null) {
nodes[0].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (nodes[1] == null) {
String format = "DD-MON-YYYY HH24:MI:SS:FF TZH:TZM";
nodes[1] = new ExpressionValue(format, Type.SQL_VARCHAR);
}
if (nodes[1].dataType == null) {
nodes[1].dataType = Type.SQL_VARCHAR;
}
if (!nodes[0].dataType.isCharacterType()
|| !nodes[1].dataType.isCharacterType()) {
throw Error.error(ErrorCode.X_42567);
}
dataType = Type.SQL_TIMESTAMP_WITH_TIME_ZONE;
break;
case FUNC_TRANSLATE :
for (int i = 0; i < nodes.length; i++) {
if (nodes[i].dataType == null) {
nodes[i].dataType = Type.SQL_VARCHAR_DEFAULT;
}
if (!nodes[i].dataType.isCharacterType()
|| nodes[i].dataType.isLobType()) {
throw Error.error(ErrorCode.X_42563);
}
}
if (nodes[1].valueData != null && nodes[2].valueData != null) {
this.charLookup =
getTranslationMap((String) nodes[1].valueData,
(String) nodes[2].valueData);
}
dataType = nodes[0].dataType;
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "FunctionCustom");
}
}
public String getSQL() {
switch (funcType) {
case FUNC_POSITION_CHAR : {
// LOCATE
StringBuffer sb = new StringBuffer(Tokens.T_LOCATE).append(
Tokens.T_OPENBRACKET).append(nodes[0].getSQL()).append(
Tokens.T_COMMA).append(nodes[1].getSQL());
if (nodes.length > 3 && nodes[3] != null) {
sb.append(Tokens.T_COMMA).append(nodes[3].getSQL());
}
sb.append(Tokens.T_CLOSEBRACKET).toString();
return sb.toString();
}
case FUNC_LPAD :
case FUNC_RPAD : {
StringBuffer sb = new StringBuffer(name);
sb.append(Tokens.T_OPENBRACKET).append(nodes[0].getSQL());
sb.append(Tokens.T_COMMA).append(nodes[1].getSQL());
if (nodes[2] != null) {
sb.append(Tokens.T_COMMA).append(nodes[2].getSQL());
}
sb.append(Tokens.T_CLOSEBRACKET).toString();
return sb.toString();
}
case FUNC_EXTRACT :
case FUNC_TRIM_CHAR :
case FUNC_OVERLAY_CHAR :
return super.getSQL();
case FUNC_POSITION_ARRAY : {
StringBuffer sb = new StringBuffer(name).append('(');
sb.append(nodes[0].getSQL()).append(' ').append(Tokens.T_IN);
sb.append(' ').append(nodes[1].getSQL());
if (((Number) nodes[1].valueData).intValue() == Tokens.DESC) {
sb.append(' ').append(Tokens.T_FROM);
sb.append(' ').append(nodes[2].getSQL());
}
sb.append(')');
return sb.toString();
}
case FUNC_SORT_ARRAY : {
StringBuffer sb = new StringBuffer(name).append('(');
sb.append(nodes[0].getSQL());
if (((Number) nodes[1].valueData).intValue() == Tokens.DESC) {
sb.append(' ').append(Tokens.T_DESC);
}
if (((Number) nodes[2].valueData).intValue() == Tokens.LAST) {
sb.append(' ').append(Tokens.T_NULLS).append(' ');
sb.append(Tokens.T_LAST);
}
sb.append(')');
return sb.toString();
}
case FUNC_SYSDATE :
case FUNC_SYSTIMESTAMP :
return name;
case FUNC_DATABASE :
case FUNC_DATABASE_NAME :
case FUNC_ISAUTOCOMMIT :
case FUNC_ISREADONLYSESSION :
case FUNC_ISREADONLYDATABASE :
case FUNC_ISREADONLYDATABASEFILES :
case FUNC_ISOLATION_LEVEL :
case FUNC_SESSION_ISOLATION_LEVEL :
case FUNC_DATABASE_ISOLATION_LEVEL :
case FUNC_TRANSACTION_CONTROL :
case FUNC_TIMEZONE :
case FUNC_SESSION_TIMEZONE :
case FUNC_DATABASE_TIMEZONE :
case FUNC_DATABASE_VERSION :
case FUNC_PI :
case FUNC_IDENTITY :
case FUNC_SESSION_ID :
case FUNC_ACTION_ID :
case FUNC_TRANSACTION_ID :
case FUNC_TRANSACTION_SIZE :
return new StringBuffer(name).append(
Tokens.T_OPENBRACKET).append(
Tokens.T_CLOSEBRACKET).toString();
case FUNC_TIMESTAMPADD : {
String token = Tokens.getSQLTSIString(
((Number) nodes[0].getValue(null)).intValue());
return new StringBuffer(Tokens.T_TIMESTAMPADD).append(
Tokens.T_OPENBRACKET).append(token).append(
Tokens.T_COMMA).append(nodes[1].getSQL()).append(
Tokens.T_COMMA).append(nodes[2].getSQL()).append(
Tokens.T_CLOSEBRACKET).toString();
}
case FUNC_TIMESTAMPDIFF : {
String token = Tokens.getSQLTSIString(
((Number) nodes[0].getValue(null)).intValue());
return new StringBuffer(Tokens.T_TIMESTAMPDIFF).append(
Tokens.T_OPENBRACKET).append(token).append(
Tokens.T_COMMA).append(nodes[1].getSQL()).append(
Tokens.T_COMMA).append(nodes[2].getSQL()).append(
Tokens.T_CLOSEBRACKET).toString();
}
case FUNC_DATE_ADD :
return new StringBuffer(nodes[0].getSQL()).append(' ').append(
'+').append(nodes[1].getSQL()).toString();
case FUNC_DATE_SUB :
return new StringBuffer(nodes[0].getSQL()).append(' ').append(
'-').append(nodes[1].getSQL()).toString();
case FUNC_UNIX_MILLIS :
case FUNC_UNIX_TIMESTAMP :
case FUNC_RAND : {
StringBuffer sb = new StringBuffer(name).append('(');
if (nodes[0] != null) {
sb.append(nodes[0].getSQL());
}
sb.append(')');
return sb.toString();
}
case FUNC_LOAD_FILE :
case FUNC_ROUND :
case FUNC_TIMESTAMP :
case FUNC_TO_DATE :
case FUNC_TO_NUMBER :
case FUNC_TO_TIMESTAMP :
case FUNC_TO_TIMESTAMP_TZ :
case FUNC_TRUNC :
case FUNC_TRUNCATE : {
StringBuffer sb = new StringBuffer(name).append('(');
sb.append(nodes[0].getSQL());
if (nodes.length > 1 && nodes[1] != null) {
sb.append(',').append(nodes[1].getSQL());
}
sb.append(')');
return sb.toString();
}
case FUNC_ACOS :
case FUNC_ASCII :
case FUNC_ASIN :
case FUNC_ATAN :
case FUNC_CHAR :
case FUNC_COS :
case FUNC_COT :
case FUNC_DAYS :
case FUNC_DEGREES :
case FUNC_SIN :
case FUNC_TAN :
case FUNC_LOG10 :
case FUNC_RADIANS :
case FUNC_ROUNDMAGIC :
case FUNC_SIGN :
case FUNC_SOUNDEX :
case FUNC_SPACE :
case FUNC_REVERSE :
case FUNC_HEXTORAW :
case FUNC_RAWTOHEX :
case FUNC_LOB_ID : {
return new StringBuffer(name).append('(').append(
nodes[0].getSQL()).append(')').toString();
}
case FUNC_ATAN2 :
case FUNC_BITAND :
case FUNC_BITANDNOT :
case FUNC_BITOR :
case FUNC_BITNOT :
case FUNC_BITXOR :
case FUNC_DIFFERENCE :
case FUNC_REPEAT :
case FUNC_LEFT :
case FUNC_RIGHT :
case FUNC_CRYPT_KEY :
case FUNC_TO_CHAR :
case FUNC_REGEXP_MATCHES :
case FUNC_REGEXP_SUBSTRING :
case FUNC_REGEXP_SUBSTRING_ARRAY : {
return new StringBuffer(name).append('(').append(
nodes[0].getSQL()).append(Tokens.T_COMMA).append(
nodes[1].getSQL()).append(')').toString();
}
case FUNC_DIAGNOSTICS : {
StringBuffer sb = new StringBuffer(name).append('(');
//exprSubType == ExpressionColumn.idx_row_count
sb.append(Tokens.T_ROW_COUNT);
sb.append(')');
return sb.toString();
}
case FUNC_SEQUENCE_ARRAY :
case FUNC_REGEXP_REPLACE :
case FUNC_REPLACE : {
return new StringBuffer(name).append('(').append(
nodes[0].getSQL()).append(Tokens.T_COMMA).append(
nodes[1].getSQL()).append(Tokens.T_COMMA).append(
nodes[2].getSQL()).append(')').toString();
}
case FUNC_DBTIMEZONE :
case FUNC_SESSIONTIMEZONE :
case FUNC_SYS_EXTRACT_UTC :
case FUNC_LAST_DAY :
case FUNC_NEXT_DAY :
case FUNC_TO_DSINTERVAL :
case FUNC_TO_YMINTERVAL :
case FUNC_ADD_MONTHS :
case FUNC_FROM_TZ :
case FUNC_MONTHS_BETWEEN :
case FUNC_NUMTODSINTERVAL :
case FUNC_NUMTOYMINTERVAL :
case FUNC_NEW_TIME :
case FUNC_TRANSLATE :
return getSQLSimple();
default :
return super.getSQL();
}
}
private String getSQLSimple() {
StringBuffer sb = new StringBuffer(name).append('(');
for (int i = 0; i < nodes.length; i++) {
if (i > 0) {
sb.append(',');
}
sb.append(nodes[i].getSQL());
}
sb.append(')');
return sb.toString();
}
/**
* Returns a four character code representing the sound of the given
* <code>String</code>. Non-ASCCI characters in the
* input <code>String</code> are ignored. <p>
*
* This method was rewritten for HSQLDB to comply with the description at
* <a href="http://www.archives.gov/research/census/soundex.html">
* http://www.archives.gov/research/census/soundex.html </a>.<p>
* @param s the <code>String</code> for which to calculate the 4 character
* <code>SOUNDEX</code> value
* @return the 4 character <code>SOUNDEX</code> value for the given
* <code>String</code>
*/
public static char[] soundex(String s) {
if (s == null) {
return null;
}
s = s.toUpperCase(Locale.ENGLISH);
int len = s.length();
char[] b = new char[] {
'0', '0', '0', '0'
};
char lastdigit = '0';
for (int i = 0, j = 0; i < len && j < 4; i++) {
char c = s.charAt(i);
char newdigit;
if ("AEIOUY".indexOf(c) != -1) {
newdigit = '7';
} else if (c == 'H' || c == 'W') {
newdigit = '8';
} else if ("BFPV".indexOf(c) != -1) {
newdigit = '1';
} else if ("CGJKQSXZ".indexOf(c) != -1) {
newdigit = '2';
} else if (c == 'D' || c == 'T') {
newdigit = '3';
} else if (c == 'L') {
newdigit = '4';
} else if (c == 'M' || c == 'N') {
newdigit = '5';
} else if (c == 'R') {
newdigit = '6';
} else {
continue;
}
if (j == 0) {
b[j++] = c;
lastdigit = newdigit;
} else if (newdigit <= '6') {
if (newdigit != lastdigit) {
b[j++] = newdigit;
lastdigit = newdigit;
}
} else if (newdigit == '7') {
lastdigit = newdigit;
}
}
return b;
}
int getTSIToken(String string) {
int part;
if ("yy".equalsIgnoreCase(string) || "year".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_YEAR;
} else if ("mm".equalsIgnoreCase(string)
|| "month".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_MONTH;
} else if ("dd".equalsIgnoreCase(string)
|| "day".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_DAY;
} else if ("hh".equalsIgnoreCase(string)
|| "hour".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_HOUR;
} else if ("mi".equalsIgnoreCase(string)
|| "minute".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_MINUTE;
} else if ("ss".equalsIgnoreCase(string)
|| "second".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_SECOND;
} else if ("ms".equalsIgnoreCase(string)
|| "millisecond".equalsIgnoreCase(string)) {
part = Tokens.SQL_TSI_MILLI_SECOND;
} else {
throw Error.error(ErrorCode.X_42566, string);
}
return part;
}
IntKeyIntValueHashMap getTranslationMap(String source, String dest) {
IntKeyIntValueHashMap map = new IntKeyIntValueHashMap();
for (int i = 0; i < source.length(); i++) {
int character = source.charAt(i);
if (i >= dest.length()) {
map.put(character, -1);
continue;
}
int value = dest.charAt(i);
map.put(character, value);
}
return map;
}
String translateWithMap(String source, IntKeyIntValueHashMap map) {
StringBuffer sb = new StringBuffer(source.length());
for (int i = 0; i < source.length(); i++) {
int character = source.charAt(i);
int value = map.get(character, -2);
if (value == -2) {
sb.append((char) character);
} else if (value == -1) {
//
} else {
sb.append((char) value);
}
}
return sb.toString();
}
}