[Improve](explode) explode function support multi param (#50310)
### What problem does this PR solve? backport:https://github.com/apache/doris/pull/48537 Issue Number: close #xxx Related PR: #xxx Problem Summary: ### Release note None ### Check List (For Author) - Test <!-- At least one of them must be included. --> - [ ] Regression test - [ ] Unit Test - [ ] Manual test (add detailed scripts or steps below) - [ ] No need to test or manual test. Explain why: - [ ] This is a refactor/code format and no logic has been changed. - [ ] Previous test can cover this change. - [ ] No code files have been changed. - [ ] Other reason <!-- Add your reason? --> - Behavior changed: - [ ] No. - [ ] Yes. <!-- Explain the behavior change --> - Does this need documentation? - [ ] No. - [ ] Yes. <!-- Add document PR link here. eg: https://github.com/apache/doris-website/pull/1214 --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->
This commit is contained in:
@ -41,8 +41,11 @@ import org.apache.doris.nereids.trees.expressions.functions.generator.PosExplode
|
||||
import org.apache.doris.nereids.trees.expressions.functions.generator.PosExplodeOuter;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Builtin table generating functions.
|
||||
@ -76,6 +79,13 @@ public class BuiltinTableGeneratingFunctions implements FunctionHelper {
|
||||
tableGenerating(PosExplodeOuter.class, "posexplode_outer")
|
||||
);
|
||||
|
||||
public static final ImmutableSet<String> RETURN_MULTI_COLUMNS_FUNCTIONS = new ImmutableSortedSet.Builder<String>(
|
||||
String.CASE_INSENSITIVE_ORDER).add("explode").add("explode_outer").build();
|
||||
|
||||
public Set<String> getReturnManyColumnFunctions() {
|
||||
return RETURN_MULTI_COLUMNS_FUNCTIONS;
|
||||
}
|
||||
|
||||
public static final BuiltinTableGeneratingFunctions INSTANCE = new BuiltinTableGeneratingFunctions();
|
||||
|
||||
// Note: Do not add any code here!
|
||||
|
||||
@ -26,6 +26,7 @@ import org.apache.doris.analysis.TableSnapshot;
|
||||
import org.apache.doris.analysis.UserIdentity;
|
||||
import org.apache.doris.catalog.AggregateType;
|
||||
import org.apache.doris.catalog.BuiltinAggregateFunctions;
|
||||
import org.apache.doris.catalog.BuiltinTableGeneratingFunctions;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.catalog.KeysType;
|
||||
import org.apache.doris.catalog.ScalarType;
|
||||
@ -1206,8 +1207,13 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
String generateName = ctx.tableName.getText();
|
||||
// if later view explode map type, we need to add a project to convert map to struct
|
||||
String columnName = ctx.columnNames.get(0).getText();
|
||||
List<String> expandColumnNames = Lists.newArrayList();
|
||||
if (ctx.columnNames.size() > 1) {
|
||||
List<String> expandColumnNames = ImmutableList.of();
|
||||
|
||||
// explode can pass multiple columns
|
||||
// then use struct to return the result of the expansion of multiple columns.
|
||||
if (ctx.columnNames.size() > 1
|
||||
|| BuiltinTableGeneratingFunctions.INSTANCE.getReturnManyColumnFunctions()
|
||||
.contains(ctx.functionName.getText())) {
|
||||
columnName = ConnectContext.get() != null
|
||||
? ConnectContext.get().getStatementContext().generateColumnName() : "expand_cols";
|
||||
expandColumnNames = ctx.columnNames.stream()
|
||||
|
||||
@ -20,31 +20,34 @@ package org.apache.doris.nereids.trees.expressions.functions.generator;
|
||||
import org.apache.doris.catalog.FunctionSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
|
||||
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.ComputePrecision;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.CustomSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.SearchSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.ArrayType;
|
||||
import org.apache.doris.nereids.types.coercion.AnyDataType;
|
||||
import org.apache.doris.nereids.types.coercion.FollowToAnyDataType;
|
||||
import org.apache.doris.nereids.types.DataType;
|
||||
import org.apache.doris.nereids.types.NullType;
|
||||
import org.apache.doris.nereids.types.StructField;
|
||||
import org.apache.doris.nereids.types.StructType;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* explode([1, 2, 3]), generate 3 lines include 1, 2 and 3.
|
||||
* explode([1, 2, 3]), generate three rows include 1, 2 and 3.
|
||||
* explode([1, 2, 3], [4, 5, 6]) generates two columns and three rows
|
||||
* where the first column contains 1, 2, 3, and the second column contains 4, 5, 6.
|
||||
*/
|
||||
public class Explode extends TableGeneratingFunction implements BinaryExpression, AlwaysNullable {
|
||||
|
||||
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
|
||||
FunctionSignature.ret(new FollowToAnyDataType(0)).args(ArrayType.of(new AnyDataType(0)))
|
||||
);
|
||||
public class Explode extends TableGeneratingFunction implements CustomSignature, ComputePrecision, AlwaysNullable {
|
||||
|
||||
/**
|
||||
* constructor with 1 argument.
|
||||
* constructor with one or more argument.
|
||||
*/
|
||||
public Explode(Expression arg) {
|
||||
super("explode", arg);
|
||||
public Explode(Expression[] args) {
|
||||
super("explode", args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,17 +55,43 @@ public class Explode extends TableGeneratingFunction implements BinaryExpression
|
||||
*/
|
||||
@Override
|
||||
public Explode withChildren(List<Expression> children) {
|
||||
Preconditions.checkArgument(children.size() == 1);
|
||||
return new Explode(children.get(0));
|
||||
Preconditions.checkArgument(!children.isEmpty());
|
||||
return new Explode(children.toArray(new Expression[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FunctionSignature> getSignatures() {
|
||||
return SIGNATURES;
|
||||
public FunctionSignature computePrecision(FunctionSignature signature) {
|
||||
return signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionSignature customSignature() {
|
||||
List<DataType> arguments = new ArrayList<>();
|
||||
ImmutableList.Builder<StructField> structFields = ImmutableList.builder();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
if (children.get(i).getDataType().isNullType()) {
|
||||
arguments.add(ArrayType.of(NullType.INSTANCE));
|
||||
structFields.add(
|
||||
new StructField("col" + (i + 1), NullType.INSTANCE, true, ""));
|
||||
} else if (children.get(i).getDataType().isArrayType()) {
|
||||
structFields.add(
|
||||
new StructField("col" + (i + 1),
|
||||
((ArrayType) (children.get(i)).getDataType()).getItemType(), true, ""));
|
||||
arguments.add(children.get(i).getDataType());
|
||||
} else {
|
||||
SearchSignature.throwCanNotFoundFunctionException(this.getName(), getArguments());
|
||||
}
|
||||
}
|
||||
return FunctionSignature.of(new StructType(structFields.build()), arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
|
||||
return visitor.visitExplode(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionSignature searchSignature(List<FunctionSignature> signatures) {
|
||||
return super.searchSignature(signatures);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,31 +20,34 @@ package org.apache.doris.nereids.trees.expressions.functions.generator;
|
||||
import org.apache.doris.catalog.FunctionSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
|
||||
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.ComputePrecision;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.CustomSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.SearchSignature;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.ArrayType;
|
||||
import org.apache.doris.nereids.types.coercion.AnyDataType;
|
||||
import org.apache.doris.nereids.types.coercion.FollowToAnyDataType;
|
||||
import org.apache.doris.nereids.types.DataType;
|
||||
import org.apache.doris.nereids.types.NullType;
|
||||
import org.apache.doris.nereids.types.StructField;
|
||||
import org.apache.doris.nereids.types.StructType;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* explode([1, 2, 3]), generate 3 lines include 1, 2 and 3.
|
||||
* explode_outer([1, 2, 3]), generate three rows include 1, 2 and 3.
|
||||
* explode_outer([1, 2, 3], [4, 5, 6]) generates two columns and three rows
|
||||
* where the first column contains 1, 2, 3, and the second column contains 4, 5, 6.
|
||||
*/
|
||||
public class ExplodeOuter extends TableGeneratingFunction implements BinaryExpression, AlwaysNullable {
|
||||
|
||||
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
|
||||
FunctionSignature.ret(new FollowToAnyDataType(0)).args(ArrayType.of(new AnyDataType(0)))
|
||||
);
|
||||
public class ExplodeOuter extends TableGeneratingFunction implements CustomSignature, ComputePrecision, AlwaysNullable {
|
||||
|
||||
/**
|
||||
* constructor with 1 argument.
|
||||
* constructor with one or more argument.
|
||||
*/
|
||||
public ExplodeOuter(Expression arg) {
|
||||
super("explode_outer", arg);
|
||||
public ExplodeOuter(Expression[] args) {
|
||||
super("explode_outer", args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,17 +55,43 @@ public class ExplodeOuter extends TableGeneratingFunction implements BinaryExpre
|
||||
*/
|
||||
@Override
|
||||
public ExplodeOuter withChildren(List<Expression> children) {
|
||||
Preconditions.checkArgument(children.size() == 1);
|
||||
return new ExplodeOuter(children.get(0));
|
||||
Preconditions.checkArgument(!children.isEmpty());
|
||||
return new ExplodeOuter(children.toArray(new Expression[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FunctionSignature> getSignatures() {
|
||||
return SIGNATURES;
|
||||
public FunctionSignature computePrecision(FunctionSignature signature) {
|
||||
return signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionSignature customSignature() {
|
||||
List<DataType> arguments = new ArrayList<>();
|
||||
ImmutableList.Builder<StructField> structFields = ImmutableList.builder();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
if (children.get(i).getDataType().isNullType()) {
|
||||
arguments.add(ArrayType.of(NullType.INSTANCE));
|
||||
structFields.add(
|
||||
new StructField("col" + (i + 1), NullType.INSTANCE, true, ""));
|
||||
} else if (children.get(i).getDataType().isArrayType()) {
|
||||
structFields.add(
|
||||
new StructField("col" + (i + 1),
|
||||
((ArrayType) (children.get(i)).getDataType()).getItemType(), true, ""));
|
||||
arguments.add(children.get(i).getDataType());
|
||||
} else {
|
||||
SearchSignature.throwCanNotFoundFunctionException(this.getName(), getArguments());
|
||||
}
|
||||
}
|
||||
return FunctionSignature.of(new StructType(structFields.build()), arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
|
||||
return visitor.visitExplodeOuter(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionSignature searchSignature(List<FunctionSignature> signatures) {
|
||||
return super.searchSignature(signatures);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions.functions.generator;
|
||||
|
||||
import org.apache.doris.catalog.FunctionSignature;
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.SlotReference;
|
||||
import org.apache.doris.nereids.types.ArrayType;
|
||||
import org.apache.doris.nereids.types.IntegerType;
|
||||
import org.apache.doris.nereids.types.NullType;
|
||||
import org.apache.doris.nereids.types.StringType;
|
||||
import org.apache.doris.nereids.types.StructType;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ExplodeOuterTest {
|
||||
|
||||
/////////////////////////////////////////
|
||||
// GetSignatures
|
||||
/////////////////////////////////////////
|
||||
|
||||
@Test
|
||||
public void testGetSignatures() {
|
||||
// build explode_outer(array<int>, array<str>) expression
|
||||
Expression[] args = {SlotReference.of("int", ArrayType.of(IntegerType.INSTANCE)),
|
||||
SlotReference.of("str", ArrayType.of(StringType.INSTANCE))};
|
||||
ExplodeOuter explode = new ExplodeOuter(args);
|
||||
|
||||
// check signature
|
||||
List<FunctionSignature> signatures = explode.getSignatures();
|
||||
Assertions.assertEquals(1, signatures.size());
|
||||
FunctionSignature signature = signatures.get(0);
|
||||
Assertions.assertEquals(2, signature.argumentsTypes.size());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(0).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(0)).getItemType().isIntegerType());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(1).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(1)).getItemType().isStringType());
|
||||
Assertions.assertTrue(signature.returnType.isStructType());
|
||||
StructType returnType = (StructType) signature.returnType;
|
||||
Assertions.assertEquals(2, returnType.getFields().size());
|
||||
Assertions.assertEquals(IntegerType.INSTANCE, returnType.getFields().get(0).getDataType());
|
||||
Assertions.assertEquals(StringType.INSTANCE, returnType.getFields().get(1).getDataType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSignaturesWithNull() {
|
||||
// build explode(null, array<int>) expression
|
||||
Expression[] args = { SlotReference.of("null", NullType.INSTANCE), SlotReference.of("int", ArrayType.of(IntegerType.INSTANCE))};
|
||||
ExplodeOuter explode = new ExplodeOuter(args);
|
||||
|
||||
// check signature
|
||||
List<FunctionSignature> signatures = explode.getSignatures();
|
||||
Assertions.assertEquals(1, signatures.size());
|
||||
FunctionSignature signature = signatures.get(0);
|
||||
Assertions.assertEquals(2, signature.argumentsTypes.size());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(0).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(0)).getItemType().isNullType());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(1).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(1)).getItemType().isIntegerType());
|
||||
Assertions.assertTrue(signature.returnType.isStructType());
|
||||
StructType returnType = (StructType) signature.returnType;
|
||||
Assertions.assertEquals(2, returnType.getFields().size());
|
||||
Assertions.assertEquals(NullType.INSTANCE, returnType.getFields().get(0).getDataType());
|
||||
Assertions.assertEquals(IntegerType.INSTANCE, returnType.getFields().get(1).getDataType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSignaturesWithInvalidArgument() {
|
||||
// build explode_outer(int)
|
||||
Expression[] args = { SlotReference.of("int", IntegerType.INSTANCE) };
|
||||
ExplodeOuter explode = new ExplodeOuter(args);
|
||||
|
||||
Assertions.assertThrows(AnalysisException.class, explode::getSignatures);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions.functions.generator;
|
||||
|
||||
import org.apache.doris.catalog.FunctionSignature;
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.SlotReference;
|
||||
import org.apache.doris.nereids.types.ArrayType;
|
||||
import org.apache.doris.nereids.types.IntegerType;
|
||||
import org.apache.doris.nereids.types.NullType;
|
||||
import org.apache.doris.nereids.types.StringType;
|
||||
import org.apache.doris.nereids.types.StructType;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ExplodeTest {
|
||||
|
||||
/////////////////////////////////////////
|
||||
// GetSignatures
|
||||
/////////////////////////////////////////
|
||||
|
||||
@Test
|
||||
public void testGetSignatures() {
|
||||
// build explode(array<int>, array<str>) expression
|
||||
Expression[] args = {SlotReference.of("int", ArrayType.of(IntegerType.INSTANCE)),
|
||||
SlotReference.of("str", ArrayType.of(StringType.INSTANCE))};
|
||||
Explode explode = new Explode(args);
|
||||
|
||||
// check signature
|
||||
List<FunctionSignature> signatures = explode.getSignatures();
|
||||
Assertions.assertEquals(1, signatures.size());
|
||||
FunctionSignature signature = signatures.get(0);
|
||||
Assertions.assertEquals(2, signature.argumentsTypes.size());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(0).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(0)).getItemType().isIntegerType());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(1).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(1)).getItemType().isStringType());
|
||||
Assertions.assertTrue(signature.returnType.isStructType());
|
||||
StructType returnType = (StructType) signature.returnType;
|
||||
Assertions.assertEquals(2, returnType.getFields().size());
|
||||
Assertions.assertEquals(IntegerType.INSTANCE, returnType.getFields().get(0).getDataType());
|
||||
Assertions.assertEquals(StringType.INSTANCE, returnType.getFields().get(1).getDataType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSignaturesWithNull() {
|
||||
// build explode(null, array<int>) expression
|
||||
Expression[] args = { SlotReference.of("null", NullType.INSTANCE), SlotReference.of("int", ArrayType.of(IntegerType.INSTANCE))};
|
||||
Explode explode = new Explode(args);
|
||||
|
||||
// check signature
|
||||
List<FunctionSignature> signatures = explode.getSignatures();
|
||||
Assertions.assertEquals(1, signatures.size());
|
||||
FunctionSignature signature = signatures.get(0);
|
||||
Assertions.assertEquals(2, signature.argumentsTypes.size());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(0).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(0)).getItemType().isNullType());
|
||||
Assertions.assertTrue(signature.argumentsTypes.get(1).isArrayType());
|
||||
Assertions.assertTrue(((ArrayType) signature.argumentsTypes.get(1)).getItemType().isIntegerType());
|
||||
Assertions.assertTrue(signature.returnType.isStructType());
|
||||
StructType returnType = (StructType) signature.returnType;
|
||||
Assertions.assertEquals(2, returnType.getFields().size());
|
||||
Assertions.assertEquals(NullType.INSTANCE, returnType.getFields().get(0).getDataType());
|
||||
Assertions.assertEquals(IntegerType.INSTANCE, returnType.getFields().get(1).getDataType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSignaturesWithInvalidArgument() {
|
||||
// build explode(int)
|
||||
Expression[] args = { SlotReference.of("int", IntegerType.INSTANCE) };
|
||||
Explode explode = new Explode(args);
|
||||
|
||||
Assertions.assertThrows(AnalysisException.class, explode::getSignatures);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user