[feature](function) support variadic template type in SQL function (#17985)
Inspired by c++ function `std::vector::emplace_back()`, we can use variadic template for this issue. e.g. ``` [['struct'], 'STRUCT<TYPES>', ['TYPES'], 'ALWAYS_NOT_NULLABLE', ['TYPES...']] ``` `...TYPES` in template_types defines a variadic template `TYPE`. Then the variadic template will be expanded to multiple normal templates based on actual input arguments at runtime in FE. But make sure `TYPES...` is placed on the last position in all template type arguments. BTW, the origin template function logic is not affected.
This commit is contained in:
@ -40,6 +40,7 @@ import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -858,6 +859,28 @@ public class Function implements Writable {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasVariadicTemplateArg() {
|
||||
for (Type t : getArgs()) {
|
||||
if (t.needExpandTemplateType()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// collect expand size of variadic template
|
||||
public void collectTemplateExpandSize(Type[] args, Map<String, Integer> expandSizeMap) throws TypeException {
|
||||
for (int i = argTypes.length - 1; i >= 0; i--) {
|
||||
if (argTypes[i].hasTemplateType()) {
|
||||
if (argTypes[i].needExpandTemplateType()) {
|
||||
argTypes[i].collectTemplateExpandSize(
|
||||
Arrays.copyOfRange(args, i, args.length), expandSizeMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
||||
@ -1227,9 +1227,14 @@ public class FunctionSet<T> {
|
||||
|
||||
List<Function> normalFunctions = Lists.newArrayList();
|
||||
List<Function> templateFunctions = Lists.newArrayList();
|
||||
List<Function> variadicTemplateFunctions = Lists.newArrayList();
|
||||
for (Function fn : fns) {
|
||||
if (fn.hasTemplateArg()) {
|
||||
templateFunctions.add(fn);
|
||||
if (!fn.hasVariadicTemplateArg()) {
|
||||
templateFunctions.add(fn);
|
||||
} else {
|
||||
variadicTemplateFunctions.add(fn);
|
||||
}
|
||||
} else {
|
||||
normalFunctions.add(fn);
|
||||
}
|
||||
@ -1244,12 +1249,29 @@ public class FunctionSet<T> {
|
||||
// then specialize template functions and try them
|
||||
List<Function> specializedTemplateFunctions = Lists.newArrayList();
|
||||
for (Function f : templateFunctions) {
|
||||
f = FunctionSet.specializeTemplateFunction(f, desc);
|
||||
f = FunctionSet.specializeTemplateFunction(f, desc, false);
|
||||
if (f != null) {
|
||||
specializedTemplateFunctions.add(f);
|
||||
}
|
||||
}
|
||||
return getFunction(desc, mode, specializedTemplateFunctions);
|
||||
|
||||
// try template function second
|
||||
fn = getFunction(desc, mode, specializedTemplateFunctions);
|
||||
if (fn != null) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
// then specialize variadic template function and try them
|
||||
List<Function> specializedVariadicTemplateFunctions = Lists.newArrayList();
|
||||
for (Function f : variadicTemplateFunctions) {
|
||||
f = FunctionSet.specializeTemplateFunction(f, desc, true);
|
||||
if (f != null) {
|
||||
specializedVariadicTemplateFunctions.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
// try variadic template function
|
||||
return getFunction(desc, mode, specializedVariadicTemplateFunctions);
|
||||
}
|
||||
|
||||
private Function getFunction(Function desc, Function.CompareMode mode, List<Function> fns) {
|
||||
@ -1292,19 +1314,43 @@ public class FunctionSet<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Function specializeTemplateFunction(Function templateFunction, Function requestFunction) {
|
||||
public static Function specializeTemplateFunction(Function templateFunction, Function requestFunction, boolean isVariadic) {
|
||||
try {
|
||||
boolean hasTemplateType = false;
|
||||
LOG.debug("templateFunction signature: " + templateFunction.signatureString()
|
||||
+ " return: " + templateFunction.getReturnType());
|
||||
LOG.debug("requestFunction signature: " + requestFunction.signatureString()
|
||||
+ " return: " + requestFunction.getReturnType());
|
||||
List<Type> newArgTypes = Lists.newArrayList();
|
||||
List<Type> newRetType = Lists.newArrayList();
|
||||
if (isVariadic) {
|
||||
Map<String, Integer> expandSizeMap = Maps.newHashMap();
|
||||
templateFunction.collectTemplateExpandSize(requestFunction.getArgs(), expandSizeMap);
|
||||
// expand the variadic template in arg types
|
||||
for (Type argType : templateFunction.getArgs()) {
|
||||
if (argType.needExpandTemplateType()) {
|
||||
newArgTypes.addAll(argType.expandVariadicTemplateType(expandSizeMap));
|
||||
} else {
|
||||
newArgTypes.add(argType);
|
||||
}
|
||||
}
|
||||
|
||||
// expand the variadic template in ret type
|
||||
if (templateFunction.getReturnType().needExpandTemplateType()) {
|
||||
newRetType.addAll(templateFunction.getReturnType().expandVariadicTemplateType(expandSizeMap));
|
||||
Preconditions.checkState(newRetType.size() == 1);
|
||||
} else {
|
||||
newRetType.add(templateFunction.getReturnType());
|
||||
}
|
||||
} else {
|
||||
newArgTypes.addAll(Lists.newArrayList(templateFunction.getArgs()));
|
||||
newRetType.add(templateFunction.getReturnType());
|
||||
}
|
||||
Function specializedFunction = templateFunction;
|
||||
if (templateFunction instanceof ScalarFunction) {
|
||||
ScalarFunction f = (ScalarFunction) templateFunction;
|
||||
specializedFunction = new ScalarFunction(f.getFunctionName(), Lists.newArrayList(f.getArgs()),
|
||||
f.getReturnType(), f.hasVarArgs(), f.getSymbolName(), f.getBinaryType(),
|
||||
f.isUserVisible(), f.isVectorized(), f.getNullableMode());
|
||||
specializedFunction = new ScalarFunction(f.getFunctionName(), newArgTypes, newRetType.get(0), f.hasVarArgs(),
|
||||
f.getSymbolName(), f.getBinaryType(), f.isUserVisible(), f.isVectorized(), f.getNullableMode());
|
||||
} else {
|
||||
// TODO(xk)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user