1 package com.mapd.calcite.parser;
5 import static org.apache.calcite.runtime.Resources.BaseMessage;
6 import static org.apache.calcite.runtime.Resources.ExInst;
10 import org.apache.calcite.linq4j.Ord;
11 import org.apache.calcite.rel.type.RelDataType;
12 import org.apache.calcite.rel.type.RelDataTypeField;
13 import org.apache.calcite.runtime.CalciteException;
14 import org.apache.calcite.runtime.Resources;
15 import org.apache.calcite.sql.SqlBasicCall;
16 import org.apache.calcite.sql.SqlCall;
17 import org.apache.calcite.sql.SqlCallBinding;
18 import org.apache.calcite.sql.SqlFunctionCategory;
19 import org.apache.calcite.sql.SqlIdentifier;
20 import org.apache.calcite.sql.SqlKind;
21 import org.apache.calcite.sql.SqlNode;
22 import org.apache.calcite.sql.SqlOperandCountRange;
24 import org.apache.calcite.sql.SqlSyntax;
25 import org.apache.calcite.sql.SqlUtil;
26 import org.apache.calcite.sql.type.SqlOperandCountRanges;
27 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
28 import org.apache.calcite.sql.type.SqlTypeFamily;
29 import org.apache.calcite.sql.type.SqlTypeName;
30 import org.apache.calcite.sql.validate.SqlNameMatchers;
31 import org.apache.calcite.sql.validate.SqlValidator;
32 import org.apache.calcite.sql.validate.SqlValidatorException;
33 import org.apache.calcite.sql.validate.SqlValidatorScope;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.List;
40 import java.util.stream.Collectors;
59 SqlCallBinding callBinding,
62 SqlCall permutedCall = callBinding.permutedCall();
63 SqlNode permutedOperand = permutedCall.operand(iFormalOperand);
69 type = callBinding.getValidator().deriveType(
70 callBinding.getScope(), permutedOperand);
71 }
catch (Exception e) {
74 SqlTypeName
typeName = type.getSqlTypeName();
75 SqlTypeFamily formalTypeFamily =
76 toSqlTypeName(tf.
getArgTypes().get(iFormalOperand)).getFamily();
78 if (typeName == SqlTypeName.CURSOR) {
79 SqlCall cursorCall = (SqlCall) permutedOperand;
80 RelDataType cursorType = callBinding.getValidator().deriveType(
81 callBinding.getScope(), cursorCall.operand(0));
84 return formalTypeFamily.getTypeNames().
contains(typeName);
89 Set<ExtTableFunction> candidateOverloads =
new HashSet<ExtTableFunction>(
92 for (SqlNode operand : callBinding.getCall().getOperandList()) {
93 if (operand != null && operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
94 final SqlCall assignmentCall = (SqlCall) operand;
95 final SqlIdentifier
id = assignmentCall.operand(1);
96 final String paramName = id.getSimple();
97 if (!candidateOverloads.stream().anyMatch(
98 tf -> tf.getParamNames().
contains(paramName))) {
106 candidateOverloads.removeIf(
107 tf -> tf.getArgTypes().size() != callBinding.getOperandCount());
109 SqlNode[] operandArray =
new SqlNode[callBinding.getCall().getOperandList().size()];
110 for (Ord<SqlNode> arg : Ord.zip(callBinding.getCall().getOperandList())) {
111 operandArray[arg.i] = arg.e;
117 HashMap<ExtTableFunction, SqlCallBinding> candidateBindings =
118 new HashMap<>(candidateOverloads.size());
120 SqlBasicCall newCall =
new SqlBasicCall(
121 tf, operandArray, callBinding.getCall().getParserPosition());
122 SqlCallBinding candidateBinding =
new SqlCallBinding(
123 callBinding.getValidator(), callBinding.getScope(), newCall);
124 candidateBindings.put(tf, candidateBinding);
127 for (
int i = 0; i < operandArray.length; i++) {
129 candidateOverloads.removeIf(tf
131 tf, candidateBindings.get(tf), operandArray[idx], idx));
135 if (candidateOverloads.size() == 0) {
136 if (throwOnFailure) {
144 if (!candidateOverloads.isEmpty()
145 && !candidateOverloads.contains(callBinding.getOperator())) {
147 ((SqlBasicCall) callBinding.getCall()).setOperator(optimal);
155 String formalOperandName = tf.getExtendedParamNames().
get(iFormalOperand);
156 List<ExtArgumentType> formalFieldTypes =
157 tf.getCursorFieldTypes().
get(formalOperandName);
158 List<RelDataTypeField> actualFieldList = actualOperand.getFieldList();
162 if (formalFieldTypes.size() == 0) {
164 "Warning: UDTF has no CURSOR field subtype data. Proceeding assuming CURSOR typechecks.");
170 while (iActual < actualFieldList.size() && iFormal < formalFieldTypes.size()) {
172 SqlTypeName formalType = toSqlTypeName(extType);
173 SqlTypeName actualType = actualFieldList.get(iActual).getValue().getSqlTypeName();
175 if (formalType == SqlTypeName.COLUMN_LIST) {
177 SqlTypeName colListType = toSqlTypeName(colListSubtype);
179 if (actualType != colListType) {
184 int numFormalArgumentsLeft = (formalFieldTypes.size() - 1) - iFormal;
185 while (iActual + colListSize
186 < (actualFieldList.size() - numFormalArgumentsLeft)) {
188 actualFieldList.get(iActual + colListSize).getValue().getSqlTypeName();
189 if (actualType != colListType) {
194 iActual += colListSize - 1;
195 }
else if (formalType == SqlTypeName.ARRAY) {
196 if (actualType != SqlTypeName.ARRAY) {
200 SqlTypeName formalArraySubtype =
201 toSqlTypeName(getValueType(getValueType(extType)));
202 SqlTypeName actualArraySubtype = actualFieldList.get(iActual)
206 if (formalArraySubtype != actualArraySubtype) {
209 }
else if (formalType != actualType) {
216 if (iActual < actualFieldList.size()) {
224 List<SqlOperator> overloads =
new ArrayList<>();
225 opTable.lookupOperatorOverloads(op.getNameAsId(),
226 SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION,
229 SqlNameMatchers.liberal());
231 return overloads.stream()
233 .map(p -> (ExtTableFunction) p)
234 .collect(Collectors.toList());
238 return SqlOperandCountRanges.any();
243 return String.join(System.lineSeparator() +
"\t",
245 .map(tf -> tf.getExtendedSignature())
246 .collect(Collectors.toList()));
250 return Consistency.NONE;
254 SqlCallBinding callBinding, SqlNode operand, String operandName) {
255 return callBinding.getValidator().newValidationError(operand,
257 callBinding.getOperator().getName(), operandName));
261 return callBinding.getValidator().newValidationError(callBinding.permutedCall(),
262 UDTF_ERRORS.typeMismatch(callBinding.getOperator().getName(),
264 callBinding.getValidator(),
265 callBinding.getScope()),
266 System.getProperty(
"line.separator") +
"\t"
267 + callBinding.getOperator().getAllowedSignatures()));
273 SqlCallBinding callBinding, SqlValidator validator, SqlValidatorScope scope) {
274 List<String> signatureList =
new ArrayList<>();
275 for (
final SqlNode operand : callBinding.permutedCall().getOperandList()) {
276 final RelDataType argType = validator.deriveType(scope, operand);
277 if (null == argType) {
279 }
else if (argType.getSqlTypeName() == SqlTypeName.CURSOR) {
280 SqlCall cursorCall = (SqlCall) operand;
281 RelDataType cursorType = callBinding.getValidator().deriveType(
282 callBinding.getScope(), cursorCall.operand(0));
283 StringBuilder cursorTypeName =
new StringBuilder();
284 cursorTypeName.append(
"CURSOR[");
285 for (
int j = 0; j < cursorType.getFieldList().size(); j++) {
287 cursorTypeName.append(
",");
289 cursorTypeName.append(
290 cursorType.getFieldList().
get(j).getType().getSqlTypeName());
292 cursorTypeName.append(
"]");
293 signatureList.add(cursorTypeName.toString());
295 signatureList.add(argType.toString());
298 return SqlUtil.getOperatorSignature(callBinding.getOperator(), signatureList);
303 "No candidate for User-defined Table Function ''{0}'' with input parameter named ''{1}''")
304 ExInst<SqlValidatorException>
308 "Cannot apply User-defined Table Function ''{0}'' to arguments of type {1}. Supported form(s): {2}")
309 ExInst<SqlValidatorException>
310 typeMismatch(String udtf, String call, String overloads);
314 Resources.create(ExtTableFunctionErrors.class);
bool contains(const T &container, const U &element)
CalciteException newExtTableFunctionNameError(SqlCallBinding callBinding, SqlNode operand, String operandName)
final HeavyDBSqlOperatorTable opTable
ExInst< SqlValidatorException > paramNameMismatch(String udtf, String wrongParamName)
ExtTableFunctionTypeChecker(HeavyDBSqlOperatorTable opTable)
List< ExtArgumentType > getArgTypes()
Consistency getConsistency()
CalciteException newExtTableFunctionSignatureError(SqlCallBinding callBinding)
static final ExtTableFunctionErrors UDTF_ERRORS
SqlOperandCountRange getOperandCountRange()
List< ExtTableFunction > getOperatorOverloads(SqlOperator op)
ExInst< SqlValidatorException > typeMismatch(String udtf, String call, String overloads)
boolean doesCursorOperandTypeMatch(ExtTableFunction tf, int iFormalOperand, RelDataType actualOperand)
boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure)
String getCallSignature(SqlCallBinding callBinding, SqlValidator validator, SqlValidatorScope scope)
std::string typeName(const T *v)
boolean isOptional(int argIndex)
boolean doesOperandTypeMatch(ExtTableFunction tf, SqlCallBinding callBinding, SqlNode node, int iFormalOperand)
String getAllowedSignatures(SqlOperator op, String opName)