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

Merge pull request #1648 from ilm-informatique/arrayFunctions

Add functions ARRAY_CAT(), ARRAY_APPEND() and ARRAY_SLICE()
...@@ -4842,6 +4842,34 @@ Returns NULL if the specified array is NULL. ...@@ -4842,6 +4842,34 @@ Returns NULL if the specified array is NULL.
CALL ARRAY_CONTAINS(ARRAY['Hello', 'World'], 'Hello') CALL ARRAY_CONTAINS(ARRAY['Hello', 'World'], 'Hello')
" "
"Functions (System)","ARRAY_CAT","
ARRAY_CAT(arrayExpression, arrayExpression)
","
Returns the concatenation of two arrays.
Returns NULL if any parameter is NULL.
","
CALL ARRAY_CAT(ARRAY[1, 2], ARRAY[3, 4])
"
"Functions (System)","ARRAY_APPEND","
ARRAY_APPEND(arrayExpression, value)
","
Append an element to the end of an array.
Returns NULL if any parameter is NULL.
","
CALL ARRAY_APPEND(ARRAY[1, 2], 3)
"
"Functions (System)","ARRAY_SLICE","
ARRAY_SLICE(arrayExpression, lowerBoundInt, upperBoundInt)
","
Returns elements from the array as specified by the lower and upper bound parameters.
Both parameters are inclusive and the first element has index 1, i.e. ARRAY_SLICE(a, 2, 2) has only the second element.
Returns NULL if any parameter is NULL or if an index is out of bounds.
","
CALL ARRAY_SLICE(ARRAY[1, 2, 3, 4], 1, 3)
"
"Functions (System)","AUTOCOMMIT"," "Functions (System)","AUTOCOMMIT","
AUTOCOMMIT() AUTOCOMMIT()
"," ","
......
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>PR #1648: Add functions ARRAY_CAT(), ARRAY_APPEND() and ARRAY_SLICE()
</li>
<li>PR #1638: Add support for Java 11 to test suite <li>PR #1638: Add support for Java 11 to test suite
</li> </li>
<li>PR #1637: Remove explicit unboxing <li>PR #1637: Remove explicit unboxing
......
...@@ -959,6 +959,7 @@ or the SQL statement <code>SET MODE PostgreSQL</code>. ...@@ -959,6 +959,7 @@ or the SQL statement <code>SET MODE PostgreSQL</code>.
</li><li>Fixed-width strings are padded with spaces. </li><li>Fixed-width strings are padded with spaces.
</li><li>MONEY data type is treated like NUMERIC(19, 2) data type. </li><li>MONEY data type is treated like NUMERIC(19, 2) data type.
</li><li>Datetime value functions return the same value within a transaction. </li><li>Datetime value functions return the same value within a transaction.
</li><li>ARRAY_SLICE() out of bounds parameters are silently corrected.
</li></ul> </li></ul>
<h3>Ignite Compatibility Mode</h3> <h3>Ignite Compatibility Mode</h3>
......
...@@ -16,6 +16,7 @@ import java.sql.Connection; ...@@ -16,6 +16,7 @@ import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -27,6 +28,7 @@ import org.h2.command.Parser; ...@@ -27,6 +28,7 @@ import org.h2.command.Parser;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
...@@ -61,6 +63,7 @@ import org.h2.util.Utils; ...@@ -61,6 +63,7 @@ import org.h2.util.Utils;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.ExtTypeInfo; import org.h2.value.ExtTypeInfo;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
import org.h2.value.ValueBytes; import org.h2.value.ValueBytes;
import org.h2.value.ValueCollectionBase; import org.h2.value.ValueCollectionBase;
...@@ -135,7 +138,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -135,7 +138,7 @@ public class Function extends Expression implements FunctionCall {
CANCEL_SESSION = 221, SET = 222, TABLE = 223, TABLE_DISTINCT = 224, CANCEL_SESSION = 221, SET = 222, TABLE = 223, TABLE_DISTINCT = 224,
FILE_READ = 225, TRANSACTION_ID = 226, TRUNCATE_VALUE = 227, FILE_READ = 225, TRANSACTION_ID = 226, TRUNCATE_VALUE = 227,
NVL2 = 228, DECODE = 229, ARRAY_CONTAINS = 230, FILE_WRITE = 232, NVL2 = 228, DECODE = 229, ARRAY_CONTAINS = 230, FILE_WRITE = 232,
UNNEST = 233; UNNEST = 233, ARRAY_CONCAT = 234, ARRAY_APPEND = 235, ARRAY_SLICE = 236;
public static final int REGEXP_LIKE = 240; public static final int REGEXP_LIKE = 240;
...@@ -419,6 +422,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -419,6 +422,9 @@ public class Function extends Expression implements FunctionCall {
addFunction("ARRAY_GET", ARRAY_GET, addFunction("ARRAY_GET", ARRAY_GET,
2, Value.NULL); 2, Value.NULL);
addFunctionWithNull("ARRAY_CONTAINS", ARRAY_CONTAINS, 2, Value.BOOLEAN); addFunctionWithNull("ARRAY_CONTAINS", ARRAY_CONTAINS, 2, Value.BOOLEAN);
addFunction("ARRAY_CAT", ARRAY_CONCAT, 2, Value.ARRAY);
addFunction("ARRAY_APPEND", ARRAY_APPEND, 2, Value.ARRAY);
addFunction("ARRAY_SLICE", ARRAY_SLICE, 3, Value.ARRAY);
addFunction("CSVREAD", CSVREAD, addFunction("CSVREAD", CSVREAD,
VAR_ARGS, Value.RESULT_SET, false, false, false, true); VAR_ARGS, Value.RESULT_SET, false, false, false, true);
addFunction("CSVWRITE", CSVWRITE, addFunction("CSVWRITE", CSVWRITE,
...@@ -1542,6 +1548,61 @@ public class Function extends Expression implements FunctionCall { ...@@ -1542,6 +1548,61 @@ public class Function extends Expression implements FunctionCall {
} }
break; break;
} }
case ARRAY_CONCAT: {
final ValueArray array = (ValueArray) v0.convertTo(Value.ARRAY);
final ValueArray array2 = (ValueArray) v1.convertTo(Value.ARRAY);
if (!array.getComponentType().equals(array2.getComponentType()))
throw DbException.get(ErrorCode.GENERAL_ERROR_1, "Expected component type " + array.getComponentType()
+ " but got " + array2.getComponentType());
final Value[] res = Arrays.copyOf(array.getList(), array.getList().length + array2.getList().length);
System.arraycopy(array2.getList(), 0, res, array.getList().length, array2.getList().length);
result = ValueArray.get(array.getComponentType(), res);
break;
}
case ARRAY_APPEND: {
final ValueArray array = (ValueArray) v0.convertTo(Value.ARRAY);
if (v1 != ValueNull.INSTANCE && array.getComponentType() != Object.class
&& !array.getComponentType().isInstance(v1.getObject()))
throw DbException.get(ErrorCode.GENERAL_ERROR_1,
"Expected component type " + array.getComponentType() + " but got " + v1.getClass());
final Value[] res = Arrays.copyOf(array.getList(), array.getList().length + 1);
res[array.getList().length] = v1;
result = ValueArray.get(array.getComponentType(), res);
break;
}
case ARRAY_SLICE: {
result = null;
final ValueArray array = (ValueArray) v0.convertTo(Value.ARRAY);
// SQL is 1-based
int index1 = v1.getInt() - 1;
// 1-based and inclusive as postgreSQL (-1+1)
int index2 = v2.getInt();
// https://www.postgresql.org/docs/current/arrays.html#ARRAYS-ACCESSING
// For historical reasons postgreSQL ignore invalid indexes
final boolean isPG = database.getMode().getEnum() == ModeEnum.PostgreSQL;
if (index1 > index2) {
if (isPG)
result = ValueArray.get(array.getComponentType(), new Value[0]);
else
result = ValueNull.INSTANCE;
} else {
if (index1 < 0) {
if (isPG)
index1 = 0;
else
result = ValueNull.INSTANCE;
}
if (index2 > array.getList().length) {
if (isPG)
index2 = array.getList().length;
else
result = ValueNull.INSTANCE;
}
}
if (result == null)
result = ValueArray.get(array.getComponentType(), Arrays.copyOfRange(array.getList(), index1, index2));
break;
}
case LINK_SCHEMA: { case LINK_SCHEMA: {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
Connection conn = session.createConnection(false); Connection conn = session.createConnection(false);
......
...@@ -186,8 +186,8 @@ public class TestScript extends TestDb { ...@@ -186,8 +186,8 @@ public class TestScript extends TestDb {
"xmlnode", "xmlstartdoc", "xmltext" }) { "xmlnode", "xmlstartdoc", "xmltext" }) {
testScript("functions/string/" + s + ".sql"); testScript("functions/string/" + s + ".sql");
} }
for (String s : new String[] { "array-contains", "array-get", for (String s : new String[] { "array-cat", "array-contains", "array-get",
"array-length", "autocommit", "cancel-session", "casewhen", "array-length","array-slice", "autocommit", "cancel-session", "casewhen",
"cast", "coalesce", "convert", "csvread", "csvwrite", "currval", "cast", "coalesce", "convert", "csvread", "csvwrite", "currval",
"database-path", "database", "decode", "disk-space-used", "database-path", "database", "decode", "disk-space-used",
"file-read", "file-write", "greatest", "h2version", "identity", "file-read", "file-write", "greatest", "h2version", "identity",
......
-- Copyright 2004-2019 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 array_cat(ARRAY[1, 2], ARRAY[3, 4]) = ARRAY[1, 2, 3, 4];
>> TRUE
select array_cat(ARRAY[1, 2], null) is null;
>> TRUE
select array_cat(null, ARRAY[1, 2]) is null;
>> TRUE
select array_append(ARRAY[1, 2], 3) = ARRAY[1, 2, 3];
>> TRUE
select array_append(ARRAY[1, 2], null) is null;
>> TRUE
select array_append(null, 3) is null;
>> TRUE
-- Copyright 2004-2019 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 array_slice(ARRAY[1, 2, 3, 4], 1, 1) = ARRAY[1];
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], 1, 3) = ARRAY[1, 2, 3];
>> TRUE
-- test invalid indexes
select array_slice(ARRAY[1, 2, 3, 4], 3, 1) is null;
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], 0, 3) is null;
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], 1, 5) is null;
>> TRUE
-- in PostgreSQL, indexes are corrected
SET MODE PostgreSQL;
> ok
select array_slice(ARRAY[1, 2, 3, 4], 3, 1) = ARRAY[];
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], 0, 3) = ARRAY[1, 2, 3];
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], 1, 5) = ARRAY[1, 2, 3, 4];
>> TRUE
SET MODE Regular;
> ok
-- null parameters
select array_slice(null, 1, 3) is null;
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], null, 3) is null;
>> TRUE
select array_slice(ARRAY[1, 2, 3, 4], 1, null) is null;
>> TRUE
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论