Unverified 提交 eeace0e1 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1610 from katzyn/row

Separate array and row value expressions
......@@ -2023,23 +2023,12 @@ ID=1 AND NAME='Hi'
"Other Grammar","Array","
ARRAY '[' [ expression, [,...] ] ']'
| ( [ expression, [ expression [,...] ] ] )
","
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]
ARRAY[]
(1, 2)
(1, )
()
"
"Other Grammar","Boolean","
......@@ -2520,6 +2509,16 @@ LZF is faster but uses more space.
COMPRESSION LZF
"
"Other Grammar","Row value expression","
ROW (expression, [,...])
| ( [ expression, expression [,...] ] )
","
A row value expression.
","
ROW (1)
(1, 2)
"
"Other Grammar","Select Expression","
wildcardExpression | expression [ [ AS ] columnAlias ]
","
......
......@@ -475,11 +475,14 @@ There is a list of keywords that can't be used as identifiers (table names, colu
unless they are quoted (surrounded with double quotes). The list is currently:
</p><p>
<code>
ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DISTINCT, EXCEPT,
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,
PRIMARY, ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
WINDOW, WITH
ALL, ARRAY, CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE,
CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, DISTINCT, EXCEPT,
EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING,
IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE,
LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL,
OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE,
SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, VALUES,
WHERE, WINDOW, WITH
</code>
</p><p>
Certain words of this list are keywords because they are functions that can be used without '()',
......
......@@ -11,17 +11,20 @@ import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueRow;
/**
* 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 {
private final Expression[] list;
private final boolean isArray;
public ExpressionList(Expression[] list) {
public ExpressionList(Expression[] list, boolean isArray) {
this.list = list;
this.isArray = isArray;
}
@Override
......@@ -30,12 +33,12 @@ public class ExpressionList extends Expression {
for (int i = 0; i < list.length; i++) {
v[i] = list[i].getValue(session);
}
return ValueArray.get(v);
return isArray ? ValueArray.get(v) : ValueRow.get(v);
}
@Override
public int getType() {
return Value.ARRAY;
return isArray ? Value.ARRAY : Value.ROW;
}
@Override
......@@ -85,12 +88,9 @@ public class ExpressionList extends Expression {
@Override
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
builder.append(isArray ? "ARRAY [" : "ROW (");
writeExpressions(builder, list);
if (list.length == 1) {
builder.append(',');
}
return builder.append(')');
return builder.append(isArray ? ']' : ')');
}
@Override
......
......@@ -14,8 +14,8 @@ import org.h2.result.ResultInterface;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueNull;
import org.h2.value.ValueRow;
/**
* A query returning a single value.
......@@ -42,7 +42,7 @@ public class Subquery extends Expression {
if (result.getVisibleColumnCount() == 1) {
v = values[0];
} else {
v = ValueArray.get(values);
v = ValueRow.get(values);
}
if (result.hasNext()) {
throw DbException.get(ErrorCode.SCALAR_SUBQUERY_CONTAINS_MORE_THAN_ONE_ROW);
......@@ -109,7 +109,7 @@ public class Subquery extends Expression {
for (int i = 0; i < columnCount; i++) {
list[i] = expressions.get(i);
}
expression = new ExpressionList(list);
expression = new ExpressionList(list, false);
}
}
return expression;
......
......@@ -205,6 +205,7 @@ public class Comparison extends Condition {
left = left.optimize(session);
if (right != null) {
right = right.optimize(session);
// TODO check row values too
if (right.getType() == Value.ARRAY && left.getType() != Value.ARRAY) {
throw DbException.get(ErrorCode.COMPARING_ARRAY_TO_SCALAR);
}
......
......@@ -70,6 +70,7 @@ import org.h2.value.ValueInt;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
import org.h2.value.ValueRow;
import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
......@@ -1038,10 +1039,10 @@ public class Function extends Expression implements FunctionCall {
break;
}
case ARRAY_GET: {
if (v0.getType() == Value.ARRAY) {
Value[] list = getArray(v0);
if (list != null) {
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 {
......@@ -1053,8 +1054,8 @@ public class Function extends Expression implements FunctionCall {
break;
}
case ARRAY_LENGTH: {
if (v0.getType() == Value.ARRAY) {
Value[] list = ((ValueArray) v0).getList();
Value[] list = getArray(v0);
if (list != null) {
result = ValueInt.get(list.length);
} else {
result = ValueNull.INSTANCE;
......@@ -1063,9 +1064,9 @@ public class Function extends Expression implements FunctionCall {
}
case ARRAY_CONTAINS: {
result = ValueBoolean.FALSE;
if (v0.getType() == Value.ARRAY) {
Value[] list = getArray(v0);
if (list != null) {
Value v1 = getNullOrValue(session, args, values, 1);
Value[] list = ((ValueArray) v0).getList();
for (Value v : list) {
if (database.areEqual(v, v1)) {
result = ValueBoolean.TRUE;
......@@ -1091,6 +1092,19 @@ public class Function extends Expression implements FunctionCall {
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) {
session.getUser().checkAdmin();
Session[] sessions = session.getDatabase().getSessions(false);
......
......@@ -1547,12 +1547,14 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* </pre>
* The complete list of keywords (including SQL-2003 keywords) is:
* <pre>
* ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP,
* DISTINCT, EXCEPT, 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, PRIMARY, ROWNUM,
* SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
* WINDOW, WITH
* ALL, ARRAY, CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE,
* CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, DISTINCT, EXCEPT,
* EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING,
* IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE,
* LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL,
* OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE,
* SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, VALUES,
* WHERE, WINDOW, WITH
* </pre>
*
* @return a list of additional the keywords
......@@ -1560,7 +1562,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements
@Override
public String getSQLKeywords() {
debugCodeCall("getSQLKeywords");
return "INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP";
return "IF,INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP";
}
/**
......
......@@ -22,10 +22,20 @@ public class ParserUtil {
*/
public static final int ALL = IDENTIFIER + 1;
/**
* The token "ARRAY".
*/
public static final int ARRAY = ALL + 1;
/**
* The token "CASE".
*/
public static final int CASE = ARRAY + 1;
/**
* The token "CHECK".
*/
public static final int CHECK = ALL + 1;
public static final int CHECK = CASE + 1;
/**
* The token "CONSTRAINT".
......@@ -52,10 +62,15 @@ public class ParserUtil {
*/
public static final int CURRENT_TIMESTAMP = CURRENT_TIME + 1;
/**
* The token "CURRENT_USER".
*/
public static final int CURRENT_USER = CURRENT_TIMESTAMP + 1;
/**
* The token "DISTINCT".
*/
public static final int DISTINCT = CURRENT_TIMESTAMP + 1;
public static final int DISTINCT = CURRENT_USER + 1;
/**
* The token "EXCEPT".
......@@ -107,20 +122,35 @@ public class ParserUtil {
*/
public static final int HAVING = GROUP + 1;
/**
* The token "IF".
*/
public static final int IF = HAVING + 1;
/**
* The token "INNER".
*/
public static final int INNER = HAVING + 1;
public static final int INNER = IF + 1;
/**
* The token "INTERSECT".
*/
public static final int INTERSECT = INNER + 1;
/**
* The token "INTERSECTS".
*/
public static final int INTERSECTS = INTERSECT + 1;
/**
* The token "INTERVAL".
*/
public static final int INTERVAL = INTERSECTS + 1;
/**
* The token "IS".
*/
public static final int IS = INTERSECT + 1;
public static final int IS = INTERVAL + 1;
/**
* The token "JOIN".
......@@ -187,10 +217,15 @@ public class ParserUtil {
*/
public static final int PRIMARY = ORDER + 1;
/**
* The token "ROW".
*/
public static final int ROW = PRIMARY + 1;
/**
* The token "ROWNUM".
*/
public static final int ROWNUM = PRIMARY + 1;
public static final int ROWNUM = ROW + 1;
/**
* The token "SELECT".
......@@ -212,10 +247,15 @@ public class ParserUtil {
*/
public static final int UNIQUE = UNION + 1;
/**
* The token "VALUES".
*/
public static final int VALUES = UNIQUE + 1;
/**
* The token "WHERE".
*/
public static final int WHERE = UNIQUE + 1;
public static final int WHERE = VALUES + 1;
/**
* The token "WINDOW".
......@@ -312,10 +352,14 @@ public class ParserUtil {
case 'A':
if (eq("ALL", s, ignoreCase, start, end)) {
return ALL;
} else if (eq("ARRAY", s, ignoreCase, start, end)) {
return ARRAY;
}
return IDENTIFIER;
case 'C':
if (eq("CHECK", s, ignoreCase, start, end)) {
if (eq("CASE", s, ignoreCase, start, end)) {
return CASE;
} else if (eq("CHECK", s, ignoreCase, start, end)) {
return CHECK;
} else if (eq("CONSTRAINT", s, ignoreCase, start, end)) {
return CONSTRAINT;
......@@ -327,6 +371,8 @@ public class ParserUtil {
return CURRENT_TIME;
} else if (eq("CURRENT_TIMESTAMP", s, ignoreCase, start, end)) {
return CURRENT_TIMESTAMP;
} else if (eq("CURRENT_USER", s, ignoreCase, start, end)) {
return CURRENT_USER;
}
return IDENTIFIER;
case 'D':
......@@ -367,18 +413,19 @@ public class ParserUtil {
}
return IDENTIFIER;
case 'I':
if (eq("INNER", s, ignoreCase, start, end)) {
if (eq("IF", s, ignoreCase, start, end)) {
return IF;
} else if (eq("INNER", s, ignoreCase, start, end)) {
return INNER;
} else if (eq("INTERSECT", s, ignoreCase, start, end)) {
return INTERSECT;
} else if (eq("INTERSECTS", s, ignoreCase, start, end)) {
return INTERSECTS;
} else if (eq("INTERVAL", s, ignoreCase, start, end)) {
return INTERVAL;
} else if (eq("IS", s, ignoreCase, start, end)) {
return IS;
}
if (additionalKeywords) {
if (eq("INTERSECTS", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'J':
if (eq("JOIN", s, ignoreCase, start, end)) {
......@@ -425,7 +472,9 @@ public class ParserUtil {
}
return IDENTIFIER;
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 IDENTIFIER;
......@@ -457,6 +506,11 @@ public class ParserUtil {
return UNION;
}
return IDENTIFIER;
case 'V':
if (eq("VALUES", s, ignoreCase, start, end)) {
return VALUES;
}
return IDENTIFIER;
case 'W':
if (eq("WHERE", s, ignoreCase, start, end)) {
return WHERE;
......
......@@ -773,6 +773,19 @@ public class DataType {
ValueInt.get(value);
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: {
ResultSet x = (ResultSet) rs.getObject(columnIndex);
if (x == null) {
......
......@@ -322,27 +322,32 @@ public class Transfer {
*/
public void writeValue(Value v) throws IOException {
int type = v.getType();
writeInt(type);
switch (type) {
case Value.NULL:
writeInt(Value.NULL);
break;
case Value.BYTES:
case Value.JAVA_OBJECT:
writeInt(type);
writeBytes(v.getBytesNoCopy());
break;
case Value.UUID: {
writeInt(Value.UUID);
ValueUuid uuid = (ValueUuid) v;
writeLong(uuid.getHigh());
writeLong(uuid.getLow());
break;
}
case Value.BOOLEAN:
writeInt(Value.BOOLEAN);
writeBoolean(v.getBoolean());
break;
case Value.BYTE:
writeInt(Value.BYTE);
writeByte(v.getByte());
break;
case Value.TIME:
writeInt(Value.TIME);
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
writeLong(((ValueTime) v).getNanos());
} else {
......@@ -350,6 +355,7 @@ public class Transfer {
}
break;
case Value.DATE:
writeInt(Value.DATE);
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
writeLong(((ValueDate) v).getDateValue());
} else {
......@@ -357,6 +363,7 @@ public class Transfer {
}
break;
case Value.TIMESTAMP: {
writeInt(Value.TIMESTAMP);
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
ValueTimestamp ts = (ValueTimestamp) v;
writeLong(ts.getDateValue());
......@@ -369,6 +376,7 @@ public class Transfer {
break;
}
case Value.TIMESTAMP_TZ: {
writeInt(Value.TIMESTAMP_TZ);
ValueTimestampTimeZone ts = (ValueTimestampTimeZone) v;
writeLong(ts.getDateValue());
writeLong(ts.getTimeNanos());
......@@ -376,29 +384,37 @@ public class Transfer {
break;
}
case Value.DECIMAL:
writeInt(Value.DECIMAL);
writeString(v.getString());
break;
case Value.DOUBLE:
writeInt(Value.DOUBLE);
writeDouble(v.getDouble());
break;
case Value.FLOAT:
writeInt(Value.FLOAT);
writeFloat(v.getFloat());
break;
case Value.INT:
writeInt(Value.INT);
writeInt(v.getInt());
break;
case Value.LONG:
writeInt(Value.LONG);
writeLong(v.getLong());
break;
case Value.SHORT:
writeInt(Value.SHORT);
writeInt(v.getShort());
break;
case Value.STRING:
case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
writeInt(type);
writeString(v.getString());
break;
case Value.BLOB: {
writeInt(Value.BLOB);
if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
if (v instanceof ValueLobDb) {
ValueLobDb lob = (ValueLobDb) v;
......@@ -429,6 +445,7 @@ public class Transfer {
break;
}
case Value.CLOB: {
writeInt(Value.CLOB);
if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
if (v instanceof ValueLobDb) {
ValueLobDb lob = (ValueLobDb) v;
......@@ -456,6 +473,7 @@ public class Transfer {
break;
}
case Value.ARRAY: {
writeInt(Value.ARRAY);
ValueArray va = (ValueArray) v;
Value[] list = va.getList();
int len = list.length;
......@@ -471,12 +489,25 @@ public class Transfer {
}
break;
}
case Value.ROW: {
writeInt(version >= Constants.TCP_PROTOCOL_VERSION_18 ? Value.ROW : Value.ARRAY);
ValueRow va = (ValueRow) v;
Value[] list = va.getList();
int len = list.length;
writeInt(len);
for (Value value : list) {
writeValue(value);
}
break;
}
case Value.ENUM: {
writeInt(Value.ENUM);
writeInt(v.getInt());
writeString(v.getString());
break;
}
case Value.RESULT_SET: {
writeInt(Value.RESULT_SET);
ResultInterface result = ((ValueResultSet) v).getResult();
int columnCount = result.getVisibleColumnCount();
writeInt(columnCount);
......@@ -506,6 +537,7 @@ public class Transfer {
break;
}
case Value.GEOMETRY:
writeInt(Value.GEOMETRY);
if (version >= Constants.TCP_PROTOCOL_VERSION_14) {
writeBytes(v.getBytesNoCopy());
} else {
......@@ -516,12 +548,17 @@ public class Transfer {
case Value.INTERVAL_MONTH:
case Value.INTERVAL_DAY:
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE: {
ValueInterval interval = (ValueInterval) v;
writeBoolean(interval.isNegative());
writeLong(interval.getLeading());
case Value.INTERVAL_MINUTE:
if (version >= Constants.TCP_PROTOCOL_VERSION_18) {
writeInt(type);
ValueInterval interval = (ValueInterval) v;
writeBoolean(interval.isNegative());
writeLong(interval.getLeading());
} else {
writeInt(Value.STRING);
writeString(v.getString());
}
break;
}
case Value.INTERVAL_SECOND:
case Value.INTERVAL_YEAR_TO_MONTH:
case Value.INTERVAL_DAY_TO_HOUR:
......@@ -529,15 +566,21 @@ public class Transfer {
case Value.INTERVAL_DAY_TO_SECOND:
case Value.INTERVAL_HOUR_TO_MINUTE:
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND: {
ValueInterval interval = (ValueInterval) v;
writeBoolean(interval.isNegative());
writeLong(interval.getLeading());
writeLong(interval.getRemaining());
case Value.INTERVAL_MINUTE_TO_SECOND:
if (version >= Constants.TCP_PROTOCOL_VERSION_18) {
writeInt(type);
ValueInterval interval = (ValueInterval) v;
writeBoolean(interval.isNegative());
writeLong(interval.getLeading());
writeLong(interval.getRemaining());
} else {
writeInt(Value.STRING);
writeString(v.getString());
}
break;
}
default:
if (JdbcUtils.customDataTypesHandler != null) {
writeInt(type);
writeBytes(v.getBytesNoCopy());
break;
}
......@@ -682,6 +725,14 @@ public class Transfer {
}
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: {
SimpleResult rs = new SimpleResult();
int columns = readInt();
......
......@@ -241,10 +241,15 @@ public abstract class Value {
*/
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.
*/
public static final int TYPE_COUNT = INTERVAL_MINUTE_TO_SECOND + 1;
public static final int TYPE_COUNT = ROW + 1;
private static SoftReference<Value[]> softCache;
......@@ -439,6 +444,8 @@ public abstract class Value {
return 44_000;
case ARRAY:
return 50_000;
case ROW:
return 50_500;
case RESULT_SET:
return 51_000;
case ENUM:
......@@ -790,6 +797,8 @@ public abstract class Value {
return convertToIntervalDayTime(targetType);
case ARRAY:
return convertToArray();
case ROW:
return convertToRow();
case RESULT_SET:
return convertToResultSet();
default:
......@@ -1298,7 +1307,37 @@ public abstract class Value {
}
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() {
......
......@@ -13,7 +13,6 @@ import java.util.Arrays;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.util.MathUtils;
import org.h2.util.StatementBuilder;
/**
* Implementation of the ARRAY data type.
......@@ -103,12 +102,14 @@ public class ValueArray extends Value {
@Override
public String getString() {
StatementBuilder buff = new StatementBuilder("(");
for (Value v : values) {
buff.appendExceptFirst(", ");
buff.append(v.getString());
StringBuilder builder = new StringBuilder().append('[');
for (int i = 0; i < values.length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(values[i].getString());
}
return buff.append(')').toString();
return builder.append(']').toString();
}
@Override
......@@ -156,7 +157,7 @@ public class ValueArray extends Value {
@Override
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
builder.append("ARRAY [");
int length = values.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
......@@ -164,20 +165,20 @@ public class ValueArray extends Value {
}
values[i].getSQL(builder);
}
if (length == 1) {
builder.append(',');
}
return builder.append(')');
return builder.append(']');
}
@Override
public String getTraceSQL() {
StatementBuilder buff = new StatementBuilder("(");
for (Value v : values) {
buff.appendExceptFirst(", ");
buff.append(v == null ? "null" : v.getTraceSQL());
StringBuilder builder = new StringBuilder("[");
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 buff.append(')').toString();
return builder.append(']').toString();
}
@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;
}
}
......@@ -196,6 +196,7 @@ import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestIntPerfectHash;
import org.h2.test.unit.TestInterval;
import org.h2.test.unit.TestJmx;
import org.h2.test.unit.TestKeywords;
import org.h2.test.unit.TestLocalResultFactory;
import org.h2.test.unit.TestLocale;
import org.h2.test.unit.TestMathUtils;
......@@ -973,6 +974,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestIntArray());
addTest(new TestIntIntHashMap());
addTest(new TestIntPerfectHash());
addTest(new TestKeywords());
addTest(new TestMathUtils());
addTest(new TestMemoryUnmapper());
addTest(new TestMode());
......
......@@ -157,8 +157,8 @@ public class TestFullText extends TestDb {
assertEquals("KEYS", rs.getMetaData().getColumnLabel(4));
assertEquals("PUBLIC", rs.getString(1));
assertEquals("TEST", rs.getString(2));
assertEquals("(ID)", rs.getString(3));
assertEquals("(1)", rs.getString(4));
assertEquals("[ID]", rs.getString(3));
assertEquals("[1]", rs.getString(4));
rs = stat.executeQuery("SELECT * FROM FT_SEARCH('this', 0, 0)");
assertFalse(rs.next());
......
......@@ -958,9 +958,9 @@ public class TestFunctions extends TestDb implements AggregateFunction {
assertEquals("Hello", rs.getString(2));
assertFalse(rs.next());
stat.execute("CREATE ALIAS ARRAY FOR \"" +
stat.execute("CREATE ALIAS GET_ARRAY FOR \"" +
getClass().getName() + ".getArray\"");
rs = stat.executeQuery("CALL ARRAY()");
rs = stat.executeQuery("CALL GET_ARRAY()");
assertEquals(1, rs.getMetaData().getColumnCount());
rs.next();
Array a = rs.getArray(1);
......
......@@ -463,7 +463,7 @@ public class TestMetaData extends TestDb {
assertEquals("schema", meta.getSchemaTerm());
assertEquals("\\", meta.getSearchStringEscape());
assertEquals("INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP",
assertEquals("IF,INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP",
meta.getSQLKeywords());
assertTrue(meta.getURL().startsWith("jdbc:h2:"));
......
......@@ -1860,7 +1860,7 @@ public class TestResultSet extends TestDb {
assertEquals(Types.NULL, array.getBaseType());
assertEquals("NULL", array.getBaseTypeName());
assertTrue(array.toString().endsWith(": (11, 12)"));
assertTrue(array.toString().endsWith(": [11, 12]"));
// free
array.free();
......
......@@ -144,7 +144,7 @@ public class TestScript extends TestDb {
for (String s : new String[] { "array", "bigint", "binary", "blob",
"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",
"uuid", "varchar", "varchar-ignorecase" }) {
testScript("datatypes/" + s + ".sql");
......
......@@ -16,10 +16,10 @@ SELECT (10, 20, 30)[4];
>> null
SELECT ARRAY[];
>> ()
>> []
SELECT ARRAY[10];
>> (10)
>> [10]
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 @@
CREATE TABLE test (id INT NOT NULL, name VARCHAR);
> ok
select * from test where id = (1, 2);
select * from test where id = ARRAY [1, 2];
> 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;
> ok
......
......@@ -6,18 +6,18 @@
SELECT HISTOGRAM(X), HISTOGRAM(DISTINCT X) FROM VALUES (1), (2), (3), (1), (2), (NULL), (5) T(X);
> 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
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);
> 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
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))
> ------------------------------------- ----------------------------------------------
> () ()
> [] []
> rows: 1
......@@ -32,7 +32,7 @@ drop table test;
> ok
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;
> ID NAME
......
......@@ -36,10 +36,10 @@ SELECT * FROM UNNEST(ARRAY[1], ARRAY[2, 3, 4], ARRAY[5, 6]) WITH ORDINALITY;
> rows: 3
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;
>> 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]));
>> TRUE
......@@ -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;
> A B A IN(UNNEST(B))
> - ------ ---------------
> 2 (2, 4) TRUE
> 3 (2, 5) FALSE
> 2 [2, 4] TRUE
> 3 [2, 5] FALSE
> rows: 2
DROP TABLE TEST;
......
......@@ -366,14 +366,14 @@ explain select -cast(0 as real), -cast(0 as double);
select () empty;
> EMPTY
> -----
> ()
> ------
> ROW ()
> rows: 1
select (1,) one_element;
> ONE_ELEMENT
> -----------
> (1)
> ROW (1)
> rows: 1
select (1) one;
......@@ -1401,9 +1401,9 @@ insert into test values(1, (1, 1)), (2, (1, 2)), (3, (1, 1, 1));
select * from test order by data;
> ID DATA
> -- ---------
> 1 (1, 1)
> 3 (1, 1, 1)
> 2 (1, 2)
> 1 [1, 1]
> 3 [1, 1, 1]
> 2 [1, 2]
> rows (ordered): 3
drop table test;
......@@ -2003,9 +2003,9 @@ drop table people, cars;
> ok
select (1, 2);
> 1, 2
> ------
> (1, 2)
> ROW (1, 2)
> ----------
> ROW (1, 2)
> rows: 1
create table array_test(x array);
......@@ -2017,7 +2017,7 @@ insert into array_test values((1, 2, 3)), ((2, 3, 4));
select * from array_test where x = (1, 2, 3);
> X
> ---------
> (1, 2, 3)
> [1, 2, 3]
> rows: 1
drop table array_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;
> 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
call (select x from dual where x is null);
......@@ -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));
> 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
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 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
> update count: 2
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.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.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(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);
#+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)
......
/*
* 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.test.unit;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashSet;
import org.h2.command.Parser;
import org.h2.test.TestBase;
import org.h2.util.ParserUtil;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* Tests keywords.
*/
public class TestKeywords extends TestBase {
/**
* Run just this test.
*
* @param a
* ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws Exception {
final HashSet<String> set = new HashSet<>();
ClassReader r = new ClassReader(Parser.class.getResourceAsStream("Parser.class"));
r.accept(new ClassVisitor(Opcodes.ASM6) {
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
add(set, value);
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
return new MethodVisitor(Opcodes.ASM6) {
@Override
public void visitLdcInsn(Object value) {
add(set, value);
}
};
}
void add(HashSet<String> set, Object value) {
if (!(value instanceof String)) {
return;
}
String s = (String) value;
int l = s.length();
if (l == 0 || ParserUtil.getSaveTokenType(s, false, 0, l, true) != ParserUtil.IDENTIFIER) {
return;
}
for (int i = 0; i < l; i++) {
char ch = s.charAt(i);
if ((ch < 'A' || ch > 'Z') && ch != '_') {
return;
}
}
set.add(s);
}
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
try (Connection conn = DriverManager.getConnection("jdbc:h2:mem:keywords")) {
Statement stat = conn.createStatement();
for (String s : set) {
// _ROWID_ is a special virtual column
String column = s.equals("_ROWID_") ? "C" : s;
try {
stat.execute("CREATE TABLE " + s + '(' + column + " INT)");
stat.execute("INSERT INTO " + s + '(' + column + ") VALUES (10)");
try (ResultSet rs = stat.executeQuery("SELECT " + column + " FROM " + s)) {
assertTrue(rs.next());
assertEquals(10, rs.getInt(1));
assertFalse(rs.next());
}
} catch (Throwable t) {
throw new AssertionError(s + " cannot be used as identifier.", t);
}
}
}
}
}
......@@ -170,7 +170,7 @@ public class TestValue extends TestDb {
assertEquals(5, v.convertPrecision(5, true).getPrecision());
v = ValueArray.get(new Value[]{ValueString.get(""), ValueString.get("")});
assertEquals(0, v.getPrecision());
assertEquals("('')", v.convertPrecision(1, true).toString());
assertEquals("['']", v.convertPrecision(1, true).toString());
v = ValueBytes.get(spaces.getBytes());
assertEquals(100, v.getPrecision());
......
......@@ -43,6 +43,7 @@ import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
import org.h2.value.ValueRow;
import org.h2.value.ValueShort;
import org.h2.value.ValueString;
import org.h2.value.ValueStringFixed;
......@@ -208,14 +209,10 @@ public class TestValueMemory extends TestBase implements DataHandler {
String s = randomString(len);
return getLobStorage().createClob(new StringReader(s), len);
}
case Value.ARRAY: {
int len = random.nextInt(20);
Value[] list = new Value[len];
for (int i = 0; i < list.length; i++) {
list[i] = create(Value.STRING);
}
return ValueArray.get(list);
}
case Value.ARRAY:
return ValueArray.get(createArray());
case Value.ROW:
return ValueRow.get(createArray());
case Value.RESULT_SET:
return ValueResultSet.get(new SimpleResult());
case Value.JAVA_OBJECT:
......@@ -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) {
byte[] data = new byte[len];
if (random.nextBoolean()) {
......
......@@ -163,9 +163,6 @@ public class Build extends BuildBase {
downloadUsingMaven("ext/org.jacoco.report-0.8.0.jar",
"org.jacoco", "org.jacoco.report", "0.8.0",
"1bcab2a451f5a382bc674857c8f3f6d3fa52151d");
downloadUsingMaven("ext/asm-6.1.jar",
"org.ow2.asm", "asm", "6.1",
"94a0d17ba8eb24833cd54253ace9b053786a9571");
downloadUsingMaven("ext/asm-commons-6.1.jar",
"org.ow2.asm", "asm-commons", "6.1",
"8a8d242d7ce00fc937a245fae5b65763d13f7cd1");
......@@ -272,6 +269,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" +
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar" +
File.pathSeparator + "ext/jts-core-1.15.0.jar" +
File.pathSeparator + "ext/asm-6.1.jar" +
File.pathSeparator + javaToolsJar;
FileList files;
if (clientOnly) {
......@@ -386,6 +384,9 @@ public class Build extends BuildBase {
downloadOrVerify("ext/junit-4.12.jar",
"junit", "junit", "4.12",
"2973d150c0dc1fefe998f834810d68f278ea58ec", offline);
downloadUsingMaven("ext/asm-6.1.jar",
"org.ow2.asm", "asm", "6.1",
"94a0d17ba8eb24833cd54253ace9b053786a9571");
}
private void downloadOrVerify(String target, String group, String artifact,
......@@ -962,6 +963,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/jts-core-1.15.0.jar" +
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/slf4j-nop-1.6.0.jar" +
File.pathSeparator + "ext/asm-6.1.jar" +
File.pathSeparator + javaToolsJar;
int version = getJavaVersion();
if (version >= 9) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论