This is an automated email from the ASF dual-hosted git repository.
zabetak pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 7b8b2b9604 [CALCITE-4972] Subfields of array columns containing
structs are not qualified in getFieldOrigins
7b8b2b9604 is described below
commit 7b8b2b96041d0cf7bf69cae336659087739fa495
Author: Mark Grey <[email protected]>
AuthorDate: Fri Jan 7 16:22:10 2022 -0500
[CALCITE-4972] Subfields of array columns containing structs are not
qualified in getFieldOrigins
Close apache/calcite#2683
---
.../calcite/sql/validate/SqlValidatorImpl.java | 16 +++++++++++++
.../calcite/sql/validate/UnnestNamespace.java | 27 ++++++++++++++++++++++
.../org/apache/calcite/test/SqlValidatorTest.java | 13 +++++++++++
3 files changed, 56 insertions(+)
diff --git
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index c53803e8fd..cd272f649b 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -6145,6 +6145,13 @@ public class SqlValidatorImpl implements
SqlValidatorWithHints {
scope.fullyQualify((SqlIdentifier) selectItem);
SqlValidatorNamespace namespace = requireNonNull(qualified.namespace,
() -> "namespace for " + qualified);
+ if (namespace.isWrapperFor(AliasNamespace.class)) {
+ AliasNamespace aliasNs = namespace.unwrap(AliasNamespace.class);
+ SqlNode aliased = requireNonNull(aliasNs.getNode(), () ->
+ "sqlNode for aliasNs " + aliasNs);
+ namespace = getNamespaceOrThrow(stripAs(aliased));
+ }
+
final SqlValidatorTable table = namespace.getTable();
if (table == null) {
return null;
@@ -6152,7 +6159,16 @@ public class SqlValidatorImpl implements
SqlValidatorWithHints {
final List<String> origin =
new ArrayList<>(table.getQualifiedName());
for (String name : qualified.suffix()) {
+ if (namespace.isWrapperFor(UnnestNamespace.class)) {
+ // If identifier is drawn from a repeated subrecord via unnest,
add name of array field
+ UnnestNamespace unnestNamespace =
namespace.unwrap(UnnestNamespace.class);
+ final SqlQualified columnUnnestedFrom =
unnestNamespace.getColumnUnnestedFrom(name);
+ if (columnUnnestedFrom != null) {
+ origin.addAll(columnUnnestedFrom.suffix());
+ }
+ }
namespace = namespace.lookupChild(name);
+
if (namespace == null) {
return null;
}
diff --git
a/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
b/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
index 531ba53a90..f3e732d993 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java
@@ -64,6 +64,33 @@ class UnnestNamespace extends AbstractNamespace {
return null;
}
+ /**
+ * Given a field name from SelectScope, find the column in this
+ * UnnestNamespace it originates from.
+ *
+ * @param queryFieldName Name of column
+ * @return A SqlQualified if subfield comes from this unnest, null if not
found
+ */
+ @Nullable SqlQualified getColumnUnnestedFrom(String queryFieldName) {
+ for (SqlNode operand : unnest.getOperandList()) {
+ // Ignore operands that are inline ARRAY[] literals
+ if (operand instanceof SqlIdentifier) {
+ final SqlIdentifier id = (SqlIdentifier) operand;
+ final SqlQualified qualified = this.scope.fullyQualify(id);
+ RelDataType dataType =
this.scope.resolveColumn(qualified.suffix().get(0), id);
+ if (dataType != null) {
+ RelDataType repeatedEntryType = dataType.getComponentType();
+ if (repeatedEntryType != null
+ && repeatedEntryType.isStruct()
+ && repeatedEntryType.getFieldNames().contains(queryFieldName)) {
+ return qualified;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
@Override protected RelDataType validateImpl(RelDataType targetRowType) {
// Validate the call and its arguments, and infer the return type.
validator.validateCall(unnest, scope);
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 00dd5e5d7b..be16adca82 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -9210,6 +9210,19 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
+ " CATALOG.SALES.EMP.HIREDATE,"
+ " null,"
+ " null}"));
+
+ sql("select e.empno from dept_nested, unnest(employees) as e")
+ .assertFieldOrigin(
+ is("{CATALOG.SALES.DEPT_NESTED.EMPLOYEES.EMPNO}"));
+
+ sql("select * from UNNEST(ARRAY['a', 'b'])")
+ .assertFieldOrigin(is("{null}"));
+
+ sql("select * from UNNEST(ARRAY['a', 'b'], ARRAY['d', 'e'])")
+ .assertFieldOrigin(is("{null, null}"));
+
+ sql("select dpt.skill.desc from dept_nested as dpt")
+ .assertFieldOrigin(is("{CATALOG.SALES.DEPT_NESTED.SKILL.DESC}"));
}
@Test void testBrackets() {