Skip to content

Commit

Permalink
Preverse LATERAL keyword during validation (#98)
Browse files Browse the repository at this point in the history
* attempt

* comment

* preserve lateral

* c

* clean up + add lateral to namespace

* document changes

* doc
  • Loading branch information
KevinGe00 authored Feb 16, 2024
1 parent 912bb67 commit d75a08d
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
Expand Down Expand Up @@ -66,8 +67,14 @@ protected AliasNamespace(
protected RelDataType validateImpl(RelDataType targetRowType) {
final List<String> nameList = new ArrayList<>();
final List<SqlNode> operands = call.getOperandList();
final SqlValidatorNamespace childNs =
validator.getNamespace(operands.get(0));
final SqlValidatorNamespace childNs;
// Skip over fetching for LATERAL namespace since they are not registered, use subquery instead
if (operands.get(0).getKind() == SqlKind.LATERAL) {
SqlNode lateral = operands.get(0);
childNs = validator.getNamespace(((SqlCall) lateral).operand(0));
} else {
childNs = validator.getNamespace(operands.get(0));
}
final RelDataType rowType = childNs.getRowTypeSansSystemColumns();
final List<SqlNode> columnNames = Util.skip(operands, 2);
for (final SqlNode operand : columnNames) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlJoin;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;

/**
Expand All @@ -41,8 +43,19 @@ class JoinNamespace extends AbstractNamespace {
protected RelDataType validateImpl(RelDataType targetRowType) {
RelDataType leftType =
validator.getNamespace(join.getLeft()).getRowType();

// Since LATERALS are used preceding subqueries appearing in FROM to allow the subquery to
// reference columns provided by preceding FROM items, LATERALS will only appear on the right side of a join.
SqlNode right;
if (join.getRight().getKind() == SqlKind.LATERAL) {
// Skip over fetching for LATERAL's name space since they are not registered
right = ((SqlCall) join.getRight()).operand(0);
} else {
right = join.getRight();
}

RelDataType rightType =
validator.getNamespace(join.getRight()).getRowType();
validator.getNamespace(right).getRowType();
final RelDataTypeFactory typeFactory = validator.getTypeFactory();
switch (join.getJoinType()) {
case LEFT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlJoin;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlLateralOperator;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlMatchRecognize;
import org.apache.calcite.sql.SqlMerge;
Expand Down Expand Up @@ -135,6 +136,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static org.apache.calcite.rel.rel2sql.SqlImplementor.*;
import static org.apache.calcite.sql.SqlUtil.stripAs;
import static org.apache.calcite.util.Static.RESOURCE;

Expand Down Expand Up @@ -1113,6 +1115,7 @@ public SqlValidatorNamespace getNamespace(SqlNode node) {
}
// fall through
case SNAPSHOT:
case LATERAL:
case OVER:
case COLLECTION_TABLE:
case ORDER_BY:
Expand Down Expand Up @@ -1584,7 +1587,14 @@ RelDataType getTableConstructorRowType(
}

public RelDataType getValidatedNodeType(SqlNode node) {
RelDataType type = getValidatedNodeTypeIfKnown(node);
RelDataType type;
if (node.getKind() == SqlKind.LATERAL) {
// Skip over LATERAL
type = getValidatedNodeTypeIfKnown(((SqlCall) node).operand(0));
} else {
type = getValidatedNodeTypeIfKnown(node);
}

if (type == null) {
throw Util.needToImplement(node);
} else {
Expand Down Expand Up @@ -2283,6 +2293,14 @@ private SqlNode registerFrom(
enclosingNode,
alias,
forceNullable);

// Keep preceding "LATERAL" keyword from joins with inner SELECT subquery
if (lateral && kind == SqlKind.SELECT) {
SqlNode lateralNode =
SqlStdOperatorTable.LATERAL.createCall(POS, newNode);
return lateralNode;
}

return newNode;

case OVER:
Expand Down Expand Up @@ -3089,7 +3107,7 @@ public void validateIntervalQualifier(SqlIntervalQualifier qualifier) {

/**
* Validates the FROM clause of a query, or (recursively) a child node of
* the FROM clause: AS, OVER, JOIN, VALUES, or sub-query.
* the FROM clause: AS, OVER, JOIN, LATERAL, VALUES, or sub-query.
*
* @param node Node in FROM clause, typically a table or derived
* table
Expand Down Expand Up @@ -3121,14 +3139,23 @@ protected void validateFrom(
case UNNEST:
validateUnnest((SqlCall) node, scope, targetRowType);
break;
case LATERAL:
// Validate subquery that LATERAL precedes
validateQuery(((SqlCall) node).operand(0), scope, targetRowType);
break;
default:
validateQuery(node, scope, targetRowType);
break;
}

// Validate the namespace representation of the node, just in case the
// validation did not occur implicitly.
getNamespace(node, scope).validate(targetRowType);
if (node.getKind() == SqlKind.LATERAL) {
// Skip over fetching for LATERAL namespace since they are not registered, use subquery instead
getNamespace(((SqlCall) node).operand(0), scope).validate(targetRowType);
} else {
getNamespace(node, scope).validate(targetRowType);
}
}

protected void validateOver(SqlCall call, SqlValidatorScope scope) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,11 @@ protected void convertFrom(
return;
}

// Skip over LATERAL conversion
if (from.getKind() == SqlKind.LATERAL) {
from = ((SqlCall) from).operand(0);
}

final SqlCall call;
final SqlNode[] operands;
switch (from.getKind()) {
Expand Down

0 comments on commit d75a08d

Please sign in to comment.