public Value getValue(Session session) {
return getValueWithArgs(session, args);
}
private Value getSimpleValue(Session session, Value v0, Expression[] args, Value[] values) {
Value result;
switch (info.type) {
case ABS:
result = v0.getSignum() > 0 ? v0 : v0.negate();
break;
case ACOS:
result = ValueDouble.get(Math.acos(v0.getDouble()));
break;
case ASIN:
result = ValueDouble.get(Math.asin(v0.getDouble()));
break;
case ATAN:
result = ValueDouble.get(Math.atan(v0.getDouble()));
break;
case CEILING:
result = ValueDouble.get(Math.ceil(v0.getDouble()));
break;
case COS:
result = ValueDouble.get(Math.cos(v0.getDouble()));
break;
case COSH:
result = ValueDouble.get(Math.cosh(v0.getDouble()));
break;
case COT: {
double d = Math.tan(v0.getDouble());
if (d == 0.0) {
throw DbException.get(ErrorCode.DIVISION_BY_ZERO_1, getSQL());
}
result = ValueDouble.get(1. / d);
break;
}
case DEGREES:
result = ValueDouble.get(Math.toDegrees(v0.getDouble()));
break;
case EXP:
result = ValueDouble.get(Math.exp(v0.getDouble()));
break;
case FLOOR:
result = ValueDouble.get(Math.floor(v0.getDouble()));
break;
case LN:
result = ValueDouble.get(Math.log(v0.getDouble()));
break;
case LOG:
if (database.getMode().logIsLogBase10) {
result = ValueDouble.get(Math.log10(v0.getDouble()));
} else {
result = ValueDouble.get(Math.log(v0.getDouble()));
}
break;
case LOG10:
result = ValueDouble.get(log10(v0.getDouble()));
break;
case PI:
result = ValueDouble.get(Math.PI);
break;
case RADIANS:
result = ValueDouble.get(Math.toRadians(v0.getDouble()));
break;
case RAND: {
if (v0 != null) {
session.getRandom().setSeed(v0.getInt());
}
result = ValueDouble.get(session.getRandom().nextDouble());
break;
}
case ROUNDMAGIC:
result = ValueDouble.get(roundmagic(v0.getDouble()));
break;
case SIGN:
result = ValueInt.get(v0.getSignum());
break;
case SIN:
result = ValueDouble.get(Math.sin(v0.getDouble()));
break;
case SINH:
result = ValueDouble.get(Math.sinh(v0.getDouble()));
break;
case SQRT:
result = ValueDouble.get(Math.sqrt(v0.getDouble()));
break;
case TAN:
result = ValueDouble.get(Math.tan(v0.getDouble()));
break;
case TANH:
result = ValueDouble.get(Math.tanh(v0.getDouble()));
break;
case SECURE_RAND:
result = ValueBytes.getNoCopy(MathUtils.secureRandomBytes(v0.getInt()));
break;
case EXPAND:
result = ValueBytes.getNoCopy(CompressTool.getInstance().expand(v0.getBytesNoCopy()));
break;
case ZERO:
result = ValueInt.get(0);
break;
case RANDOM_UUID:
result = ValueUuid.getNewRandom();
break;
// string
case ASCII: {
String s = v0.getString();
if (s.length() == 0) {
result = ValueNull.INSTANCE;
} else {
result = ValueInt.get(s.charAt(0));
}
break;
}
case BIT_LENGTH:
result = ValueLong.get(16 * length(v0));
break;
case CHAR:
result = ValueString.get(String.valueOf((char) v0.getInt()));
break;
case CHAR_LENGTH:
case LENGTH:
result = ValueLong.get(length(v0));
break;
case OCTET_LENGTH:
result = ValueLong.get(2 * length(v0));
break;
case CONCAT_WS:
case CONCAT: {
result = ValueNull.INSTANCE;
int start = 0;
String separator = "";
if (info.type == CONCAT_WS) {
start = 1;
separator = getNullOrValue(session, args, values, 0).getString();
}
for (int i = start; i < args.length; i++) {
Value v = getNullOrValue(session, args, values, i);
if (v == ValueNull.INSTANCE) {
continue;
}
if (result == ValueNull.INSTANCE) {
result = v;
} else {
String tmp = v.getString();
if (!StringUtils.isNullOrEmpty(separator) && !StringUtils.isNullOrEmpty(tmp)) {
tmp = separator.concat(tmp);
}
result = ValueString.get(result.getString().concat(tmp));
}
}
if (info.type == CONCAT_WS) {
if (separator != null && result == ValueNull.INSTANCE) {
result = ValueString.get("");
}
}
break;
}
case HEXTORAW:
result = ValueString.get(hexToRaw(v0.getString()));
break;
case LOWER:
case LCASE:
// TODO this is locale specific, need to document or provide a way
// to set the locale
result = ValueString.get(v0.getString().toLowerCase());
break;
case RAWTOHEX:
result = ValueString.get(rawToHex(v0.getString()));
break;
case SOUNDEX:
result = ValueString.get(getSoundex(v0.getString()));
break;
case SPACE: {
int len = Math.max(0, v0.getInt());
char[] chars = new char[len];
for (int i = len - 1; i >= 0; i--) {
chars[i] = ' ';
}
result = ValueString.get(new String(chars));
break;
}
case UPPER:
case UCASE:
// TODO this is locale specific, need to document or provide a way
// to set the locale
result = ValueString.get(v0.getString().toUpperCase());
break;
case STRINGENCODE:
result = ValueString.get(StringUtils.javaEncode(v0.getString()));
break;
case STRINGDECODE:
result = ValueString.get(StringUtils.javaDecode(v0.getString()));
break;
case STRINGTOUTF8:
result = ValueBytes.getNoCopy(v0.getString().getBytes(Constants.UTF8));
break;
case UTF8TOSTRING:
result = ValueString.get(new String(v0.getBytesNoCopy(), Constants.UTF8));
break;
case XMLCOMMENT:
result = ValueString.get(StringUtils.xmlComment(v0.getString()));
break;
case XMLCDATA:
result = ValueString.get(StringUtils.xmlCData(v0.getString()));
break;
case XMLSTARTDOC:
result = ValueString.get(StringUtils.xmlStartDoc());
break;
case DAY_NAME: {
SimpleDateFormat dayName = new SimpleDateFormat("EEEE", Locale.ENGLISH);
result = ValueString.get(dayName.format(v0.getDate()));
break;
}
case DAY_OF_MONTH:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.DAY_OF_MONTH));
break;
case DAY_OF_WEEK:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.DAY_OF_WEEK));
break;
case DAY_OF_YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.DAY_OF_YEAR));
break;
case HOUR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.HOUR_OF_DAY));
break;
case MINUTE:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.MINUTE));
break;
case MONTH:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.MONTH));
break;
case MONTH_NAME: {
SimpleDateFormat monthName = new SimpleDateFormat("MMMM", Locale.ENGLISH);
result = ValueString.get(monthName.format(v0.getDate()));
break;
}
case QUARTER:
result = ValueInt.get((DateTimeUtils.getDatePart(v0.getDate(), Calendar.MONTH) - 1) / 3 + 1);
break;
case SECOND:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.SECOND));
break;
case WEEK:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.WEEK_OF_YEAR));
break;
case YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.YEAR));
break;
case ISO_YEAR:
result = ValueInt.get(DateTimeUtils.getIsoYear(v0.getDate()));
break;
case ISO_WEEK:
result = ValueInt.get(DateTimeUtils.getIsoWeek(v0.getDate()));
break;
case ISO_DAY_OF_WEEK:
result = ValueInt.get(DateTimeUtils.getIsoDayOfWeek(v0.getDate()));
break;
case CURDATE:
case CURRENT_DATE: {
long now = session.getTransactionStart();
// need to normalize
result = ValueDate.get(new Date(now));
break;
}
case CURTIME:
case CURRENT_TIME: {
long now = session.getTransactionStart();
// need to normalize
result = ValueTime.get(new Time(now));
break;
}
case NOW:
case CURRENT_TIMESTAMP: {
long now = session.getTransactionStart();
ValueTimestamp vt = ValueTimestamp.get(new Timestamp(now));
if (v0 != null) {
Mode mode = database.getMode();
vt = (ValueTimestamp) vt.convertScale(mode.convertOnlyToSmallerScale, v0.getInt());
}
result = vt;
break;
}
case DATABASE:
result = ValueString.get(database.getShortName());
break;
case USER:
case CURRENT_USER:
result = ValueString.get(session.getUser().getName());
break;
case IDENTITY:
result = session.getLastIdentity();
break;
case SCOPE_IDENTITY:
result = session.getLastScopeIdentity();
break;
case AUTOCOMMIT:
result = ValueBoolean.get(session.getAutoCommit());
break;
case READONLY:
result = ValueBoolean.get(database.isReadOnly());
break;
case DATABASE_PATH: {
String path = database.getDatabasePath();
result = path == null ? (Value) ValueNull.INSTANCE : ValueString.get(path);
break;
}
case LOCK_TIMEOUT:
result = ValueInt.get(session.getLockTimeout());
break;
case DISK_SPACE_USED:
result = ValueLong.get(getDiskSpaceUsed(session, v0));
break;
case CAST:
case CONVERT: {
v0 = v0.convertTo(dataType);
Mode mode = database.getMode();
v0 = v0.convertScale(mode.convertOnlyToSmallerScale, scale);
v0 = v0.convertPrecision(getPrecision(), false);
result = v0;
break;
}
case MEMORY_FREE:
session.getUser().checkAdmin();
result = ValueInt.get(Utils.getMemoryFree());
break;
case MEMORY_USED:
session.getUser().checkAdmin();
result = ValueInt.get(Utils.getMemoryUsed());
break;
case LOCK_MODE:
result = ValueInt.get(database.getLockMode());
break;
case SCHEMA:
result = ValueString.get(session.getCurrentSchemaName());
break;
case SESSION_ID:
result = ValueInt.get(session.getId());
break;
case IFNULL: {
result = v0;
if (v0 == ValueNull.INSTANCE) {
result = getNullOrValue(session, args, values, 1);
}
break;
}
case CASEWHEN: {
Value v;
if (v0 == ValueNull.INSTANCE || !v0.getBoolean().booleanValue()) {
v = getNullOrValue(session, args, values, 2);
} else {
v = getNullOrValue(session, args, values, 1);
}
result = v.convertTo(dataType);
break;
}
case DECODE: {
int index = -1;
for (int i = 1; i < args.length - 1; i += 2) {
if (database.areEqual(v0, getNullOrValue(session, args, values, i))) {
index = i + 1;
}
}
if (index < 0 && args.length % 2 == 0) {
index = args.length - 1;
}
Value v = index < 0 ? ValueNull.INSTANCE : getNullOrValue(session, args, values, index);
result = v.convertTo(dataType);
break;
}
case NVL2: {
Value v;
if (v0 == ValueNull.INSTANCE) {
v = getNullOrValue(session, args, values, 2);
} else {
v = getNullOrValue(session, args, values, 1);
}
result = v.convertTo(dataType);
break;
}
case COALESCE: {
result = v0;
for (int i = 0; i < args.length; i++) {
Value v = getNullOrValue(session, args, values, i);
if (!(v == ValueNull.INSTANCE)) {
result = v.convertTo(dataType);
break;
}
}
break;
}
case GREATEST:
case LEAST: {
result = ValueNull.INSTANCE;
for (int i = 0; i < args.length; i++) {
Value v = getNullOrValue(session, args, values, i);
if (!(v == ValueNull.INSTANCE)) {
v = v.convertTo(dataType);
if (result == ValueNull.INSTANCE) {
result = v;
} else {
int comp = database.compareTypeSave(result, v);
if (info.type == GREATEST && comp < 0) {
result = v;
} else if (info.type == LEAST && comp > 0) {
result = v;
}
}
}
}
break;
}
case CASE: {
result = null;
int i = 0;
for (; i < args.length; i++) {
Value when = getNullOrValue(session, args, values, i++);
if (Boolean.TRUE.equals(when)) {
result = getNullOrValue(session, args, values, i);
break;
}
}
if (result == null) {
result = i < args.length ? getNullOrValue(session, args, values, i) : ValueNull.INSTANCE;
}
break;
}
case ARRAY_GET: {
if (v0.getType() == Value.ARRAY) {
Value v1 = getNullOrValue(session, args, values, 1);
int element = v1.getInt();
Value[] list = ((ValueArray) v0).getList();
if (element < 1 || element > list.length) {
result = ValueNull.INSTANCE;
} else {
result = list[element - 1];
}
} else {
result = ValueNull.INSTANCE;
}
break;
}
case ARRAY_LENGTH: {
if (v0.getType() == Value.ARRAY) {
Value[] list = ((ValueArray) v0).getList();
result = ValueInt.get(list.length);
} else {
result = ValueNull.INSTANCE;
}
break;
}
case ARRAY_CONTAINS: {
result = ValueBoolean.get(false);
if (v0.getType() == Value.ARRAY) {
Value v1 = getNullOrValue(session, args, values, 1);
Value[] list = ((ValueArray) v0).getList();
for (Value v : list) {
if (v.equals(v1)) {
result = ValueBoolean.get(true);
break;