IGNITE-29031 SQL Calcite: Support byte[] in UDF and UDTF parameters and results - #13543
IGNITE-29031 SQL Calcite: Support byte[] in UDF and UDTF parameters and results#13543tkalkirill wants to merge 2 commits into
Conversation
|
First of all you need to follow the common process [1] i.e. make a PR from your own ignite mirror, not from origin = https://github.com/apache but from: https://github.com/tkalkirill/ignite |
|
@zstan Okay, subsequent tickets will do as described. |
| Object[] convertedRow = row; | ||
|
|
||
| for (int i = 0; i < row.length; i++) { | ||
| if (row[i] instanceof byte[] && SqlTypeUtil.isBinary(rowType.getFieldList().get(i).getType())) { |
There was a problem hiding this comment.
- we already have common converter : TypeUtils#toInternal - it need to be used
- explain why do you need row.clone() ? .toArray() - already produced a new array.
There was a problem hiding this comment.
Tried to fix them.
| /** */ | ||
| private static Function<Object, Object> fieldConverter(ExecutionContext<?> ectx, RelDataType fieldType) { | ||
| Type storageType = ectx.getTypeFactory().getJavaClass(fieldType); | ||
| Type storageType = SqlTypeUtil.isBinary(fieldType) ? byte[].class : ectx.getTypeFactory().getJavaClass(fieldType); |
There was a problem hiding this comment.
plz explain why do we need changes in this class ? All changes need to be covered by tests, i miss them.
There was a problem hiding this comment.
This was needed because the previous implementation was only for a byte[], now it is not needed, I got rid of it.
| } | ||
|
|
||
| /** Prevents Calcite from evaluating binary literals while deriving a table function row type. */ | ||
| private static FunctionParameter sqlBinaryParameter(FunctionParameter delegate) { |
There was a problem hiding this comment.
This change is only needed when a byte[] table-function argument is a binary literal, for example binaryTableLength(x'010203'). Calcite tries to materialize the literal as byte[] during row-type inference, before the runtime converter is involved. Dynamic parameters and other non-literal expressions work without this workaround.
Would you prefer that we drop binary-literal support from this fix and address it separately if needed, or keep the workaround with an explanatory comment and a dedicated test?
There was a problem hiding this comment.
I prefer to revise this approach, if it`s hard to implement now - let`s fill an additional issue, thanks !
There was a problem hiding this comment.
When testing with temporal types, it turned out that this is currently necessary and does not work without it.
|
|
||
| /** */ | ||
| @Test | ||
| public void testBinaryFunctions() { |
There was a problem hiding this comment.
I disagree that this PR need to cover only byte[], what about temporal types ? BO, appropriate tests need to be appended.
There was a problem hiding this comment.
Added quite a lot of tests.
| callExpr = Expressions.call(target, method, translatedOperands); | ||
| } | ||
|
|
||
| if (TypeUtils.isConvertableType(method.getReturnType())) { |
There was a problem hiding this comment.
@QuerySqlFunction
public static java.util.Date kill1() {
return java.sql.Date.valueOf("2020-01-01");
}
and further call:
assertQuery("SELECT kill1()")
.resultSize(1)
.check();
will raise ClassCastException, while
@QuerySqlFunction
public static java.sql.Date kill2() {
return java.sql.Date.valueOf("2020-01-01");
}
passes, wdyt ?
|
|
||
| for (int i = 0; i < rowArr.length; i++) { | ||
| if (!(rowType.getFieldList().get(i).getType() instanceof OtherType)) | ||
| rowArr[i] = TypeUtils.toInternal(ctx, rowArr[i]); |
There was a problem hiding this comment.
failed:
assertQuery("SELECT EXTRACT(YEAR FROM D) FROM f()")
.resultSize(1)
.check();
@QuerySqlTableFunction(columnTypes =
{java.util.Date.class}, columnNames = {"D"})
public static Iterable<Object[]> f() { // kill
return Collections.singletonList(new Object[] {java.sql.Date.valueOf("2020-01-01")});
}
| Duration.class, | ||
| Period.class, | ||
| char.class, | ||
| Character.class, |
There was a problem hiding this comment.
UDF like : static boolean f(char c)
and further SELECT f('') ->
literal CHAR(0) passes SqlTypeAssignmentRule (CHAR assignable from CHAR,
precision ignored) so no CAST is added;
TypeUtils.fromInternal(root, "", char.class) ->
StringIndexOutOfBoundsException
| else if (targetType == Long.class) | ||
| return Expressions.call(BuiltInMethod.TIMESTAMP_TO_LONG_OPTIONAL.method, operand); | ||
| } | ||
| else if (fromType == byte[].class && targetType == ByteString.class) |
| if (isA(fromType, Primitive.LONG)) | ||
| return Expressions.call(BuiltInMethod.INTERNAL_TO_TIMESTAMP.method, operand); | ||
| } | ||
| else if (targetType == byte[].class && fromType == ByteString.class) |
| } | ||
|
|
||
| /** {@inheritDoc} */ | ||
| @Override public List<FunctionParameter> getParameters() { |
There was a problem hiding this comment.
need to be moved into abstract class cause IgniteScalarFunction#getParameters do the same as i can see
| } | ||
|
|
||
| for (int i = 0; i < rowArr.length; i++) { | ||
| if (!(rowType.getFieldList().get(i).getType() instanceof OtherType)) |
There was a problem hiding this comment.
Also near passed on master and failed in current branch, seems regression:
@Test
public void testCollectionColumnTableFunctions() {
client.getOrCreateCache(new
CacheConfiguration<>("collection-column-table-functions")
.setSqlSchema("PUBLIC")
.setSqlFunctionClasses(CollectionColumnFunctionsLibrary.class));
// ArrayList column -> ARRAY.
assertQuery("SELECT ID, CARDINALITY(VALS), VALS[1] FROM " +
"listColumn()")
.returns(1, 2, 10)
.returns(2, 3, 30)
.check();
assertQuery("SELECT t.ID, v.VAL FROM listColumn() t, " +
" UNNEST(t.VALS) v(VAL) ORDER BY t.ID, v.VAL")
.returns(1, 10)
.returns(1, 20)
.returns(2, 30)
.returns(2, 40)
.returns(2, 50)
.check();
// String[] column -> MULTISET.
assertQuery("SELECT ID, CARDINALITY(NAMES) FROM arrayColumn()")
.returns(1, 1)
.returns(2, 2)
.check();
assertQuery("SELECT t.ID, n.NAME FROM arrayColumn() t, " +
" UNNEST(t.NAMES) n(NAME) ORDER BY t.ID, n.NAME")
.returns(1, "a")
.returns(2, "b")
.returns(2, "c")
.check();
}
/** */
public static final class CollectionColumnFunctionsLibrary {
/** */
private CollectionColumnFunctionsLibrary() {
// No-op.
}
/** Returns rows with a {@link List}-typed column. */
@QuerySqlTableFunction(columnTypes = {int.class, ArrayList.class},
columnNames = {"ID", "VALS"})
public static Iterable<Collection<?>> listColumn() {
return Arrays.asList(
Arrays.asList(1, new ArrayList<>(Arrays.asList(10, 20))),
Arrays.asList(2, new ArrayList<>(Arrays.asList(30, 40,
50)))
);
}
/** Returns rows with an array-typed column. */
@QuerySqlTableFunction(columnTypes = {int.class, String[].class},
columnNames = {"ID", "NAMES"})
public static Iterable<Collection<?>> arrayColumn() {
return Arrays.asList(
Arrays.asList(1, Arrays.asList("a")),
Arrays.asList(2, Arrays.asList("b", "c"))
);
}
}
https://issues.apache.org/jira/browse/IGNITE-29031