提交 45394387 authored 作者: Thomas Mueller's avatar Thomas Mueller

Issue 414: for some functions, the parameters were evaluated twice (for example…

Issue 414: for some functions, the parameters were evaluated twice (for example "char(nextval(..))" ran "nextval(..)" twice).
上级 74a0a0cc
...@@ -18,7 +18,9 @@ Change Log ...@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>The ResultSetMetaData methods getSchemaName and getTableName <ul><li>Issue 414: for some functions, the parameters were evaluated twice
(for example "char(nextval(..))" ran "nextval(..)" twice).
</li><li>The ResultSetMetaData methods getSchemaName and getTableName
could return null instead of "" (an empty string) as specified in the JDBC API. could return null instead of "" (an empty string) as specified in the JDBC API.
</li><li>Added compatibility for "SET NAMES" query in MySQL compatibility mode.</li> </li><li>Added compatibility for "SET NAMES" query in MySQL compatibility mode.</li>
</ul> </ul>
......
...@@ -447,17 +447,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -447,17 +447,7 @@ public class Function extends Expression implements FunctionCall {
return getValueWithArgs(session, args); return getValueWithArgs(session, args);
} }
private static Value getNullOrValue(Session session, Expression[] x, int i) { private Value getSimpleValue(Session session, Value v0, Expression[] args, Value[] values) {
if (i < x.length) {
Expression e = x[i];
if (e != null) {
return e.getValue(session);
}
}
return null;
}
private Value getSimpleValue(Session session, Value v0, Expression[] argList) {
Value result; Value result;
switch (info.type) { switch (info.type) {
case ABS: case ABS:
...@@ -582,8 +572,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -582,8 +572,8 @@ public class Function extends Expression implements FunctionCall {
break; break;
case CONCAT: { case CONCAT: {
result = ValueNull.INSTANCE; result = ValueNull.INSTANCE;
for (Expression e : argList) { for (int i = 0; i < args.length; i++) {
Value v = e.getValue(session); Value v = getNullOrValue(session, args, values, i);
if (v == ValueNull.INSTANCE) { if (v == ValueNull.INSTANCE) {
continue; continue;
} }
...@@ -774,49 +764,50 @@ public class Function extends Expression implements FunctionCall { ...@@ -774,49 +764,50 @@ public class Function extends Expression implements FunctionCall {
result = ValueInt.get(session.getId()); result = ValueInt.get(session.getId());
break; break;
case IFNULL: { case IFNULL: {
result = v0 == ValueNull.INSTANCE ? argList[1].getValue(session) : v0; result = v0;
if (v0 == ValueNull.INSTANCE) {
result = getNullOrValue(session, args, values, 1);
}
break; break;
} }
case CASEWHEN: { case CASEWHEN: {
Expression expr; Value v;
if (v0 == ValueNull.INSTANCE || !v0.getBoolean().booleanValue()) { if (v0 == ValueNull.INSTANCE || !v0.getBoolean().booleanValue()) {
expr = argList[2]; v = getNullOrValue(session, args, values, 2);
} else { } else {
expr = argList[1]; v = getNullOrValue(session, args, values, 1);
} }
Value v = expr.getValue(session);
result = v.convertTo(dataType); result = v.convertTo(dataType);
break; break;
} }
case DECODE: { case DECODE: {
Expression expr = null; int index = -1;
for (int i = 1; i < argList.length - 1; i += 2) { for (int i = 1; i < args.length - 1; i += 2) {
if (database.areEqual(v0, argList[i].getValue(session))) { if (database.areEqual(v0, getNullOrValue(session, args, values, i))) {
expr = argList[i + 1]; index = i + 1;
} }
} }
if (expr == null && argList.length % 2 == 0) { if (index < 0 && args.length % 2 == 0) {
expr = argList[argList.length - 1]; index = args.length - 1;
} }
Value v = expr == null ? ValueNull.INSTANCE : expr.getValue(session); Value v = index < 0 ? ValueNull.INSTANCE : getNullOrValue(session, args, values, index);
result = v.convertTo(dataType); result = v.convertTo(dataType);
break; break;
} }
case NVL2: { case NVL2: {
Expression expr; Value v;
if (v0 == ValueNull.INSTANCE) { if (v0 == ValueNull.INSTANCE) {
expr = argList[2]; v = getNullOrValue(session, args, values, 2);
} else { } else {
expr = argList[1]; v = getNullOrValue(session, args, values, 1);
} }
Value v = expr.getValue(session);
result = v.convertTo(dataType); result = v.convertTo(dataType);
break; break;
} }
case COALESCE: { case COALESCE: {
result = v0; result = v0;
for (int i = 0; i < argList.length; i++) { for (int i = 0; i < args.length; i++) {
Value v = i == 0 ? v0 : argList[i].getValue(session); Value v = getNullOrValue(session, args, values, i);
if (!(v == ValueNull.INSTANCE)) { if (!(v == ValueNull.INSTANCE)) {
result = v.convertTo(dataType); result = v.convertTo(dataType);
break; break;
...@@ -827,8 +818,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -827,8 +818,8 @@ public class Function extends Expression implements FunctionCall {
case GREATEST: case GREATEST:
case LEAST: { case LEAST: {
result = ValueNull.INSTANCE; result = ValueNull.INSTANCE;
for (int i = 0; i < argList.length; i++) { for (int i = 0; i < args.length; i++) {
Value v = i == 0 ? v0 : argList[i].getValue(session); Value v = getNullOrValue(session, args, values, i);
if (!(v == ValueNull.INSTANCE)) { if (!(v == ValueNull.INSTANCE)) {
v = v.convertTo(dataType); v = v.convertTo(dataType);
if (result == ValueNull.INSTANCE) { if (result == ValueNull.INSTANCE) {
...@@ -848,21 +839,21 @@ public class Function extends Expression implements FunctionCall { ...@@ -848,21 +839,21 @@ public class Function extends Expression implements FunctionCall {
case CASE: { case CASE: {
result = null; result = null;
int i = 0; int i = 0;
for (; i < argList.length; i++) { for (; i < args.length; i++) {
Value when = argList[i++].getValue(session); Value when = getNullOrValue(session, args, values, i++);
if (Boolean.TRUE.equals(when)) { if (Boolean.TRUE.equals(when)) {
result = argList[i].getValue(session); result = getNullOrValue(session, args, values, i);
break; break;
} }
} }
if (result == null) { if (result == null) {
result = i < argList.length ? argList[i].getValue(session) : ValueNull.INSTANCE; result = i < args.length ? getNullOrValue(session, args, values, i) : ValueNull.INSTANCE;
} }
break; break;
} }
case ARRAY_GET: { case ARRAY_GET: {
if (v0.getType() == Value.ARRAY) { if (v0.getType() == Value.ARRAY) {
Value v1 = argList[1].getValue(session); Value v1 = getNullOrValue(session, args, values, 1);
int element = v1.getInt(); int element = v1.getInt();
Value[] list = ((ValueArray) v0).getList(); Value[] list = ((ValueArray) v0).getList();
if (element < 1 || element > list.length) { if (element < 1 || element > list.length) {
...@@ -887,7 +878,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -887,7 +878,7 @@ public class Function extends Expression implements FunctionCall {
case ARRAY_CONTAINS: { case ARRAY_CONTAINS: {
result = ValueBoolean.get(false); result = ValueBoolean.get(false);
if (v0.getType() == Value.ARRAY) { if (v0.getType() == Value.ARRAY) {
Value v1 = argList[1].getValue(session); Value v1 = getNullOrValue(session, args, values, 1);
Value[] list = ((ValueArray) v0).getList(); Value[] list = ((ValueArray) v0).getList();
for (Value v : list) { for (Value v : list) {
if (v.equals(v1)) { if (v.equals(v1)) {
...@@ -928,24 +919,39 @@ public class Function extends Expression implements FunctionCall { ...@@ -928,24 +919,39 @@ public class Function extends Expression implements FunctionCall {
return false; return false;
} }
private Value getValueWithArgs(Session session, Expression[] argList) { private static Value getNullOrValue(Session session, Expression[] args, Value[] values, int i) {
if (i < values.length) {
return null;
}
Value v = values[i];
if (v == null) {
v = values[i] = args[i].getValue(session);
}
return v;
}
private Value getValueWithArgs(Session session, Expression[] args) {
Value[] values = new Value[args.length];
if (info.nullIfParameterIsNull) { if (info.nullIfParameterIsNull) {
for (int i = 0; i < argList.length; i++) { for (int i = 0; i < args.length; i++) {
if (getNullOrValue(session, argList, i) == ValueNull.INSTANCE) { Expression e = args[i];
Value v = e.getValue(session);
if (v == ValueNull.INSTANCE) {
return ValueNull.INSTANCE; return ValueNull.INSTANCE;
} }
values[i] = v;
} }
} }
Value v0 = getNullOrValue(session, argList, 0); Value v0 = getNullOrValue(session, args, values, 0);
Value resultSimple = getSimpleValue(session, v0, argList); Value resultSimple = getSimpleValue(session, v0, args, values);
if (resultSimple != null) { if (resultSimple != null) {
return resultSimple; return resultSimple;
} }
Value v1 = getNullOrValue(session, argList, 1); Value v1 = getNullOrValue(session, args, values, 1);
Value v2 = getNullOrValue(session, argList, 2); Value v2 = getNullOrValue(session, args, values, 2);
Value v3 = getNullOrValue(session, argList, 3); Value v3 = getNullOrValue(session, args, values, 3);
Value v4 = getNullOrValue(session, argList, 4); Value v4 = getNullOrValue(session, args, values, 4);
Value v5 = getNullOrValue(session, argList, 5); Value v5 = getNullOrValue(session, args, values, 5);
Value result; Value result;
switch (info.type) { switch (info.type) {
case ATAN2: case ATAN2:
...@@ -1149,7 +1155,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1149,7 +1155,7 @@ public class Function extends Expression implements FunctionCall {
String fieldSeparatorRead = v3 == null ? null : v3.getString(); String fieldSeparatorRead = v3 == null ? null : v3.getString();
String fieldDelimiter = v4 == null ? null : v4.getString(); String fieldDelimiter = v4 == null ? null : v4.getString();
String escapeCharacter = v5 == null ? null : v5.getString(); String escapeCharacter = v5 == null ? null : v5.getString();
Value v6 = getNullOrValue(session, argList, 6); Value v6 = getNullOrValue(session, args, values, 6);
String nullString = v6 == null ? null : v6.getString(); String nullString = v6 == null ? null : v6.getString();
setCsvDelimiterEscape(csv, fieldSeparatorRead, fieldDelimiter, escapeCharacter); setCsvDelimiterEscape(csv, fieldSeparatorRead, fieldDelimiter, escapeCharacter);
csv.setNullString(nullString); csv.setNullString(nullString);
...@@ -1185,9 +1191,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -1185,9 +1191,9 @@ public class Function extends Expression implements FunctionCall {
String fieldSeparatorWrite = v3 == null ? null : v3.getString(); String fieldSeparatorWrite = v3 == null ? null : v3.getString();
String fieldDelimiter = v4 == null ? null : v4.getString(); String fieldDelimiter = v4 == null ? null : v4.getString();
String escapeCharacter = v5 == null ? null : v5.getString(); String escapeCharacter = v5 == null ? null : v5.getString();
Value v6 = getNullOrValue(session, argList, 6); Value v6 = getNullOrValue(session, args, values, 6);
String nullString = v6 == null ? null : v6.getString(); String nullString = v6 == null ? null : v6.getString();
Value v7 = getNullOrValue(session, argList, 7); Value v7 = getNullOrValue(session, args, values, 7);
String lineSeparator = v7 == null ? null : v7.getString(); String lineSeparator = v7 == null ? null : v7.getString();
setCsvDelimiterEscape(csv, fieldSeparatorWrite, fieldDelimiter, escapeCharacter); setCsvDelimiterEscape(csv, fieldSeparatorWrite, fieldDelimiter, escapeCharacter);
csv.setNullString(nullString); csv.setNullString(nullString);
...@@ -1204,7 +1210,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1204,7 +1210,7 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case SET: { case SET: {
Variable var = (Variable) argList[0]; Variable var = (Variable) args[0];
session.setVariable(var.getName(), v1); session.setVariable(var.getName(), v1);
result = v1; result = v1;
break; break;
...@@ -1212,7 +1218,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1212,7 +1218,7 @@ public class Function extends Expression implements FunctionCall {
case FILE_READ: { case FILE_READ: {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
String fileName = v0.getString(); String fileName = v0.getString();
boolean blob = argList.length == 1; boolean blob = args.length == 1;
try { try {
InputStream in = new AutoCloseInputStream(FileUtils.newInputStream(fileName)); InputStream in = new AutoCloseInputStream(FileUtils.newInputStream(fileName));
if (blob) { if (blob) {
......
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
create sequence seq start with 65 increment by 1;
> ok
select char(nextval('seq')) as x;
> X
> -
> A
select char(nextval('seq')) as x;
> X
> -
> B
drop sequence seq;
> ok
create table test(id int, name varchar); create table test(id int, name varchar);
> ok > ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论