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

BEFORE syntax support for presto engine. #22631

Merged
merged 1 commit into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -217,26 +217,31 @@ public void testTableVersionMisc()
@Test
public void testTableVersionErrors()
{
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF 100", ".* Type integer is invalid. Supported table version AS OF expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF 'bad'", ".* Type varchar\\(3\\) is invalid. Supported table version AS OF expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF CURRENT_DATE", ".* Type date is invalid. Supported table version AS OF expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF CURRENT_TIMESTAMP", ".* Type timestamp with time zone is invalid. Supported table version AS OF expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF 100", ".* Type integer is invalid. Supported table version AS OF/BEFORE expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF 'bad'", ".* Type varchar\\(3\\) is invalid. Supported table version AS OF/BEFORE expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF CURRENT_DATE", ".* Type date is invalid. Supported table version AS OF/BEFORE expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF CURRENT_TIMESTAMP", ".* Type timestamp with time zone is invalid. Supported table version AS OF/BEFORE expression type is BIGINT");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF id", ".* cannot be resolved");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF (SELECT 10000000)", ".* Constant expression cannot contain a subquery");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF NULL", "Table version AS OF expression cannot be NULL for .*");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF NULL", "Table version AS OF/BEFORE expression cannot be NULL for .*");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF " + tab2VersionId1 + " - " + tab2VersionId1, "Iceberg snapshot ID does not exists: 0");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR VERSION AS OF CAST (100 AS BIGINT)", "Iceberg snapshot ID does not exists: 100");

assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF 100", ".* Type integer is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF 'bad'", ".* Type varchar\\(3\\) is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF 100", ".* Type integer is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF 'bad'", ".* Type varchar\\(3\\) is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF id", ".* cannot be resolved");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF (SELECT CURRENT_TIMESTAMP)", ".* Constant expression cannot contain a subquery");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF NULL", "Table version AS OF expression cannot be NULL for .*");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF NULL", "Table version AS OF/BEFORE expression cannot be NULL for .*");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF TIMESTAMP " + "'" + tab2Timestamp1 + "' - INTERVAL '1' MONTH", "No history found based on timestamp for table \"test_tt_schema\".\"test_table_version_tab2\"");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CAST ('2023-01-01' AS TIMESTAMP WITH TIME ZONE)", "No history found based on timestamp for table \"test_tt_schema\".\"test_table_version_tab2\"");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CAST ('2023-01-01' AS TIMESTAMP)", ".* Type timestamp is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CAST ('2023-01-01' AS DATE)", ".* Type date is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CURRENT_DATE", ".* Type date is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF TIMESTAMP '2023-01-01 00:00:00.000'", ".* Type timestamp is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CAST ('2023-01-01' AS TIMESTAMP)", ".* Type timestamp is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CAST ('2023-01-01' AS DATE)", ".* Type date is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF CURRENT_DATE", ".* Type date is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.");
assertQueryFails("SELECT desc FROM " + tableName2 + " FOR TIMESTAMP AS OF TIMESTAMP '2023-01-01 00:00:00.000'", ".* Type timestamp is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.");

assertQueryFails("SELECT desc FROM " + tableName1 + " FOR VERSION BEFORE " + tab1VersionId1 + " ORDER BY 1", ".*Table version BEFORE expression is not supported for .*");
assertQueryFails("SELECT desc FROM " + tableName1 + " FOR SYSTEM_VERSION BEFORE " + tab1VersionId1 + " ORDER BY 1", ".*Table version BEFORE expression is not supported for .*");
assertQueryFails("SELECT desc FROM " + tableName1 + " FOR TIMESTAMP BEFORE TIMESTAMP " + "'" + tab1Timestamp1 + "'" + " ORDER BY 1", ".*Table version BEFORE expression is not supported for .*");
assertQueryFails("SELECT desc FROM " + tableName1 + " FOR SYSTEM_TIME BEFORE TIMESTAMP " + "'" + tab1Timestamp1 + "'" + " ORDER BY 1", ".*Table version BEFORE expression is not supported for .*");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@
import static com.facebook.presto.spi.analyzer.AccessControlRole.TABLE_CREATE;
import static com.facebook.presto.spi.analyzer.AccessControlRole.TABLE_DELETE;
import static com.facebook.presto.spi.analyzer.AccessControlRole.TABLE_INSERT;
import static com.facebook.presto.spi.connector.ConnectorTableVersion.VersionOperator;
import static com.facebook.presto.spi.connector.ConnectorTableVersion.VersionType;
import static com.facebook.presto.spi.function.FunctionKind.AGGREGATE;
import static com.facebook.presto.spi.function.FunctionKind.WINDOW;
Expand Down Expand Up @@ -277,6 +278,9 @@
import static com.facebook.presto.sql.tree.FrameBound.Type.PRECEDING;
import static com.facebook.presto.sql.tree.FrameBound.Type.UNBOUNDED_FOLLOWING;
import static com.facebook.presto.sql.tree.FrameBound.Type.UNBOUNDED_PRECEDING;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator.EQUAL;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator.LESS_THAN;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionType;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionType.TIMESTAMP;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionType.VERSION;
Expand Down Expand Up @@ -1348,7 +1352,7 @@ protected Scope visitTable(Table table, Optional<Scope> scope)

private Optional<TableHandle> getTableHandle(TableColumnMetadata tableColumnsMetadata, Table table, QualifiedObjectName name, Optional<Scope> scope)
{
// Process table version AS OF expression
// Process table version AS OF/BEFORE expression
if (table.getTableVersionExpression().isPresent()) {
return processTableVersion(table, name, scope);
}
Expand All @@ -1357,6 +1361,17 @@ private Optional<TableHandle> getTableHandle(TableColumnMetadata tableColumnsMet
}
}

private VersionOperator toVersionOperator(TableVersionOperator operator)
{
switch (operator) {
case EQUAL:
return VersionOperator.EQUAL;
case LESS_THAN:
return VersionOperator.LESS_THAN;
}
throw new SemanticException(NOT_SUPPORTED, "Table version operator %s not supported." + operator);
}

private VersionType toVersionType(TableVersionType type)
{
switch (type) {
Expand All @@ -1365,35 +1380,39 @@ private VersionType toVersionType(TableVersionType type)
case VERSION:
return VersionType.VERSION;
}
throw new SemanticException(NOT_SUPPORTED, type.toString(), "Table version type not supported.");
throw new SemanticException(NOT_SUPPORTED, "Table version type %s not supported." + type);
}
private Optional<TableHandle> processTableVersion(Table table, QualifiedObjectName name, Optional<Scope> scope)
{
Expression asOfExpr = table.getTableVersionExpression().get().getAsOfExpression();
Expression stateExpr = table.getTableVersionExpression().get().getStateExpression();
TableVersionType tableVersionType = table.getTableVersionExpression().get().getTableVersionType();
ExpressionAnalysis expressionAnalysis = analyzeExpression(asOfExpr, scope.get());
TableVersionOperator tableVersionOperator = table.getTableVersionExpression().get().getTableVersionOperator();
ExpressionAnalysis expressionAnalysis = analyzeExpression(stateExpr, scope.get());
analysis.recordSubqueries(table, expressionAnalysis);
Type asOfExprType = expressionAnalysis.getType(asOfExpr);
if (asOfExprType == UNKNOWN) {
throw new PrestoException(INVALID_ARGUMENTS, format("Table version AS OF expression cannot be NULL for %s", name.toString()));
Type stateExprType = expressionAnalysis.getType(stateExpr);
if (tableVersionOperator == LESS_THAN) {
gupteaj marked this conversation as resolved.
Show resolved Hide resolved
throw new SemanticException(NOT_SUPPORTED, stateExpr, "Table version BEFORE expression is not supported for %s", name.toString());
}
if (stateExprType == UNKNOWN) {
throw new PrestoException(INVALID_ARGUMENTS, format("Table version AS OF/BEFORE expression cannot be NULL for %s", name.toString()));
}
Object evalAsOfExpr = evaluateConstantExpression(asOfExpr, asOfExprType, metadata, session, analysis.getParameters());
Object evalStateExpr = evaluateConstantExpression(stateExpr, stateExprType, metadata, session, analysis.getParameters());
if (tableVersionType == TIMESTAMP) {
if (!(asOfExprType instanceof TimestampWithTimeZoneType)) {
throw new SemanticException(TYPE_MISMATCH, asOfExpr,
"Type %s is invalid. Supported table version AS OF expression type is Timestamp with Time Zone.",
asOfExprType.getDisplayName());
if (!(stateExprType instanceof TimestampWithTimeZoneType)) {
throw new SemanticException(TYPE_MISMATCH, stateExpr,
"Type %s is invalid. Supported table version AS OF/BEFORE expression type is Timestamp with Time Zone.",
stateExprType.getDisplayName());
}
}
if (tableVersionType == VERSION) {
if (!(asOfExprType instanceof BigintType)) {
throw new SemanticException(TYPE_MISMATCH, asOfExpr,
"Type %s is invalid. Supported table version AS OF expression type is BIGINT",
asOfExprType.getDisplayName());
if (!(stateExprType instanceof BigintType)) {
throw new SemanticException(TYPE_MISMATCH, stateExpr,
"Type %s is invalid. Supported table version AS OF/BEFORE expression type is BIGINT",
stateExprType.getDisplayName());
}
}

ConnectorTableVersion tableVersion = new ConnectorTableVersion(toVersionType(tableVersionType), asOfExprType, evalAsOfExpr);
ConnectorTableVersion tableVersion = new ConnectorTableVersion(toVersionType(tableVersionType), toVersionOperator(tableVersionOperator), stateExprType, evalStateExpr);
return metadata.getHandleVersion(session, name, Optional.of(tableVersion));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,12 @@ qualifiedName
;

tableVersionExpression
: FOR tableVersionType=(SYSTEM_TIME | SYSTEM_VERSION | TIMESTAMP | VERSION) AS OF valueExpression #tableVersion
: FOR tableVersionType=(SYSTEM_TIME | SYSTEM_VERSION | TIMESTAMP | VERSION) tableVersionState valueExpression #tableVersion
;

tableVersionState
: AS OF #tableversionasof
| BEFORE #tableversionbefore
;

grantor
Expand Down Expand Up @@ -608,7 +613,7 @@ constraintEnforced
nonReserved
// IMPORTANT: this rule must only contain tokens. Nested rules are not supported. See SqlParser.exitNonReserved
: ADD | ADMIN | ALL | ANALYZE | ANY | ARRAY | ASC | AT
| BERNOULLI
| BEFORE | BERNOULLI
| CALL | CALLED | CASCADE | CATALOGS | COLUMN | COLUMNS | COMMENT | COMMIT | COMMITTED | CURRENT | CURRENT_ROLE
| DATA | DATE | DAY | DEFINER | DESC | DETERMINISTIC | DISABLED | DISTRIBUTED
| ENABLED | ENFORCED | EXCLUDING | EXPLAIN | EXTERNAL
Expand Down Expand Up @@ -645,6 +650,7 @@ ARRAY: 'ARRAY';
AS: 'AS';
ASC: 'ASC';
AT: 'AT';
BEFORE: 'BEFORE';
BERNOULLI: 'BERNOULLI';
BETWEEN: 'BETWEEN';
BY: 'BY';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import java.util.function.Function;

import static com.facebook.presto.sql.SqlFormatter.formatSql;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator.EQUAL;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.lang.String.format;
Expand Down Expand Up @@ -693,7 +694,9 @@ private String joinExpressions(List<Expression> expressions)

protected String visitTableVersion(TableVersionExpression node, Void context)
{
return "FOR " + node.getTableVersionType().name() + " AS OF " + process(node.getAsOfExpression(), context) + " ";
return "FOR " + node.getTableVersionType().name()
+ (node.getTableVersionOperator() == EQUAL ? " AS OF " : " BEFORE ")
+ process(node.getStateExpression(), context) + " ";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@
import static com.facebook.presto.sql.tree.RoutineCharacteristics.NullCallClause;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.NullCallClause.CALLED_ON_NULL_INPUT;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.NullCallClause.RETURNS_NULL_ON_NULL_INPUT;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator.EQUAL;
import static com.facebook.presto.sql.tree.TableVersionExpression.TableVersionOperator.LESS_THAN;
import static com.facebook.presto.sql.tree.TableVersionExpression.timestampExpression;
import static com.facebook.presto.sql.tree.TableVersionExpression.versionExpression;
import static com.google.common.collect.ImmutableList.toImmutableList;
Expand Down Expand Up @@ -1551,10 +1554,10 @@ public Node visitTableVersion(SqlBaseParser.TableVersionContext context)
switch (context.tableVersionType.getType()) {
case SqlBaseLexer.SYSTEM_TIME:
case SqlBaseLexer.TIMESTAMP:
return timestampExpression(getLocation(context), child);
return timestampExpression(getLocation(context), getTableVersionOperator((Token) context.tableVersionState().getChild(0).getPayload()), child);
case SqlBaseLexer.SYSTEM_VERSION:
case SqlBaseLexer.VERSION:
return versionExpression(getLocation(context), child);
return versionExpression(getLocation(context), getTableVersionOperator((Token) context.tableVersionState().getChild(0).getPayload()), child);
default:
throw new UnsupportedOperationException("Unsupported Type: " + context.tableVersionType.getText());
}
Expand Down Expand Up @@ -2285,6 +2288,18 @@ private static ConstraintType getConstraintType(Token token)
throw new IllegalArgumentException("Unsupported constraint type: " + token.getText());
}

private static TableVersionOperator getTableVersionOperator(Token token)
{
switch (token.getType()) {
case SqlBaseLexer.AS:
return EQUAL;
case SqlBaseLexer.BEFORE:
return LESS_THAN;
}

throw new IllegalArgumentException("Unsupported table version operator: " + token.getText());
}

private static ArithmeticBinaryExpression.Operator getArithmeticBinaryOperator(Token operator)
{
switch (operator.getType()) {
Expand Down
Loading
Loading