Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CALCITE-1426] Support customized star expansion in Table #307

Closed
wants to merge 8 commits into from
@@ -0,0 +1,42 @@
/*
* 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.calcite.schema;

import java.util.List;

/**
* Extension to {@link Table} that specifies a list of column names for
* custom star expansion. The columns specified in the list can be any
* top-level column from the Table or any field or nested field under a
* top-level column, thus each column name is returned as a list of String
* objects representing the full name of the column or field. This expansion
* list will also be used as target columns in INSERT if the original target
* column list is not present.
*
* <p>It is optional for a Table to implement this interface. If Table does
* not implement this interface, star expansion will be performed in the
* default way according to the Table's row type.</p>
*
* <p><strong>NOTE: This class is experimental and subject to
* change/removal without notice</strong>.</p>
*/
public interface CustomExpansionTable extends Table {
/** Returns a list of column names for custom star expansion. */
List<List<String>> getCustomStarExpansion();
}

// End CustomExpansionTable.java
10 changes: 0 additions & 10 deletions core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
Expand Up @@ -258,16 +258,6 @@ public SqlIdentifier plus(String name, SqlParserPos pos) {
return new SqlIdentifier(names, collation, pos2, componentPositions);
}

/**
* Creates an identifier that consists of this identifier plus a wildcard star.
* Does not modify this identifier.
*/
public SqlIdentifier plusStar() {
final SqlIdentifier id = this.plus("*", SqlParserPos.ZERO);
return new SqlIdentifier(Lists.transform(id.names, STAR_TO_EMPTY), null, id.pos,
id.componentPositions);
}

/** Creates an identifier that consists of all but the last {@code n}
* name segments of this one. */
public SqlIdentifier skipLast(int n) {
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlInsert.java
Expand Up @@ -120,6 +120,10 @@ public SqlNodeList getTargetColumnList() {
return columnList;
}

public void setTargetColumnList(SqlNodeList columnList) {
this.columnList = columnList;
}

public final SqlNode getModifierNode(SqlInsertKeyword modifier) {
for (SqlNode keyword : keywords) {
SqlInsertKeyword keyword2 =
Expand Down
Expand Up @@ -201,6 +201,13 @@ protected void validateNamespace(final SqlValidatorNamespace namespace,
return true;
}

public boolean shouldUseCustomStarExpansion() {
// Disable custom star expansion otherwise SqlValidatorNamespace.getTable()
// could be called on a SqlValidatorNamespace that was not successfully
// validated.
return false;
}

protected boolean shouldAllowOverRelation() {
return true; // no reason not to be lenient
}
Expand Down
Expand Up @@ -616,6 +616,13 @@ void setValidatedNodeType(
*/
boolean shouldExpandIdentifiers();

/**
* Returns whether to use a Table's custom star expansion.
*
* @return true if custom star expansion should be used; false otherwise.
*/
boolean shouldUseCustomStarExpansion();

/**
* Enables or disables rewrite of "macro-like" calls such as COALESCE.
*
Expand Down
Expand Up @@ -19,6 +19,7 @@
import org.apache.calcite.config.NullCollation;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.prepare.Prepare;
import org.apache.calcite.rel.type.DynamicRecordType;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
Expand All @@ -29,6 +30,7 @@
import org.apache.calcite.runtime.CalciteException;
import org.apache.calcite.runtime.Feature;
import org.apache.calcite.runtime.Resources;
import org.apache.calcite.schema.CustomExpansionTable;
import org.apache.calcite.schema.Table;
import org.apache.calcite.sql.JoinConditionType;
import org.apache.calcite.sql.JoinType;
Expand Down Expand Up @@ -460,26 +462,42 @@ private boolean expandStar(List<SqlNode> selectItems, Set<String> aliases,
scope,
includeSystemVars);
} else {
final SqlNode from = p.right.getNode();
final SqlValidatorNamespace fromNs = getNamespace(from, scope);
assert fromNs != null;
final RelDataType rowType = fromNs.getRowType();
for (RelDataTypeField field : rowType.getFieldList()) {
String columnName = field.getName();

// TODO: do real implicit collation here
final SqlIdentifier exp =
new SqlIdentifier(
ImmutableList.of(p.left, columnName),
startPosition);
addOrExpandField(
selectItems,
aliases,
types,
includeSystemVars,
scope,
exp,
field);
final List<List<String>> customStarExpansion =
getCustomStarExpansion(p.right);
if (customStarExpansion != null) {
for (List<String> names : customStarExpansion) {
SqlIdentifier exp = new SqlIdentifier(
Lists.asList(p.left, names.toArray(new String[names.size()])),
startPosition);
addToSelectList(
selectItems,
aliases,
types,
exp,
scope,
includeSystemVars);
}
} else {
final SqlNode from = p.right.getNode();
final SqlValidatorNamespace fromNs = getNamespace(from, scope);
assert fromNs != null;
final RelDataType rowType = fromNs.getRowType();
for (RelDataTypeField field : rowType.getFieldList()) {
String columnName = field.getName();

// TODO: do real implicit collation here
final SqlNode exp =
new SqlIdentifier(
ImmutableList.of(p.left, columnName),
startPosition);
addToSelectList(
selectItems,
aliases,
types,
exp,
scope,
includeSystemVars);
}
}
}
}
Expand Down Expand Up @@ -512,14 +530,13 @@ private boolean expandStar(List<SqlNode> selectItems, Set<String> aliases,
String columnName = field.getName();

// TODO: do real implicit collation here
addOrExpandField(
addToSelectList(
selectItems,
aliases,
types,
includeSystemVars,
scope,
prefixId.plus(columnName, startPosition),
field);
scope,
includeSystemVars);
}
} else {
throw newValidationError(prefixId, RESOURCE.starRequiresRecordType());
Expand All @@ -528,33 +545,18 @@ private boolean expandStar(List<SqlNode> selectItems, Set<String> aliases,
}
}

private boolean addOrExpandField(List<SqlNode> selectItems, Set<String> aliases,
List<Map.Entry<String, RelDataType>> types, boolean includeSystemVars,
SelectScope scope, SqlIdentifier id, RelDataTypeField field) {
switch (field.getType().getStructKind()) {
case PEEK_FIELDS:
case PEEK_FIELDS_DEFAULT:
final SqlNode starExp = id.plusStar();
expandStar(
selectItems,
aliases,
types,
includeSystemVars,
scope,
starExp);
return true;

default:
addToSelectList(
selectItems,
aliases,
types,
id,
scope,
includeSystemVars);
private List<List<String>> getCustomStarExpansion(SqlValidatorNamespace ns) {
if (!shouldUseCustomStarExpansion()) {
return null;
}

return false;
final SqlValidatorTable table = ns.getTable();
if (table instanceof Prepare.PreparingTable) {
Table t = ((Prepare.PreparingTable) table).unwrap(Table.class);
if (t instanceof CustomExpansionTable) {
return ((CustomExpansionTable) t).getCustomStarExpansion();
}
}
return null;
}

public SqlNode validate(SqlNode topNode) {
Expand Down Expand Up @@ -1759,6 +1761,10 @@ public boolean shouldExpandIdentifiers() {
return expandIdentifiers;
}

public boolean shouldUseCustomStarExpansion() {
return true;
}

protected boolean shouldAllowIntermediateOrderBy() {
return true;
}
Expand Down Expand Up @@ -3734,6 +3740,11 @@ public void validateInsert(SqlInsert insert) {
validateNamespace(targetNamespace, unknownType);
SqlValidatorTable table = targetNamespace.getTable();

// If the INSERT does not have a target column list and the target
// table specifies a custom star expansion list, we will set the new
// target column list as the star expansion list.
rewriteTargetColumnList(insert, targetNamespace);

// INSERT has an optional column name list. If present then
// reduce the rowtype to the columns specified. If not present
// then the entire target rowtype is used.
Expand Down Expand Up @@ -3771,6 +3782,22 @@ public void validateInsert(SqlInsert insert) {
validateAccess(insert.getTargetTable(), table, SqlAccessEnum.INSERT);
}

private void rewriteTargetColumnList(
SqlInsert insert, SqlValidatorNamespace ns) {
final List<List<String>> customStarExpansion = getCustomStarExpansion(ns);
if (customStarExpansion == null) {
return;
}

final List<SqlNode> targetColumnList = new ArrayList<>();
final SqlParserPos startPosition = insert.getParserPosition();
for (List<String> names : customStarExpansion) {
targetColumnList.add(new SqlIdentifier(names, startPosition));
}
insert.setTargetColumnList(
new SqlNodeList(targetColumnList, startPosition));
}

private void checkFieldCount(
SqlNode node,
RelDataType logicalSourceRowType,
Expand Down