提交 5ae94953 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Separate array and row value expressions

上级 291b541c
...@@ -2023,23 +2023,12 @@ ID=1 AND NAME='Hi' ...@@ -2023,23 +2023,12 @@ ID=1 AND NAME='Hi'
"Other Grammar","Array"," "Other Grammar","Array","
ARRAY '[' [ expression, [,...] ] ']' ARRAY '[' [ expression, [,...] ] ']'
| ( [ expression, [ expression [,...] ] ] )
"," ","
An array of values. An array of values.
The array can be declared with standard ARRAY[] syntax or with H2 syntax.
With standard syntax trailing comma is not allowed.
With H2 syntax an empty array is '()'. Trailing comma is ignored.
An array with one element must contain a trailing comma to be parsed as an array.
"," ","
ARRAY[1, 2] ARRAY[1, 2]
ARRAY[1] ARRAY[1]
ARRAY[] ARRAY[]
(1, 2)
(1, )
()
" "
"Other Grammar","Boolean"," "Other Grammar","Boolean","
...@@ -2520,6 +2509,16 @@ LZF is faster but uses more space. ...@@ -2520,6 +2509,16 @@ LZF is faster but uses more space.
COMPRESSION LZF COMPRESSION LZF
" "
"Other Grammar","Row value expression","
ROW (expression, [,...])
| ( [ expression, expression [,...] ] )
","
A row value expression.
","
ROW (1)
(1, 2)
"
"Other Grammar","Select Expression"," "Other Grammar","Select Expression","
wildcardExpression | expression [ [ AS ] columnAlias ] wildcardExpression | expression [ [ AS ] columnAlias ]
"," ","
......
...@@ -478,7 +478,7 @@ unless they are quoted (surrounded with double quotes). The list is currently: ...@@ -478,7 +478,7 @@ unless they are quoted (surrounded with double quotes). The list is currently:
ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DISTINCT, EXCEPT, ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DISTINCT, EXCEPT,
EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS, EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS,
IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER,
PRIMARY, ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
WINDOW, WITH WINDOW, WITH
</code> </code>
</p><p> </p><p>
......
...@@ -43,6 +43,7 @@ import static org.h2.util.ParserUtil.OFFSET; ...@@ -43,6 +43,7 @@ import static org.h2.util.ParserUtil.OFFSET;
import static org.h2.util.ParserUtil.ON; import static org.h2.util.ParserUtil.ON;
import static org.h2.util.ParserUtil.ORDER; import static org.h2.util.ParserUtil.ORDER;
import static org.h2.util.ParserUtil.PRIMARY; import static org.h2.util.ParserUtil.PRIMARY;
import static org.h2.util.ParserUtil.ROW;
import static org.h2.util.ParserUtil.ROWNUM; import static org.h2.util.ParserUtil.ROWNUM;
import static org.h2.util.ParserUtil.SELECT; import static org.h2.util.ParserUtil.SELECT;
import static org.h2.util.ParserUtil.TRUE; import static org.h2.util.ParserUtil.TRUE;
...@@ -482,6 +483,8 @@ public class Parser { ...@@ -482,6 +483,8 @@ public class Parser {
"ORDER", "ORDER",
// PRIMARY // PRIMARY
"PRIMARY", "PRIMARY",
// ROW
"ROW",
// ROWNUM // ROWNUM
"ROWNUM", "ROWNUM",
// SELECT // SELECT
...@@ -2400,7 +2403,7 @@ public class Parser { ...@@ -2400,7 +2403,7 @@ public class Parser {
if (readIf(OFFSET)) { if (readIf(OFFSET)) {
hasOffsetOrFetch = true; hasOffsetOrFetch = true;
command.setOffset(readExpression().optimize(session)); command.setOffset(readExpression().optimize(session));
if (!readIf("ROW")) { if (!readIf(ROW)) {
readIf("ROWS"); readIf("ROWS");
} }
} }
...@@ -2409,7 +2412,7 @@ public class Parser { ...@@ -2409,7 +2412,7 @@ public class Parser {
if (!readIf("FIRST")) { if (!readIf("FIRST")) {
read("NEXT"); read("NEXT");
} }
if (readIf("ROW") || readIf("ROWS")) { if (readIf(ROW) || readIf("ROWS")) {
command.setLimit(ValueExpression.get(ValueInt.get(1))); command.setLimit(ValueExpression.get(ValueInt.get(1)));
} else { } else {
Expression limit = readExpression().optimize(session); Expression limit = readExpression().optimize(session);
...@@ -2417,7 +2420,7 @@ public class Parser { ...@@ -2417,7 +2420,7 @@ public class Parser {
if (readIf("PERCENT")) { if (readIf("PERCENT")) {
command.setFetchPercent(true); command.setFetchPercent(true);
} }
if (!readIf("ROW")) { if (!readIf(ROW)) {
read("ROWS"); read("ROWS");
} }
} }
...@@ -3198,7 +3201,7 @@ public class Parser { ...@@ -3198,7 +3201,7 @@ public class Parser {
WindowFrameExclusion exclusion = WindowFrameExclusion.EXCLUDE_NO_OTHERS; WindowFrameExclusion exclusion = WindowFrameExclusion.EXCLUDE_NO_OTHERS;
if (readIf("EXCLUDE")) { if (readIf("EXCLUDE")) {
if (readIf("CURRENT")) { if (readIf("CURRENT")) {
read("ROW"); read(ROW);
exclusion = WindowFrameExclusion.EXCLUDE_CURRENT_ROW; exclusion = WindowFrameExclusion.EXCLUDE_CURRENT_ROW;
} else if (readIf(GROUP)) { } else if (readIf(GROUP)) {
exclusion = WindowFrameExclusion.EXCLUDE_GROUP; exclusion = WindowFrameExclusion.EXCLUDE_GROUP;
...@@ -3222,7 +3225,7 @@ public class Parser { ...@@ -3222,7 +3225,7 @@ public class Parser {
return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_PRECEDING, null); return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_PRECEDING, null);
} }
if (readIf("CURRENT")) { if (readIf("CURRENT")) {
read("ROW"); read(ROW);
return new WindowFrameBound(WindowFrameBoundType.CURRENT_ROW, null); return new WindowFrameBound(WindowFrameBoundType.CURRENT_ROW, null);
} }
Expression value = readValueOrParameter(); Expression value = readValueOrParameter();
...@@ -3239,7 +3242,7 @@ public class Parser { ...@@ -3239,7 +3242,7 @@ public class Parser {
return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_FOLLOWING, null); return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_FOLLOWING, null);
} }
if (readIf("CURRENT")) { if (readIf("CURRENT")) {
read("ROW"); read(ROW);
return new WindowFrameBound(WindowFrameBoundType.CURRENT_ROW, null); return new WindowFrameBound(WindowFrameBoundType.CURRENT_ROW, null);
} }
Expression value = readValueOrParameter(); Expression value = readValueOrParameter();
...@@ -3790,7 +3793,7 @@ public class Parser { ...@@ -3790,7 +3793,7 @@ public class Parser {
case OPEN_PAREN: case OPEN_PAREN:
read(); read();
if (readIf(CLOSE_PAREN)) { if (readIf(CLOSE_PAREN)) {
r = new ExpressionList(new Expression[0]); r = new ExpressionList(new Expression[0], false);
} else { } else {
r = readExpression(); r = readExpression();
if (readIfMore(true)) { if (readIfMore(true)) {
...@@ -3801,10 +3804,24 @@ public class Parser { ...@@ -3801,10 +3804,24 @@ public class Parser {
list.add(readExpression()); list.add(readExpression());
} while (readIfMore(false)); } while (readIfMore(false));
} }
r = new ExpressionList(list.toArray(new Expression[0])); r = new ExpressionList(list.toArray(new Expression[0]), false);
} }
} }
break; break;
case ROW: {
read();
read(OPEN_PAREN);
if (readIf(CLOSE_PAREN)) {
r = new ExpressionList(new Expression[0], false);
} else {
ArrayList<Expression> list = Utils.newSmallArrayList();
do {
list.add(readExpression());
} while (readIfMore(true));
r = new ExpressionList(list.toArray(new Expression[0]), false);
}
break;
}
case TRUE: case TRUE:
read(); read();
r = ValueExpression.get(ValueBoolean.TRUE); r = ValueExpression.get(ValueBoolean.TRUE);
...@@ -3909,7 +3926,7 @@ public class Parser { ...@@ -3909,7 +3926,7 @@ public class Parser {
} }
read(CLOSE_BRACKET); read(CLOSE_BRACKET);
} }
return new ExpressionList(list.toArray(new Expression[0])); return new ExpressionList(list.toArray(new Expression[0]), true);
} }
break; break;
case 'C': case 'C':
...@@ -5790,7 +5807,7 @@ public class Parser { ...@@ -5790,7 +5807,7 @@ public class Parser {
for (int j = 0; j < rowCount; j++) { for (int j = 0; j < rowCount; j++) {
array[j] = rows.get(j).get(i); array[j] = rows.get(j).get(i);
} }
ExpressionList list = new ExpressionList(array); ExpressionList list = new ExpressionList(array, false);
tf.setParameter(i, list); tf.setParameter(i, list);
} }
tf.setColumns(columns); tf.setColumns(columns);
...@@ -5964,7 +5981,7 @@ public class Parser { ...@@ -5964,7 +5981,7 @@ public class Parser {
command.setTableName(tableName); command.setTableName(tableName);
if (readIf(FOR)) { if (readIf(FOR)) {
read("EACH"); read("EACH");
read("ROW"); read(ROW);
command.setRowBased(true); command.setRowBased(true);
} else { } else {
command.setRowBased(false); command.setRowBased(false);
......
...@@ -11,17 +11,20 @@ import org.h2.table.ColumnResolver; ...@@ -11,17 +11,20 @@ import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueRow;
/** /**
* A list of expressions, as in (ID, NAME). * A list of expressions, as in (ID, NAME).
* The result of this expression is an array. * The result of this expression is a row or an array.
*/ */
public class ExpressionList extends Expression { public class ExpressionList extends Expression {
private final Expression[] list; private final Expression[] list;
private final boolean isArray;
public ExpressionList(Expression[] list) { public ExpressionList(Expression[] list, boolean isArray) {
this.list = list; this.list = list;
this.isArray = isArray;
} }
@Override @Override
...@@ -30,12 +33,12 @@ public class ExpressionList extends Expression { ...@@ -30,12 +33,12 @@ public class ExpressionList extends Expression {
for (int i = 0; i < list.length; i++) { for (int i = 0; i < list.length; i++) {
v[i] = list[i].getValue(session); v[i] = list[i].getValue(session);
} }
return ValueArray.get(v); return isArray ? ValueArray.get(v) : ValueRow.get(v);
} }
@Override @Override
public int getType() { public int getType() {
return Value.ARRAY; return isArray ? Value.ARRAY : Value.ROW;
} }
@Override @Override
...@@ -85,12 +88,9 @@ public class ExpressionList extends Expression { ...@@ -85,12 +88,9 @@ public class ExpressionList extends Expression {
@Override @Override
public StringBuilder getSQL(StringBuilder builder) { public StringBuilder getSQL(StringBuilder builder) {
builder.append('('); builder.append(isArray ? "ARRAY [" : "ROW (");
writeExpressions(builder, list); writeExpressions(builder, list);
if (list.length == 1) { return builder.append(isArray ? ']' : ')');
builder.append(',');
}
return builder.append(')');
} }
@Override @Override
......
...@@ -14,8 +14,8 @@ import org.h2.result.ResultInterface; ...@@ -14,8 +14,8 @@ import org.h2.result.ResultInterface;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueRow;
/** /**
* A query returning a single value. * A query returning a single value.
...@@ -42,7 +42,7 @@ public class Subquery extends Expression { ...@@ -42,7 +42,7 @@ public class Subquery extends Expression {
if (result.getVisibleColumnCount() == 1) { if (result.getVisibleColumnCount() == 1) {
v = values[0]; v = values[0];
} else { } else {
v = ValueArray.get(values); v = ValueRow.get(values);
} }
if (result.hasNext()) { if (result.hasNext()) {
throw DbException.get(ErrorCode.SCALAR_SUBQUERY_CONTAINS_MORE_THAN_ONE_ROW); throw DbException.get(ErrorCode.SCALAR_SUBQUERY_CONTAINS_MORE_THAN_ONE_ROW);
...@@ -109,7 +109,7 @@ public class Subquery extends Expression { ...@@ -109,7 +109,7 @@ public class Subquery extends Expression {
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
list[i] = expressions.get(i); list[i] = expressions.get(i);
} }
expression = new ExpressionList(list); expression = new ExpressionList(list, false);
} }
} }
return expression; return expression;
......
...@@ -205,6 +205,7 @@ public class Comparison extends Condition { ...@@ -205,6 +205,7 @@ public class Comparison extends Condition {
left = left.optimize(session); left = left.optimize(session);
if (right != null) { if (right != null) {
right = right.optimize(session); right = right.optimize(session);
// TODO check row values too
if (right.getType() == Value.ARRAY && left.getType() != Value.ARRAY) { if (right.getType() == Value.ARRAY && left.getType() != Value.ARRAY) {
throw DbException.get(ErrorCode.COMPARING_ARRAY_TO_SCALAR); throw DbException.get(ErrorCode.COMPARING_ARRAY_TO_SCALAR);
} }
......
...@@ -70,6 +70,7 @@ import org.h2.value.ValueInt; ...@@ -70,6 +70,7 @@ import org.h2.value.ValueInt;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet; import org.h2.value.ValueResultSet;
import org.h2.value.ValueRow;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
...@@ -1038,10 +1039,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -1038,10 +1039,10 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case ARRAY_GET: { case ARRAY_GET: {
if (v0.getType() == Value.ARRAY) { Value[] list = getArray(v0);
if (list != null) {
Value v1 = getNullOrValue(session, args, values, 1); Value v1 = getNullOrValue(session, args, values, 1);
int element = v1.getInt(); int element = v1.getInt();
Value[] list = ((ValueArray) v0).getList();
if (element < 1 || element > list.length) { if (element < 1 || element > list.length) {
result = ValueNull.INSTANCE; result = ValueNull.INSTANCE;
} else { } else {
...@@ -1053,8 +1054,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1053,8 +1054,8 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case ARRAY_LENGTH: { case ARRAY_LENGTH: {
if (v0.getType() == Value.ARRAY) { Value[] list = getArray(v0);
Value[] list = ((ValueArray) v0).getList(); if (list != null) {
result = ValueInt.get(list.length); result = ValueInt.get(list.length);
} else { } else {
result = ValueNull.INSTANCE; result = ValueNull.INSTANCE;
...@@ -1063,9 +1064,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -1063,9 +1064,9 @@ public class Function extends Expression implements FunctionCall {
} }
case ARRAY_CONTAINS: { case ARRAY_CONTAINS: {
result = ValueBoolean.FALSE; result = ValueBoolean.FALSE;
if (v0.getType() == Value.ARRAY) { Value[] list = getArray(v0);
if (list != null) {
Value v1 = getNullOrValue(session, args, values, 1); Value v1 = getNullOrValue(session, args, values, 1);
Value[] list = ((ValueArray) v0).getList();
for (Value v : list) { for (Value v : list) {
if (database.areEqual(v, v1)) { if (database.areEqual(v, v1)) {
result = ValueBoolean.TRUE; result = ValueBoolean.TRUE;
...@@ -1091,6 +1092,19 @@ public class Function extends Expression implements FunctionCall { ...@@ -1091,6 +1092,19 @@ public class Function extends Expression implements FunctionCall {
return result; return result;
} }
private Value[] getArray(Value v0) {
int t = v0.getType();
Value[] list;
if (t == Value.ARRAY) {
list = ((ValueArray) v0).getList();
} else if (t == Value.ROW) {
list = ((ValueRow) v0).getList();
} else {
list = null;
}
return list;
}
private static boolean cancelStatement(Session session, int targetSessionId) { private static boolean cancelStatement(Session session, int targetSessionId) {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
Session[] sessions = session.getDatabase().getSessions(false); Session[] sessions = session.getDatabase().getSessions(false);
......
...@@ -1550,7 +1550,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements ...@@ -1550,7 +1550,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, * ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP,
* DISTINCT, EXCEPT, EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, * DISTINCT, EXCEPT, EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP,
* HAVING, INNER, INTERSECT, INTERSECTS, IS, JOIN, LIKE, LIMIT, LOCALTIME, * HAVING, INNER, INTERSECT, INTERSECTS, IS, JOIN, LIKE, LIMIT, LOCALTIME,
* LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROWNUM, * LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM,
* SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE, * SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
* WINDOW, WITH * WINDOW, WITH
* </pre> * </pre>
......
...@@ -187,10 +187,15 @@ public class ParserUtil { ...@@ -187,10 +187,15 @@ public class ParserUtil {
*/ */
public static final int PRIMARY = ORDER + 1; public static final int PRIMARY = ORDER + 1;
/**
* The token "ROW".
*/
public static final int ROW = PRIMARY + 1;
/** /**
* The token "ROWNUM". * The token "ROWNUM".
*/ */
public static final int ROWNUM = PRIMARY + 1; public static final int ROWNUM = ROW + 1;
/** /**
* The token "SELECT". * The token "SELECT".
...@@ -425,7 +430,9 @@ public class ParserUtil { ...@@ -425,7 +430,9 @@ public class ParserUtil {
} }
return IDENTIFIER; return IDENTIFIER;
case 'R': case 'R':
if (eq("ROWNUM", s, ignoreCase, start, end)) { if (eq("ROW", s, ignoreCase, start, end)) {
return ROW;
} else if (eq("ROWNUM", s, ignoreCase, start, end)) {
return ROWNUM; return ROWNUM;
} }
return IDENTIFIER; return IDENTIFIER;
......
...@@ -773,6 +773,19 @@ public class DataType { ...@@ -773,6 +773,19 @@ public class DataType {
ValueInt.get(value); ValueInt.get(value);
break; break;
} }
case Value.ROW: {
Object[] list = (Object[]) rs.getObject(columnIndex);
if (list == null) {
return ValueNull.INSTANCE;
}
int len = list.length;
Value[] values = new Value[len];
for (int i = 0; i < len; i++) {
values[i] = DataType.convertToValue(session, list[i], Value.NULL);
}
v = ValueRow.get(values);
break;
}
case Value.RESULT_SET: { case Value.RESULT_SET: {
ResultSet x = (ResultSet) rs.getObject(columnIndex); ResultSet x = (ResultSet) rs.getObject(columnIndex);
if (x == null) { if (x == null) {
......
...@@ -471,6 +471,16 @@ public class Transfer { ...@@ -471,6 +471,16 @@ public class Transfer {
} }
break; break;
} }
case Value.ROW: {
ValueRow va = (ValueRow) v;
Value[] list = va.getList();
int len = list.length;
writeInt(len);
for (Value value : list) {
writeValue(value);
}
break;
}
case Value.ENUM: { case Value.ENUM: {
writeInt(v.getInt()); writeInt(v.getInt());
writeString(v.getString()); writeString(v.getString());
...@@ -682,6 +692,14 @@ public class Transfer { ...@@ -682,6 +692,14 @@ public class Transfer {
} }
return ValueArray.get(componentType, list); return ValueArray.get(componentType, list);
} }
case Value.ROW: {
int len = readInt();
Value[] list = new Value[len];
for (int i = 0; i < len; i++) {
list[i] = readValue();
}
return ValueRow.get(list);
}
case Value.RESULT_SET: { case Value.RESULT_SET: {
SimpleResult rs = new SimpleResult(); SimpleResult rs = new SimpleResult();
int columns = readInt(); int columns = readInt();
......
...@@ -241,10 +241,15 @@ public abstract class Value { ...@@ -241,10 +241,15 @@ public abstract class Value {
*/ */
public static final int INTERVAL_MINUTE_TO_SECOND = 38; public static final int INTERVAL_MINUTE_TO_SECOND = 38;
/**
* The value type for ROW values.
*/
public static final int ROW = 39;
/** /**
* The number of value types. * The number of value types.
*/ */
public static final int TYPE_COUNT = INTERVAL_MINUTE_TO_SECOND + 1; public static final int TYPE_COUNT = ROW + 1;
private static SoftReference<Value[]> softCache; private static SoftReference<Value[]> softCache;
...@@ -439,6 +444,8 @@ public abstract class Value { ...@@ -439,6 +444,8 @@ public abstract class Value {
return 44_000; return 44_000;
case ARRAY: case ARRAY:
return 50_000; return 50_000;
case ROW:
return 50_500;
case RESULT_SET: case RESULT_SET:
return 51_000; return 51_000;
case ENUM: case ENUM:
...@@ -790,6 +797,8 @@ public abstract class Value { ...@@ -790,6 +797,8 @@ public abstract class Value {
return convertToIntervalDayTime(targetType); return convertToIntervalDayTime(targetType);
case ARRAY: case ARRAY:
return convertToArray(); return convertToArray();
case ROW:
return convertToRow();
case RESULT_SET: case RESULT_SET:
return convertToResultSet(); return convertToResultSet();
default: default:
...@@ -1298,7 +1307,37 @@ public abstract class Value { ...@@ -1298,7 +1307,37 @@ public abstract class Value {
} }
private ValueArray convertToArray() { private ValueArray convertToArray() {
return ValueArray.get(new Value[] { ValueString.get(getString()) }); Value[] a;
switch (getType()) {
case ROW:
a = ((ValueRow) this).getList();
break;
case BLOB:
case CLOB:
case RESULT_SET:
a = new Value[] { ValueString.get(getString()) };
break;
default:
a = new Value[] { this };
}
return ValueArray.get(a);
}
private ValueRow convertToRow() {
Value[] a;
switch (getType()) {
case ARRAY:
a = ((ValueArray) this).getList();
break;
case BLOB:
case CLOB:
case RESULT_SET:
a = new Value[] { ValueString.get(getString()) };
break;
default:
a = new Value[] { this };
}
return ValueRow.get(a);
} }
private ValueResultSet convertToResultSet() { private ValueResultSet convertToResultSet() {
......
...@@ -13,7 +13,6 @@ import java.util.Arrays; ...@@ -13,7 +13,6 @@ import java.util.Arrays;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.StatementBuilder;
/** /**
* Implementation of the ARRAY data type. * Implementation of the ARRAY data type.
...@@ -103,12 +102,14 @@ public class ValueArray extends Value { ...@@ -103,12 +102,14 @@ public class ValueArray extends Value {
@Override @Override
public String getString() { public String getString() {
StatementBuilder buff = new StatementBuilder("("); StringBuilder builder = new StringBuilder().append('[');
for (Value v : values) { for (int i = 0; i < values.length; i++) {
buff.appendExceptFirst(", "); if (i > 0) {
buff.append(v.getString()); builder.append(", ");
}
builder.append(values[i].getString());
} }
return buff.append(')').toString(); return builder.append(']').toString();
} }
@Override @Override
...@@ -156,7 +157,7 @@ public class ValueArray extends Value { ...@@ -156,7 +157,7 @@ public class ValueArray extends Value {
@Override @Override
public StringBuilder getSQL(StringBuilder builder) { public StringBuilder getSQL(StringBuilder builder) {
builder.append('('); builder.append("ARRAY [");
int length = values.length; int length = values.length;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
if (i > 0) { if (i > 0) {
...@@ -164,20 +165,20 @@ public class ValueArray extends Value { ...@@ -164,20 +165,20 @@ public class ValueArray extends Value {
} }
values[i].getSQL(builder); values[i].getSQL(builder);
} }
if (length == 1) { return builder.append(']');
builder.append(',');
}
return builder.append(')');
} }
@Override @Override
public String getTraceSQL() { public String getTraceSQL() {
StatementBuilder buff = new StatementBuilder("("); StringBuilder builder = new StringBuilder("[");
for (Value v : values) { for (int i = 0; i < values.length; i++) {
buff.appendExceptFirst(", "); if (i > 0) {
buff.append(v == null ? "null" : v.getTraceSQL()); builder.append(", ");
}
Value v = values[i];
builder.append(v == null ? "null" : v.getTraceSQL());
} }
return buff.append(')').toString(); return builder.append(']').toString();
} }
@Override @Override
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.value;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import org.h2.api.ErrorCode;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.util.MathUtils;
/**
* Row value.
*/
public class ValueRow extends Value {
/**
* Empty row.
*/
private static final Object EMPTY = get(new Value[0]);
private final Value[] values;
private int hash;
private ValueRow(Value[] list) {
this.values = list;
}
/**
* Get or create a row value for the given value array.
* Do not clone the data.
*
* @param list the value array
* @return the value
*/
public static ValueRow get(Value[] list) {
return new ValueRow(list);
}
/**
* Returns empty row.
*
* @return empty row
*/
public static ValueRow getEmpty() {
return (ValueRow) EMPTY;
}
@Override
public int hashCode() {
if (hash != 0) {
return hash;
}
int h = 1;
for (Value v : values) {
h = h * 31 + v.hashCode();
}
hash = h;
return h;
}
public Value[] getList() {
return values;
}
@Override
public int getType() {
return Value.ROW;
}
@Override
public long getPrecision() {
long p = 0;
for (Value v : values) {
p += v.getPrecision();
}
return p;
}
@Override
public String getString() {
StringBuilder builder = new StringBuilder("ROW (");
for (int i = 0; i < values.length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(values[i].getString());
}
return builder.append(')').toString();
}
@Override
public int compareTypeSafe(Value o, CompareMode mode) {
ValueRow v = (ValueRow) o;
if (values == v.values) {
return 0;
}
int len = values.length;
if (len != v.values.length) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
}
for (int i = 0; i < len; i++) {
Value v1 = values[i];
Value v2 = v.values[i];
int comp = v1.compareTo(v2, /* TODO */ null, mode);
if (comp != 0) {
return comp;
}
}
return 0;
}
@Override
public Object getObject() {
int len = values.length;
Object[] list = new Object[len];
for (int i = 0; i < len; i++) {
final Value value = values[i];
if (!SysProperties.OLD_RESULT_SET_GET_OBJECT) {
final int type = value.getType();
if (type == Value.BYTE || type == Value.SHORT) {
list[i] = value.getInt();
continue;
}
}
list[i] = value.getObject();
}
return list;
}
@Override
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
throw getUnsupportedExceptionForOperation("PreparedStatement.set");
}
@Override
public StringBuilder getSQL(StringBuilder builder) {
builder.append("ROW (");
int length = values.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(", ");
}
values[i].getSQL(builder);
}
return builder.append(')');
}
@Override
public String getTraceSQL() {
StringBuilder builder = new StringBuilder("ROW (");
for (int i = 0; i < values.length; i++) {
if (i > 0) {
builder.append(", ");
}
Value v = values[i];
builder.append(v == null ? "null" : v.getTraceSQL());
}
return builder.append(')').toString();
}
@Override
public int getDisplaySize() {
long size = 0;
for (Value v : values) {
size += v.getDisplaySize();
}
return MathUtils.convertLongToInt(size);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ValueRow)) {
return false;
}
ValueRow v = (ValueRow) other;
if (values == v.values) {
return true;
}
int len = values.length;
if (len != v.values.length) {
return false;
}
for (int i = 0; i < len; i++) {
if (!values[i].equals(v.values[i])) {
return false;
}
}
return true;
}
@Override
public int getMemory() {
int memory = 32;
for (Value v : values) {
memory += v.getMemory() + Constants.MEMORY_POINTER;
}
return memory;
}
@Override
public Value convertPrecision(long precision, boolean force) {
if (!force) {
return this;
}
int length = values.length;
Value[] newValues = new Value[length];
int i = 0;
boolean modified = false;
for (; i < length; i++) {
Value old = values[i];
Value v = old.convertPrecision(precision, true);
if (v != old) {
modified = true;
}
// empty byte arrays or strings have precision 0
// they count as precision 1 here
precision -= Math.max(1, v.getPrecision());
if (precision < 0) {
break;
}
newValues[i] = v;
}
if (i < length) {
return get(Arrays.copyOf(newValues, i));
}
return modified ? get(newValues) : this;
}
}
...@@ -157,8 +157,8 @@ public class TestFullText extends TestDb { ...@@ -157,8 +157,8 @@ public class TestFullText extends TestDb {
assertEquals("KEYS", rs.getMetaData().getColumnLabel(4)); assertEquals("KEYS", rs.getMetaData().getColumnLabel(4));
assertEquals("PUBLIC", rs.getString(1)); assertEquals("PUBLIC", rs.getString(1));
assertEquals("TEST", rs.getString(2)); assertEquals("TEST", rs.getString(2));
assertEquals("(ID)", rs.getString(3)); assertEquals("[ID]", rs.getString(3));
assertEquals("(1)", rs.getString(4)); assertEquals("[1]", rs.getString(4));
rs = stat.executeQuery("SELECT * FROM FT_SEARCH('this', 0, 0)"); rs = stat.executeQuery("SELECT * FROM FT_SEARCH('this', 0, 0)");
assertFalse(rs.next()); assertFalse(rs.next());
......
...@@ -1860,7 +1860,7 @@ public class TestResultSet extends TestDb { ...@@ -1860,7 +1860,7 @@ public class TestResultSet extends TestDb {
assertEquals(Types.NULL, array.getBaseType()); assertEquals(Types.NULL, array.getBaseType());
assertEquals("NULL", array.getBaseTypeName()); assertEquals("NULL", array.getBaseTypeName());
assertTrue(array.toString().endsWith(": (11, 12)")); assertTrue(array.toString().endsWith(": [11, 12]"));
// free // free
array.free(); array.free();
......
...@@ -144,7 +144,7 @@ public class TestScript extends TestDb { ...@@ -144,7 +144,7 @@ public class TestScript extends TestDb {
for (String s : new String[] { "array", "bigint", "binary", "blob", for (String s : new String[] { "array", "bigint", "binary", "blob",
"boolean", "char", "clob", "date", "decimal", decimal2, "double", "enum", "boolean", "char", "clob", "date", "decimal", decimal2, "double", "enum",
"geometry", "identity", "int", "interval", "other", "real", "smallint", "geometry", "identity", "int", "interval", "other", "real", "row", "smallint",
"time", "timestamp-with-timezone", "timestamp", "tinyint", "time", "timestamp-with-timezone", "timestamp", "tinyint",
"uuid", "varchar", "varchar-ignorecase" }) { "uuid", "varchar", "varchar-ignorecase" }) {
testScript("datatypes/" + s + ".sql"); testScript("datatypes/" + s + ".sql");
......
...@@ -16,10 +16,10 @@ SELECT (10, 20, 30)[4]; ...@@ -16,10 +16,10 @@ SELECT (10, 20, 30)[4];
>> null >> null
SELECT ARRAY[]; SELECT ARRAY[];
>> () >> []
SELECT ARRAY[10]; SELECT ARRAY[10];
>> (10) >> [10]
SELECT ARRAY[10, 20, 30]; SELECT ARRAY[10, 20, 30];
>> (10, 20, 30) >> [10, 20, 30]
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
SELECT ROW (10);
>> ROW (10)
SELECT (10, 20, 30);
>> ROW (10, 20, 30)
...@@ -6,9 +6,15 @@ ...@@ -6,9 +6,15 @@
CREATE TABLE test (id INT NOT NULL, name VARCHAR); CREATE TABLE test (id INT NOT NULL, name VARCHAR);
> ok > ok
select * from test where id = (1, 2); select * from test where id = ARRAY [1, 2];
> exception COMPARING_ARRAY_TO_SCALAR > exception COMPARING_ARRAY_TO_SCALAR
insert into test values (1, 't');
> update count: 1
select * from test where id = (1, 2);
> exception COLUMN_COUNT_DOES_NOT_MATCH
drop table test; drop table test;
> ok > ok
......
...@@ -6,18 +6,18 @@ ...@@ -6,18 +6,18 @@
SELECT HISTOGRAM(X), HISTOGRAM(DISTINCT X) FROM VALUES (1), (2), (3), (1), (2), (NULL), (5) T(X); SELECT HISTOGRAM(X), HISTOGRAM(DISTINCT X) FROM VALUES (1), (2), (3), (1), (2), (NULL), (5) T(X);
> HISTOGRAM(C1) HISTOGRAM(DISTINCT C1) > HISTOGRAM(C1) HISTOGRAM(DISTINCT C1)
> ------------------------------------------- ------------------------------------------- > ------------------------------------------- -------------------------------------------
> ((null, 1), (1, 2), (2, 2), (3, 1), (5, 1)) ((null, 1), (1, 1), (2, 1), (3, 1), (5, 1)) > [[null, 1], [1, 2], [2, 2], [3, 1], [5, 1]] [[null, 1], [1, 1], [2, 1], [3, 1], [5, 1]]
> rows: 1 > rows: 1
SELECT HISTOGRAM(X) FILTER (WHERE X > 1), HISTOGRAM(DISTINCT X) FILTER (WHERE X > 1) SELECT HISTOGRAM(X) FILTER (WHERE X > 1), HISTOGRAM(DISTINCT X) FILTER (WHERE X > 1)
FROM VALUES (1), (2), (3), (1), (2), (NULL), (5) T(X); FROM VALUES (1), (2), (3), (1), (2), (NULL), (5) T(X);
> HISTOGRAM(C1) FILTER (WHERE (C1 > 1)) HISTOGRAM(DISTINCT C1) FILTER (WHERE (C1 > 1)) > HISTOGRAM(C1) FILTER (WHERE (C1 > 1)) HISTOGRAM(DISTINCT C1) FILTER (WHERE (C1 > 1))
> ------------------------------------- ---------------------------------------------- > ------------------------------------- ----------------------------------------------
> ((2, 2), (3, 1), (5, 1)) ((2, 1), (3, 1), (5, 1)) > [[2, 2], [3, 1], [5, 1]] [[2, 1], [3, 1], [5, 1]]
> rows: 1 > rows: 1
SELECT HISTOGRAM(X) FILTER (WHERE X > 0), HISTOGRAM(DISTINCT X) FILTER (WHERE X > 0) FROM VALUES (0) T(X); SELECT HISTOGRAM(X) FILTER (WHERE X > 0), HISTOGRAM(DISTINCT X) FILTER (WHERE X > 0) FROM VALUES (0) T(X);
> HISTOGRAM(C1) FILTER (WHERE (C1 > 0)) HISTOGRAM(DISTINCT C1) FILTER (WHERE (C1 > 0)) > HISTOGRAM(C1) FILTER (WHERE (C1 > 0)) HISTOGRAM(DISTINCT C1) FILTER (WHERE (C1 > 0))
> ------------------------------------- ---------------------------------------------- > ------------------------------------- ----------------------------------------------
> () () > [] []
> rows: 1 > rows: 1
...@@ -32,7 +32,7 @@ drop table test; ...@@ -32,7 +32,7 @@ drop table test;
> ok > ok
explain select * from table(id int = (1, 2), name varchar=('Hello', 'World')); explain select * from table(id int = (1, 2), name varchar=('Hello', 'World'));
>> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=(1, 2), NAME VARCHAR=('Hello', 'World')) /* function */ >> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=ROW (1, 2), NAME VARCHAR=ROW ('Hello', 'World')) /* function */
select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by id; select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by id;
> ID NAME > ID NAME
......
...@@ -36,10 +36,10 @@ SELECT * FROM UNNEST(ARRAY[1], ARRAY[2, 3, 4], ARRAY[5, 6]) WITH ORDINALITY; ...@@ -36,10 +36,10 @@ SELECT * FROM UNNEST(ARRAY[1], ARRAY[2, 3, 4], ARRAY[5, 6]) WITH ORDINALITY;
> rows: 3 > rows: 3
EXPLAIN SELECT * FROM UNNEST(ARRAY[1]); EXPLAIN SELECT * FROM UNNEST(ARRAY[1]);
>> SELECT UNNEST.C1 FROM UNNEST((1,)) /* function */ >> SELECT UNNEST.C1 FROM UNNEST(ARRAY [1]) /* function */
EXPLAIN SELECT * FROM UNNEST(ARRAY[1]) WITH ORDINALITY; EXPLAIN SELECT * FROM UNNEST(ARRAY[1]) WITH ORDINALITY;
>> SELECT UNNEST.C1, UNNEST.NORD FROM UNNEST((1,)) WITH ORDINALITY /* function */ >> SELECT UNNEST.C1, UNNEST.NORD FROM UNNEST(ARRAY [1]) WITH ORDINALITY /* function */
SELECT 1 IN(UNNEST(ARRAY[1, 2, 3])); SELECT 1 IN(UNNEST(ARRAY[1, 2, 3]));
>> TRUE >> TRUE
...@@ -80,8 +80,8 @@ INSERT INTO TEST VALUES (2, ARRAY[2, 4]), (3, ARRAY[2, 5]); ...@@ -80,8 +80,8 @@ INSERT INTO TEST VALUES (2, ARRAY[2, 4]), (3, ARRAY[2, 5]);
SELECT A, B, A IN(UNNEST(B)) FROM TEST; SELECT A, B, A IN(UNNEST(B)) FROM TEST;
> A B A IN(UNNEST(B)) > A B A IN(UNNEST(B))
> - ------ --------------- > - ------ ---------------
> 2 (2, 4) TRUE > 2 [2, 4] TRUE
> 3 (2, 5) FALSE > 3 [2, 5] FALSE
> rows: 2 > rows: 2
DROP TABLE TEST; DROP TABLE TEST;
......
...@@ -366,14 +366,14 @@ explain select -cast(0 as real), -cast(0 as double); ...@@ -366,14 +366,14 @@ explain select -cast(0 as real), -cast(0 as double);
select () empty; select () empty;
> EMPTY > EMPTY
> ----- > ------
> () > ROW ()
> rows: 1 > rows: 1
select (1,) one_element; select (1,) one_element;
> ONE_ELEMENT > ONE_ELEMENT
> ----------- > -----------
> (1) > ROW (1)
> rows: 1 > rows: 1
select (1) one; select (1) one;
...@@ -1401,9 +1401,9 @@ insert into test values(1, (1, 1)), (2, (1, 2)), (3, (1, 1, 1)); ...@@ -1401,9 +1401,9 @@ insert into test values(1, (1, 1)), (2, (1, 2)), (3, (1, 1, 1));
select * from test order by data; select * from test order by data;
> ID DATA > ID DATA
> -- --------- > -- ---------
> 1 (1, 1) > 1 [1, 1]
> 3 (1, 1, 1) > 3 [1, 1, 1]
> 2 (1, 2) > 2 [1, 2]
> rows (ordered): 3 > rows (ordered): 3
drop table test; drop table test;
...@@ -2003,9 +2003,9 @@ drop table people, cars; ...@@ -2003,9 +2003,9 @@ drop table people, cars;
> ok > ok
select (1, 2); select (1, 2);
> 1, 2 > ROW (1, 2)
> ------ > ----------
> (1, 2) > ROW (1, 2)
> rows: 1 > rows: 1
create table array_test(x array); create table array_test(x array);
...@@ -2017,7 +2017,7 @@ insert into array_test values((1, 2, 3)), ((2, 3, 4)); ...@@ -2017,7 +2017,7 @@ insert into array_test values((1, 2, 3)), ((2, 3, 4));
select * from array_test where x = (1, 2, 3); select * from array_test where x = (1, 2, 3);
> X > X
> --------- > ---------
> (1, 2, 3) > [1, 2, 3]
> rows: 1 > rows: 1
drop table array_test; drop table array_test;
...@@ -3177,7 +3177,7 @@ drop table test; ...@@ -3177,7 +3177,7 @@ drop table test;
call select 1.0/3.0*3.0, 100.0/2.0, -25.0/100.0, 0.0/3.0, 6.9/2.0, 0.72179425150347250912311550800000 / 5314251955.21; call select 1.0/3.0*3.0, 100.0/2.0, -25.0/100.0, 0.0/3.0, 6.9/2.0, 0.72179425150347250912311550800000 / 5314251955.21;
> SELECT 0.999999999999999999999999990, 50, -0.25, 0, 3.45, 1.35822361752313607260107721120531135706133161972E-10 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */ /* scanCount: 2 */ > SELECT 0.999999999999999999999999990, 50, -0.25, 0, 3.45, 1.35822361752313607260107721120531135706133161972E-10 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */ /* scanCount: 2 */
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> (0.999999999999999999999999990, 50, -0.25, 0, 3.45, 1.35822361752313607260107721120531135706133161972E-10) > ROW (0.999999999999999999999999990, 50, -0.25, 0, 3.45, 1.35822361752313607260107721120531135706133161972E-10)
> rows: 1 > rows: 1
call (select x from dual where x is null); call (select x from dual where x is null);
...@@ -3254,9 +3254,12 @@ select count(*) from test where id in ((select id from test)); ...@@ -3254,9 +3254,12 @@ select count(*) from test where id in ((select id from test));
select count(*) from test where id = ((select id from test)); select count(*) from test where id = ((select id from test));
> exception SCALAR_SUBQUERY_CONTAINS_MORE_THAN_ONE_ROW > exception SCALAR_SUBQUERY_CONTAINS_MORE_THAN_ONE_ROW
select count(*) from test where id = ((select id from test), 1); select count(*) from test where id = ARRAY [(select id from test), 1];
> exception COMPARING_ARRAY_TO_SCALAR > exception COMPARING_ARRAY_TO_SCALAR
select count(*) from test where id = ((select id from test fetch first row only), 1);
> exception COLUMN_COUNT_DOES_NOT_MATCH
select (select id from test where 1=0) from test; select (select id from test where 1=0) from test;
> SELECT ID FROM PUBLIC.TEST /* PUBLIC.TEST.tableScan: FALSE */ WHERE FALSE > SELECT ID FROM PUBLIC.TEST /* PUBLIC.TEST.tableScan: FALSE */ WHERE FALSE
> ------------------------------------------------------------------------- > -------------------------------------------------------------------------
...@@ -4315,8 +4318,8 @@ update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id ...@@ -4315,8 +4318,8 @@ update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id
> update count: 2 > update count: 2
explain update test set (id, name)=(id+1, name || 'Hi'); explain update test set (id, name)=(id+1, name || 'Hi');
#+mvStore#>> UPDATE PUBLIC.TEST /* PUBLIC.TEST.tableScan */ SET ID = ARRAY_GET(((ID + 1), (NAME || 'Hi')), 1), NAME = ARRAY_GET(((ID + 1), (NAME || 'Hi')), 2) #+mvStore#>> UPDATE PUBLIC.TEST /* PUBLIC.TEST.tableScan */ SET ID = ARRAY_GET(ROW ((ID + 1), (NAME || 'Hi')), 1), NAME = ARRAY_GET(ROW ((ID + 1), (NAME || 'Hi')), 2)
#-mvStore#>> UPDATE PUBLIC.TEST /* PUBLIC.PRIMARY_KEY_2 */ SET ID = ARRAY_GET(((ID + 1), (NAME || 'Hi')), 1), NAME = ARRAY_GET(((ID + 1), (NAME || 'Hi')), 2) #-mvStore#>> UPDATE PUBLIC.TEST /* PUBLIC.PRIMARY_KEY_2 */ SET ID = ARRAY_GET(ROW ((ID + 1), (NAME || 'Hi')), 1), NAME = ARRAY_GET(ROW ((ID + 1), (NAME || 'Hi')), 2)
explain update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id=t1.id); explain update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id=t1.id);
#+mvStore#>> UPDATE PUBLIC.TEST /* PUBLIC.TEST.tableScan */ SET ID = ARRAY_GET((SELECT (ID + 1), (NAME || 'Ho') FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_2: ID = TEST.ID */ WHERE TEST.ID = T1.ID), 1), NAME = ARRAY_GET((SELECT (ID + 1), (NAME || 'Ho') FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_2: ID = TEST.ID */ WHERE TEST.ID = T1.ID), 2) #+mvStore#>> UPDATE PUBLIC.TEST /* PUBLIC.TEST.tableScan */ SET ID = ARRAY_GET((SELECT (ID + 1), (NAME || 'Ho') FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_2: ID = TEST.ID */ WHERE TEST.ID = T1.ID), 1), NAME = ARRAY_GET((SELECT (ID + 1), (NAME || 'Ho') FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_2: ID = TEST.ID */ WHERE TEST.ID = T1.ID), 2)
......
...@@ -170,7 +170,7 @@ public class TestValue extends TestDb { ...@@ -170,7 +170,7 @@ public class TestValue extends TestDb {
assertEquals(5, v.convertPrecision(5, true).getPrecision()); assertEquals(5, v.convertPrecision(5, true).getPrecision());
v = ValueArray.get(new Value[]{ValueString.get(""), ValueString.get("")}); v = ValueArray.get(new Value[]{ValueString.get(""), ValueString.get("")});
assertEquals(0, v.getPrecision()); assertEquals(0, v.getPrecision());
assertEquals("('')", v.convertPrecision(1, true).toString()); assertEquals("['']", v.convertPrecision(1, true).toString());
v = ValueBytes.get(spaces.getBytes()); v = ValueBytes.get(spaces.getBytes());
assertEquals(100, v.getPrecision()); assertEquals(100, v.getPrecision());
......
...@@ -43,6 +43,7 @@ import org.h2.value.ValueJavaObject; ...@@ -43,6 +43,7 @@ import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet; import org.h2.value.ValueResultSet;
import org.h2.value.ValueRow;
import org.h2.value.ValueShort; import org.h2.value.ValueShort;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueStringFixed; import org.h2.value.ValueStringFixed;
...@@ -208,14 +209,10 @@ public class TestValueMemory extends TestBase implements DataHandler { ...@@ -208,14 +209,10 @@ public class TestValueMemory extends TestBase implements DataHandler {
String s = randomString(len); String s = randomString(len);
return getLobStorage().createClob(new StringReader(s), len); return getLobStorage().createClob(new StringReader(s), len);
} }
case Value.ARRAY: { case Value.ARRAY:
int len = random.nextInt(20); return ValueArray.get(createArray());
Value[] list = new Value[len]; case Value.ROW:
for (int i = 0; i < list.length; i++) { return ValueRow.get(createArray());
list[i] = create(Value.STRING);
}
return ValueArray.get(list);
}
case Value.RESULT_SET: case Value.RESULT_SET:
return ValueResultSet.get(new SimpleResult()); return ValueResultSet.get(new SimpleResult());
case Value.JAVA_OBJECT: case Value.JAVA_OBJECT:
...@@ -254,6 +251,15 @@ public class TestValueMemory extends TestBase implements DataHandler { ...@@ -254,6 +251,15 @@ public class TestValueMemory extends TestBase implements DataHandler {
} }
} }
private Value[] createArray() throws SQLException {
int len = random.nextInt(20);
Value[] list = new Value[len];
for (int i = 0; i < list.length; i++) {
list[i] = create(Value.STRING);
}
return list;
}
private byte[] randomBytes(int len) { private byte[] randomBytes(int len) {
byte[] data = new byte[len]; byte[] data = new byte[len];
if (random.nextBoolean()) { if (random.nextBoolean()) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论