Skip to content

Commit 42ed367

Browse files
guojn1githubgxll
authored andcommitted
[fix][core] Hidden columns can be ignored during validation
1 parent d773a6e commit 42ed367

File tree

7 files changed

+117
-20
lines changed

7 files changed

+117
-20
lines changed

core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,30 @@ abstract class AbstractNamespace implements SqlValidatorNamespace {
102102
}
103103
}
104104

105+
@Override public final void validate(RelDataType targetRowType, boolean ignoreImplicitName) {
106+
switch (status) {
107+
case UNVALIDATED:
108+
try {
109+
status = SqlValidatorImpl.Status.IN_PROGRESS;
110+
Preconditions.checkArgument(rowType == null,
111+
"Namespace.rowType must be null before validate has been called");
112+
RelDataType type = validateImpl(targetRowType, ignoreImplicitName);
113+
Preconditions.checkArgument(type != null,
114+
"validateImpl() returned null");
115+
setType(type);
116+
} finally {
117+
status = SqlValidatorImpl.Status.VALID;
118+
}
119+
break;
120+
case IN_PROGRESS:
121+
throw new AssertionError("Cycle detected during type-checking");
122+
case VALID:
123+
break;
124+
default:
125+
throw Util.unexpected(status);
126+
}
127+
}
128+
105129
/**
106130
* Validates this scope and returns the type of the records it returns.
107131
* External users should call {@link #validate}, which uses the
@@ -114,6 +138,10 @@ abstract class AbstractNamespace implements SqlValidatorNamespace {
114138
*/
115139
protected abstract RelDataType validateImpl(RelDataType targetRowType);
116140

141+
protected RelDataType validateImpl(RelDataType targetRowType, boolean ignoreImplicitName) {
142+
return validateImpl(targetRowType);
143+
}
144+
117145
@Override public RelDataType getRowType() {
118146
if (rowType == null) {
119147
validator.validateNamespace(this, validator.unknownType);

core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public SelectNamespace(
6262
return requireNonNull(rowType, "rowType");
6363
}
6464

65+
@Override public RelDataType validateImpl(RelDataType targetRowType, boolean ignoreImplicitName) {
66+
validator.validateSelect(select, targetRowType, ignoreImplicitName);
67+
return requireNonNull(rowType, "rowType");
68+
}
69+
6570
@Override public boolean supportsModality(SqlModality modality) {
6671
return validator.validateModality(select, modality, false);
6772
}

core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ SqlNode validateParameterizedExpression(
156156
SqlNode topNode,
157157
Map<String, RelDataType> nameToTypeMap);
158158

159+
default void validateQuery(SqlNode node, SqlValidatorScope scope,
160+
RelDataType targetRowType, boolean ignoreImplicitName) {
161+
162+
}
159163
/**
160164
* Checks that a query is valid.
161165
*

core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,11 @@ protected SqlNode getTop() {
413413
return parentCursorMap.get(columnListParamName);
414414
}
415415

416+
private boolean expandSelectItem(final SqlNode selectItem, SqlSelect select,
417+
RelDataType targetType, List<SqlNode> selectItems, Set<String> aliases,
418+
List<Map.Entry<String, RelDataType>> fields, boolean includeSystemVars) {
419+
return expandSelectItem(selectItem, select, targetType, selectItems, aliases, fields, includeSystemVars, false);
420+
}
416421
/**
417422
* If <code>selectItem</code> is "*" or "TABLE.*", expands it and returns
418423
* true; otherwise writes the unexpanded item.
@@ -427,10 +432,15 @@ protected SqlNode getTop() {
427432
*/
428433
private boolean expandSelectItem(final SqlNode selectItem, SqlSelect select,
429434
RelDataType targetType, List<SqlNode> selectItems, Set<String> aliases,
430-
List<Map.Entry<String, RelDataType>> fields, boolean includeSystemVars) {
435+
List<Map.Entry<String, RelDataType>> fields, boolean includeSystemVars, boolean ignoreImplicitName) {
431436
final SelectScope scope = (SelectScope) getWhereScope(select);
432437
if (expandStar(selectItems, aliases, fields, includeSystemVars, scope,
433438
selectItem)) {
439+
if (ignoreImplicitName) {
440+
selectItems.removeIf(sqlNode -> sqlNode.toString().contains(IMPLICIT_COL_NAME));
441+
aliases.remove(IMPLICIT_COL_NAME);
442+
fields.removeIf(entry -> entry.getKey().equalsIgnoreCase(IMPLICIT_COL_NAME));
443+
}
434444
return true;
435445
}
436446

@@ -1062,40 +1072,45 @@ private SqlNode validateScopedExpression(
10621072
}
10631073

10641074
@Override public void validateQuery(SqlNode node, SqlValidatorScope scope,
1065-
RelDataType targetRowType) {
1075+
RelDataType targetRowType, boolean ignoreImplicitName) {
10661076
final SqlValidatorNamespace ns = getNamespaceOrThrow(node, scope);
10671077
if (node.getKind() == SqlKind.TABLESAMPLE) {
10681078
List<SqlNode> operands = ((SqlCall) node).getOperandList();
10691079
SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands.get(1));
10701080
if (sampleSpec instanceof SqlSampleSpec.SqlTableSampleSpec) {
10711081
validateFeature(RESOURCE.sQLFeature_T613(), node.getParserPosition());
10721082
} else if (sampleSpec
1073-
instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
1083+
instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
10741084
validateFeature(RESOURCE.sQLFeatureExt_T613_Substitution(),
1075-
node.getParserPosition());
1085+
node.getParserPosition());
10761086
}
10771087
}
10781088

1079-
validateNamespace(ns, targetRowType);
1089+
validateNamespace(ns, targetRowType, ignoreImplicitName);
10801090
switch (node.getKind()) {
1081-
case EXTEND:
1082-
// Until we have a dedicated namespace for EXTEND
1083-
deriveType(requireNonNull(scope, "scope"), node);
1084-
break;
1085-
default:
1086-
break;
1091+
case EXTEND:
1092+
// Until we have a dedicated namespace for EXTEND
1093+
deriveType(requireNonNull(scope, "scope"), node);
1094+
break;
1095+
default:
1096+
break;
10871097
}
10881098
if (node == top) {
10891099
validateModality(node);
10901100
}
10911101
validateAccess(
1092-
node,
1093-
ns.getTable(),
1094-
SqlAccessEnum.SELECT);
1102+
node,
1103+
ns.getTable(),
1104+
SqlAccessEnum.SELECT);
10951105

10961106
validateSnapshot(node, scope, ns);
10971107
}
10981108

1109+
@Override public void validateQuery(SqlNode node, SqlValidatorScope scope,
1110+
RelDataType targetRowType) {
1111+
validateQuery(node, scope, targetRowType, false);
1112+
}
1113+
10991114
/**
11001115
* Validates a namespace.
11011116
*
@@ -1112,6 +1127,15 @@ protected void validateNamespace(final SqlValidatorNamespace namespace,
11121127
}
11131128
}
11141129

1130+
protected void validateNamespace(final SqlValidatorNamespace namespace,
1131+
RelDataType targetRowType, boolean ignoreImplicitName) {
1132+
namespace.validate(targetRowType, ignoreImplicitName);
1133+
SqlNode node = namespace.getNode();
1134+
if (node != null) {
1135+
setValidatedNodeType(node, namespace.getType());
1136+
}
1137+
}
1138+
11151139
@Override public SqlValidatorScope getEmptyScope() {
11161140
return new EmptyScope(this);
11171141
}
@@ -3796,6 +3820,12 @@ private RelDataType validateCommonInputJoinColumn(SqlIdentifier id,
37963820
return field.getType();
37973821
}
37983822

3823+
protected void validateSelect(
3824+
SqlSelect select,
3825+
RelDataType targetRowType) {
3826+
validateSelect(select, targetRowType, false);
3827+
}
3828+
37993829
/**
38003830
* Validates a SELECT statement.
38013831
*
@@ -3805,7 +3835,7 @@ private RelDataType validateCommonInputJoinColumn(SqlIdentifier id,
38053835
*/
38063836
protected void validateSelect(
38073837
SqlSelect select,
3808-
RelDataType targetRowType) {
3838+
RelDataType targetRowType, boolean ignoreImplicitName) {
38093839
assert targetRowType != null;
38103840
// Namespace is either a select namespace or a wrapper around one.
38113841
final SelectNamespace ns =
@@ -3877,7 +3907,7 @@ protected void validateSelect(
38773907
// depend on the GROUP BY list, or the window function might reference
38783908
// window name in the WINDOW clause etc.
38793909
final RelDataType rowType =
3880-
validateSelectList(selectItems, select, targetRowType);
3910+
validateSelectList(selectItems, select, targetRowType, ignoreImplicitName);
38813911
ns.setType(rowType);
38823912
validateHavingClause(select);
38833913

@@ -4642,7 +4672,7 @@ protected void validateHavingClause(SqlSelect select) {
46424672
protected RelDataType validateSelectList(
46434673
final SqlNodeList selectItems,
46444674
SqlSelect select,
4645-
RelDataType targetRowType) {
4675+
RelDataType targetRowType, boolean ignoreImplicitName) {
46464676
// First pass, ensure that aliases are unique. "*" and "TABLE.*" items
46474677
// are ignored.
46484678

@@ -4676,7 +4706,7 @@ protected RelDataType validateSelectList(
46764706
expandedSelectItems,
46774707
aliases,
46784708
fieldList,
4679-
false);
4709+
false, ignoreImplicitName);
46804710
}
46814711
}
46824712
expandSelectItemWithNotInGroupBy(expandedSelectItems, selectScope);
@@ -4869,7 +4899,7 @@ protected RelDataType createTargetRowType(
48694899
final SqlNode source = insert.getSource();
48704900
if (source instanceof SqlSelect) {
48714901
final SqlSelect sqlSelect = (SqlSelect) source;
4872-
validateSelect(sqlSelect, targetRowType);
4902+
validateSelect(sqlSelect, targetRowType, true);
48734903
} else {
48744904
final SqlValidatorScope scope = scopes.get(source);
48754905
requireNonNull(scope, "scope");

core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ public interface SqlValidatorNamespace {
115115
*/
116116
void validate(RelDataType targetRowType);
117117

118+
default void validate(RelDataType targetRowType, boolean ignoreImplicitName) {
119+
120+
}
121+
118122
/**
119123
* Returns the parse tree node at the root of this namespace.
120124
*

core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public class WithNamespace extends AbstractNamespace {
5656
}
5757
final SqlValidatorScope scope2 =
5858
validator.getWithScope(Util.last(with.withList));
59-
validator.validateQuery(with.body, scope2, targetRowType);
59+
validator.validateQuery(with.body, scope2, targetRowType, true);
6060
final RelDataType rowType = validator.getValidatedNodeType(with.body);
6161
validator.setValidatedNodeType(with, rowType);
6262
return rowType;

core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
import static org.apache.calcite.sql.SqlUtil.stripAs;
116116

117117
import static java.util.Objects.requireNonNull;
118+
import static org.apache.calcite.sql.validate.SqlValidatorImpl.IMPLICIT_COL_NAME;
118119
import static org.apache.calcite.sql.validate.SqlValidatorImpl.isImplicitKey;
119120
import static org.apache.calcite.util.Static.RESOURCE;
120121

@@ -3823,11 +3824,36 @@ protected RelNode convertInsert(SqlInsert call) {
38233824
assert targetRowType != null;
38243825
RelNode sourceRel =
38253826
convertQueryRecursive(call.getSource(), true, targetRowType).project();
3827+
if (sourceRel instanceof LogicalProject && call.getSource() instanceof SqlSelect) {
3828+
sourceRel = ignoreImplicitCol((LogicalProject) sourceRel);
3829+
}
38263830
RelNode massagedRel = convertColumnList(call, sourceRel);
38273831

38283832
return createModify(targetTable, massagedRel);
38293833
}
38303834

3835+
public LogicalProject ignoreImplicitCol(LogicalProject logicalProject) {
3836+
int hiddenIdex = -1;
3837+
for (int i = 0; i < logicalProject.getRowType().getFieldNames().size(); i ++) {
3838+
if (IMPLICIT_COL_NAME.equalsIgnoreCase(logicalProject.getRowType().getFieldNames().get(i))) {
3839+
hiddenIdex = i;
3840+
}
3841+
}
3842+
if (hiddenIdex >= 0) {
3843+
List<RexNode> newRexNode = new ArrayList<>();
3844+
List<String> fieldNameList = new ArrayList<>();
3845+
for (int i = 0; i < logicalProject.getProjects().size(); i++) {
3846+
if (i == hiddenIdex) {
3847+
continue;
3848+
}
3849+
newRexNode.add(logicalProject.getProjects().get(i));
3850+
fieldNameList.add(logicalProject.getRowType().getFieldNames().get(i));
3851+
}
3852+
return LogicalProject.create(logicalProject.getInput(), newRexNode, fieldNameList);
3853+
}
3854+
return logicalProject;
3855+
}
3856+
38313857
/** Creates a relational expression to modify a table or modifiable view. */
38323858
private RelNode createModify(RelOptTable targetTable, RelNode source) {
38333859
final ModifiableTable modifiableTable =

0 commit comments

Comments
 (0)