This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 759ed475eec [feat](iceberg) change OPTIMIZE TABLE to ALTER TABLE
EXECUTE syntax (#56638)
759ed475eec is described below
commit 759ed475eecced52c02cf7bb4dbd57bef0c3b25a
Author: Socrates <[email protected]>
AuthorDate: Fri Oct 10 16:24:23 2025 +0800
[feat](iceberg) change OPTIMIZE TABLE to ALTER TABLE EXECUTE syntax (#56638)
### What problem does this PR solve?
Issue: https://github.com/apache/doris/issues/56002
Related: #55679
This PR transforms the existing OPTIMIZE TABLE syntax to the more
standard ALTER TABLE EXECUTE action syntax. This change provides a
unified interface for table action operations across different table
engines in Apache Doris.
#### New ALTER TABLE EXECUTE Syntax
```sql
ALTER TABLE [catalog.]database.table
EXECUTE action("key1" = "value1", "key2" = "value2", ...)
[PARTITION (partition_list)]
[WHERE condition]
```
---
.../antlr4/org/apache/doris/nereids/DorisParser.g4 | 10 +-
.../iceberg/action/BaseIcebergAction.java | 10 +-
...ctory.java => IcebergExecuteActionFactory.java} | 12 +-
.../doris/nereids/parser/LogicalPlanBuilder.java | 28 ++--
...TableCommand.java => ExecuteActionCommand.java} | 85 ++++++------
.../BaseExecuteAction.java} | 11 +-
.../ExecuteAction.java} | 16 +--
.../ExecuteActionFactory.java} | 24 ++--
.../trees/plans/visitor/CommandVisitor.java | 6 +-
.../doris/nereids/parser/NereidsParserTest.java | 114 ++++++++++++----
...ctions.out => test_iceberg_execute_actions.out} | 0
....groovy => test_iceberg_execute_actions.groovy} | 152 +++++++++++----------
12 files changed, 267 insertions(+), 201 deletions(-)
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index 005271cf480..95bb67d46da 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -53,7 +53,6 @@ statementBase
| supportedDmlStatement #supportedDmlStatementAlias
| supportedCreateStatement #supportedCreateStatementAlias
| supportedAlterStatement #supportedAlterStatementAlias
- | supportedOptimizeStatement #supportedOptimizeStatementAlias
| materializedViewStatement #materializedViewStatementAlias
| supportedJobStatement #supportedJobStatementAlias
| constraintStatement #constraintStatementAlias
@@ -273,6 +272,8 @@ supportedAlterStatement
properties=propertyClause
#alterStoragePolicy
| ALTER TABLE tableName=multipartIdentifier
alterTableClause (COMMA alterTableClause)*
#alterTable
+ | ALTER TABLE tableName=multipartIdentifier EXECUTE actionName=identifier
+ LEFT_PAREN propertyItemList? RIGHT_PAREN partitionSpec? (WHERE
whereExpression=booleanExpression)? #alterTableExecute
| ALTER TABLE tableName=multipartIdentifier ADD ROLLUP
addRollupClause (COMMA addRollupClause)*
#alterTableAddRollup
| ALTER TABLE tableName=multipartIdentifier DROP ROLLUP
@@ -296,13 +297,6 @@ supportedAlterStatement
passwordOption (COMMENT STRING_LITERAL)?
#alterUser
;
-supportedOptimizeStatement
- : OPTIMIZE TABLE tableName=multipartIdentifier
- (partitionSpec)?
- (WHERE booleanExpression)?
- properties=propertyClause
#optimizeTable
- ;
-
supportedDropStatement
: DROP CATALOG RECYCLE BIN WHERE idType=STRING_LITERAL EQ id=INTEGER_VALUE
#dropCatalogRecycleBin
| DROP ENCRYPTKEY (IF EXISTS)? name=multipartIdentifier
#dropEncryptkey
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/BaseIcebergAction.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/BaseIcebergAction.java
index a0eba0782dc..ddf8a29b441 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/BaseIcebergAction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/BaseIcebergAction.java
@@ -22,17 +22,17 @@ import org.apache.doris.common.UserException;
import org.apache.doris.datasource.iceberg.IcebergExternalTable;
import org.apache.doris.info.PartitionNamesInfo;
import org.apache.doris.nereids.trees.expressions.Expression;
-import
org.apache.doris.nereids.trees.plans.commands.optimize.BaseOptimizeAction;
+import org.apache.doris.nereids.trees.plans.commands.execute.BaseExecuteAction;
import java.util.Map;
import java.util.Optional;
/**
- * Abstract base class for Iceberg-specific OPTIMIZE TABLE actions.
- * This class extends BaseOptimizeAction and provides Iceberg-specific
- * functionality while inheriting common optimization action behavior.
+ * Abstract base class for Iceberg-specific EXECUTE TABLE actions.
+ * This class extends BaseExecuteAction and provides Iceberg-specific
+ * functionality while inheriting common execution action behavior.
*/
-public abstract class BaseIcebergAction extends BaseOptimizeAction {
+public abstract class BaseIcebergAction extends BaseExecuteAction {
protected final IcebergExternalTable icebergTable;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergOptimizeActionFactory.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergExecuteActionFactory.java
similarity index 91%
rename from
fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergOptimizeActionFactory.java
rename to
fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergExecuteActionFactory.java
index 8434254ba34..d9693433950 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergOptimizeActionFactory.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergExecuteActionFactory.java
@@ -21,15 +21,15 @@ import org.apache.doris.common.DdlException;
import org.apache.doris.datasource.iceberg.IcebergExternalTable;
import org.apache.doris.info.PartitionNamesInfo;
import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.plans.commands.optimize.OptimizeAction;
+import org.apache.doris.nereids.trees.plans.commands.execute.ExecuteAction;
import java.util.Map;
import java.util.Optional;
/**
- * Factory for creating Iceberg-specific OPTIMIZE TABLE actions.
+ * Factory for creating Iceberg-specific EXECUTE TABLE actions.
*/
-public class IcebergOptimizeActionFactory {
+public class IcebergExecuteActionFactory {
// Iceberg procedure names (mapped to action types)
public static final String ROLLBACK_TO_SNAPSHOT = "rollback_to_snapshot";
@@ -41,7 +41,7 @@ public class IcebergOptimizeActionFactory {
public static final String REWRITE_DATA_FILES = "rewrite_data_files";
/**
- * Create an Iceberg-specific OptimizeAction instance.
+ * Create an Iceberg-specific ExecuteAction instance.
*
* @param actionType the type of action to create (corresponds to
* Iceberg procedure name)
@@ -50,10 +50,10 @@ public class IcebergOptimizeActionFactory {
* @param partitionNamesInfo partition information
* @param whereCondition where condition for filtering
* @param table the Iceberg table to operate on
- * @return OptimizeAction instance that wraps Iceberg procedure calls
+ * @return ExecuteAction instance that wraps Iceberg procedure calls
* @throws DdlException if action creation fails
*/
- public static OptimizeAction createAction(String actionType, Map<String,
String> properties,
+ public static ExecuteAction createAction(String actionType, Map<String,
String> properties,
Optional<PartitionNamesInfo> partitionNamesInfo,
Optional<Expression> whereCondition,
IcebergExternalTable table) throws DdlException {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index d1527a9ef22..eeeff743ec2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -716,6 +716,7 @@ import
org.apache.doris.nereids.trees.plans.commands.DropUserCommand;
import org.apache.doris.nereids.trees.plans.commands.DropViewCommand;
import org.apache.doris.nereids.trees.plans.commands.DropWorkloadGroupCommand;
import org.apache.doris.nereids.trees.plans.commands.DropWorkloadPolicyCommand;
+import org.apache.doris.nereids.trees.plans.commands.ExecuteActionCommand;
import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
import
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
import org.apache.doris.nereids.trees.plans.commands.ExplainDictionaryCommand;
@@ -730,7 +731,6 @@ import
org.apache.doris.nereids.trees.plans.commands.KillConnectionCommand;
import org.apache.doris.nereids.trees.plans.commands.KillQueryCommand;
import org.apache.doris.nereids.trees.plans.commands.LoadCommand;
import org.apache.doris.nereids.trees.plans.commands.LockTablesCommand;
-import org.apache.doris.nereids.trees.plans.commands.OptimizeTableCommand;
import org.apache.doris.nereids.trees.plans.commands.PauseJobCommand;
import org.apache.doris.nereids.trees.plans.commands.PauseMTMVCommand;
import org.apache.doris.nereids.trees.plans.commands.RecoverDatabaseCommand;
@@ -7056,25 +7056,27 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
}
@Override
- public LogicalPlan visitOptimizeTable(DorisParser.OptimizeTableContext
ctx) {
- TableNameInfo tableName = new
TableNameInfo(visitMultipartIdentifier(ctx.multipartIdentifier()));
+ public LogicalPlan
visitAlterTableExecute(DorisParser.AlterTableExecuteContext ctx) {
+ TableNameInfo tableName = new
TableNameInfo(visitMultipartIdentifier(ctx.tableName));
+ String action = ctx.actionName.getText();
+
+ // Parse partition specification if present
Optional<PartitionNamesInfo> partitionNamesInfo = Optional.empty();
if (ctx.partitionSpec() != null) {
Pair<Boolean, List<String>> partitionSpec =
visitPartitionSpec(ctx.partitionSpec());
partitionNamesInfo = Optional.of(new
PartitionNamesInfo(partitionSpec.first, partitionSpec.second));
}
- Optional<Expression> whereCondition = ctx.booleanExpression() == null
+
+ // Parse WHERE condition if present
+ Optional<Expression> whereCondition = ctx.whereExpression == null
? Optional.empty()
- : Optional.of((Expression) visit(ctx.booleanExpression()));
- Map<String, String> properties = ctx.properties == null
- ? Maps.newHashMap()
- : visitPropertyClause(ctx.properties);
+ : Optional.of((Expression) visit(ctx.whereExpression));
- return new OptimizeTableCommand(
- tableName,
- partitionNamesInfo,
- whereCondition,
- properties);
+ Map<String, String> props = ctx.propertyItemList() == null
+ ? Maps.newHashMap()
+ : visitPropertyItemList(ctx.propertyItemList());
+ return new ExecuteActionCommand(
+ tableName, action, props, partitionNamesInfo, whereCondition);
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/OptimizeTableCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteActionCommand.java
similarity index 65%
rename from
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/OptimizeTableCommand.java
rename to
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteActionCommand.java
index f4f970fdba2..b0dbff95ba4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/OptimizeTableCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteActionCommand.java
@@ -30,8 +30,8 @@ import org.apache.doris.info.PartitionNamesInfo;
import org.apache.doris.info.TableNameInfo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.commands.optimize.OptimizeAction;
-import
org.apache.doris.nereids.trees.plans.commands.optimize.OptimizeActionFactory;
+import org.apache.doris.nereids.trees.plans.commands.execute.ExecuteAction;
+import
org.apache.doris.nereids.trees.plans.commands.execute.ExecuteActionFactory;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ResultSet;
@@ -42,29 +42,38 @@ import java.util.Objects;
import java.util.Optional;
/**
- * OPTIMIZE TABLE tbl [PARTITION(p1, p2, ...)] [WHERE expr] PROPERTIES("action"
- * = "xx", ...)
+ * ALTER TABLE table EXECUTE action("k" = "v", ...) [PARTITION
(partition_list)]
+ * [WHERE condition]
*/
-public class OptimizeTableCommand extends Command implements ForwardWithSync {
+public class ExecuteActionCommand extends Command implements ForwardWithSync {
private final TableNameInfo tableNameInfo;
- private final Optional<PartitionNamesInfo> partitionNamesInfo;
- private final Optional<Expression> whereClause;
+ private final String actionName;
private final Map<String, String> properties;
-
- public OptimizeTableCommand(TableNameInfo tableNameInfo,
- Optional<PartitionNamesInfo> partitionNamesInfo,
- Optional<Expression> whereClause,
- Map<String, String> properties) {
+ private final Optional<PartitionNamesInfo> partitionNamesInfo;
+ private final Optional<Expression> whereCondition;
+
+ /**
+ * Constructor for ExecuteActionCommand.
+ *
+ * @param tableNameInfo table name information
+ * @param actionName name of the action to execute
+ * @param properties action properties as key-value pairs
+ * @param partitionNamesInfo optional partition information
+ * @param whereCondition optional where condition for filtering
+ */
+ public ExecuteActionCommand(TableNameInfo tableNameInfo, String actionName,
+ Map<String, String> properties, Optional<PartitionNamesInfo>
partitionNamesInfo,
+ Optional<Expression> whereCondition) {
super(PlanType.OPTIMIZE_TABLE_COMMAND);
this.tableNameInfo = Objects.requireNonNull(tableNameInfo,
"tableNameInfo is null");
- this.partitionNamesInfo = Objects.requireNonNull(partitionNamesInfo,
"partitionNamesInfo is null");
- this.whereClause = Objects.requireNonNull(whereClause, "whereClause is
null");
+ this.actionName = Objects.requireNonNull(actionName, "actionName is
null");
this.properties = Objects.requireNonNull(properties, "properties is
null");
+ this.partitionNamesInfo = Objects.requireNonNull(partitionNamesInfo,
"partitionNamesInfo is null");
+ this.whereCondition = Objects.requireNonNull(whereCondition,
"whereCondition is null");
}
@Override
public void run(ConnectContext ctx, StmtExecutor executor) throws
Exception {
- // Get the table
CatalogIf<?> catalog =
Env.getCurrentEnv().getCatalogMgr().getCatalog(tableNameInfo.getCtl());
if (catalog == null) {
throw new AnalysisException("Catalog " + tableNameInfo.getCtl() +
" does not exist");
@@ -81,44 +90,30 @@ public class OptimizeTableCommand extends Command
implements ForwardWithSync {
}
if (!(table instanceof ExternalTable)) {
- throw new AnalysisException("OPTIMIZE TABLE is currently only
supported for external tables");
+ throw new AnalysisException("ALTER TABLE EXECUTE is currently only
supported for external tables");
}
- ExternalTable externalTable = (ExternalTable) table;
-
- // Get action type from properties
- String actionType = properties.get("action");
- if (actionType == null || actionType.isEmpty()) {
- throw new AnalysisException("OPTIMIZE TABLE requires 'action'
property to be specified");
- }
-
- // Create and execute the appropriate action
try {
- OptimizeAction action = OptimizeActionFactory.createAction(
- actionType, properties, partitionNamesInfo, whereClause,
externalTable);
+ ExecuteAction action = ExecuteActionFactory.createAction(
+ actionName, properties, partitionNamesInfo,
whereCondition, table);
- if (!action.isSupported(externalTable)) {
- throw new AnalysisException("Action '" + actionType + "' is
not supported for this table engine");
+ if (!action.isSupported(table)) {
+ throw new AnalysisException("Action '" + actionName + "' is
not supported for this table engine");
}
action.validate(tableNameInfo, ctx.getCurrentUserIdentity());
-
- // Execute action and check for results
- ResultSet resultSet = action.execute(externalTable);
-
- // If action returns results, send them to the client
+ ResultSet resultSet = action.execute(table);
if (resultSet != null) {
executor.sendResultSet(resultSet);
}
-
} catch (UserException e) {
- throw new DdlException("Failed to execute OPTIMIZE TABLE: " +
e.getMessage(), e);
+ throw new DdlException("Failed to execute action: " +
e.getMessage(), e);
}
}
@Override
public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
- return visitor.visitOptimizeTableCommand(this, context);
+ return visitor.visitExecuteActionCommand(this, context);
}
@Override
@@ -130,15 +125,19 @@ public class OptimizeTableCommand extends Command
implements ForwardWithSync {
return tableNameInfo;
}
- public Optional<PartitionNamesInfo> getPartitionNamesInfo() {
- return partitionNamesInfo;
- }
-
- public Optional<Expression> getWhereClause() {
- return whereClause;
+ public String getActionName() {
+ return actionName;
}
public Map<String, String> getProperties() {
return properties;
}
+
+ public Optional<PartitionNamesInfo> getPartitionNamesInfo() {
+ return partitionNamesInfo;
+ }
+
+ public Optional<Expression> getWhereCondition() {
+ return whereCondition;
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/BaseOptimizeAction.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/BaseExecuteAction.java
similarity index 95%
rename from
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/BaseOptimizeAction.java
rename to
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/BaseExecuteAction.java
index 9ee86bf6a63..840e5039dfa 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/BaseOptimizeAction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/BaseExecuteAction.java
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package org.apache.doris.nereids.trees.plans.commands.optimize;
+package org.apache.doris.nereids.trees.plans.commands.execute;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Column;
@@ -44,9 +44,9 @@ import java.util.Map;
import java.util.Optional;
/**
- * Abstract base class for all OPTIMIZE TABLE actions.
+ * Abstract base class for all EXECUTE TABLE actions.
*/
-public abstract class BaseOptimizeAction implements OptimizeAction {
+public abstract class BaseExecuteAction implements ExecuteAction {
protected final String actionType;
protected final Map<String, String> properties;
@@ -59,7 +59,7 @@ public abstract class BaseOptimizeAction implements
OptimizeAction {
// ResultSet metadata if the action produces results
protected final ResultSetMetaData resultSetMetaData;
- protected BaseOptimizeAction(String actionType, Map<String, String>
properties,
+ protected BaseExecuteAction(String actionType, Map<String, String>
properties,
Optional<PartitionNamesInfo> partitionNamesInfo,
Optional<Expression> whereCondition) {
this.actionType = actionType;
@@ -67,9 +67,6 @@ public abstract class BaseOptimizeAction implements
OptimizeAction {
this.partitionNamesInfo = partitionNamesInfo;
this.whereCondition = whereCondition;
- // Add OPTIMIZE TABLE specific allowed arguments
- this.namedArguments.addAllowedArgument("action");
-
// Register arguments specific to this action
registerArguments();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/OptimizeAction.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/ExecuteAction.java
similarity index 88%
rename from
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/OptimizeAction.java
rename to
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/ExecuteAction.java
index d1b1dfeef21..66de1e2612f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/OptimizeAction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/ExecuteAction.java
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package org.apache.doris.nereids.trees.plans.commands.optimize;
+package org.apache.doris.nereids.trees.plans.commands.execute;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.TableIf;
@@ -29,12 +29,12 @@ import java.util.Map;
import java.util.Optional;
/**
- * Interface for all OPTIMIZE TABLE actions in Doris.
- * This provides a generic framework for implementing different optimization
+ * Interface for all EXECUTE TABLE actions in Doris.
+ * This provides a generic framework for implementing different execution
* strategies across various table engines (internal tables, external tables,
* etc.).
*/
-public interface OptimizeAction {
+public interface ExecuteAction {
/**
* Validate the action parameters and permissions.
*
@@ -83,16 +83,16 @@ public interface OptimizeAction {
Map<String, String> getProperties();
/**
- * Get partition information if specified.
+ * Get partition names info if specified.
*
- * @return optional partition names info
+ * @return partition names info
*/
Optional<PartitionNamesInfo> getPartitionNamesInfo();
/**
- * Get WHERE condition if specified.
+ * Get where condition if specified.
*
- * @return optional where condition expression
+ * @return where condition
*/
Optional<Expression> getWhereCondition();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/OptimizeActionFactory.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/ExecuteActionFactory.java
similarity index 75%
rename from
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/OptimizeActionFactory.java
rename to
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/ExecuteActionFactory.java
index 08bb7c1642f..33db949ed7f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/optimize/OptimizeActionFactory.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/execute/ExecuteActionFactory.java
@@ -15,13 +15,13 @@
// specific language governing permissions and limitations
// under the License.
-package org.apache.doris.nereids.trees.plans.commands.optimize;
+package org.apache.doris.nereids.trees.plans.commands.execute;
import org.apache.doris.catalog.TableIf;
import org.apache.doris.common.DdlException;
import org.apache.doris.datasource.ExternalTable;
import org.apache.doris.datasource.iceberg.IcebergExternalTable;
-import org.apache.doris.datasource.iceberg.action.IcebergOptimizeActionFactory;
+import org.apache.doris.datasource.iceberg.action.IcebergExecuteActionFactory;
import org.apache.doris.info.PartitionNamesInfo;
import org.apache.doris.nereids.trees.expressions.Expression;
@@ -29,41 +29,41 @@ import java.util.Map;
import java.util.Optional;
/**
- * Factory for creating OPTIMIZE TABLE actions based on table type.
+ * Factory for creating EXECUTE TABLE actions based on table type.
* This factory delegates to specific table engine factories to create
* appropriate action instances, maintaining complete separation between
- * the general OptimizeAction framework and specific table implementations.
+ * the general ExecuteAction framework and specific table implementations.
*/
-public class OptimizeActionFactory {
+public class ExecuteActionFactory {
/**
- * Create an OptimizeAction instance based on the table type and action
type.
+ * Create an ExecuteAction instance based on the table type and action
type.
*
* @param actionType the type of action to create
* @param properties action properties
* @param partitionNamesInfo partition information
* @param whereCondition where condition for filtering
* @param table the table to operate on
- * @return OptimizeAction instance
+ * @return ExecuteAction instance
* @throws DdlException if action creation fails
*/
- public static OptimizeAction createAction(String actionType, Map<String,
String> properties,
+ public static ExecuteAction createAction(String actionType, Map<String,
String> properties,
Optional<PartitionNamesInfo> partitionNamesInfo,
Optional<Expression> whereCondition,
TableIf table) throws DdlException {
// Delegate to specific table engine factories
if (table instanceof IcebergExternalTable) {
- return IcebergOptimizeActionFactory.createAction(actionType,
properties,
+ return IcebergExecuteActionFactory.createAction(actionType,
properties,
partitionNamesInfo, whereCondition, (IcebergExternalTable)
table);
} else if (table instanceof ExternalTable) {
// Handle other external table types in the future
- throw new DdlException("Optimize actions are not supported for
table type: "
+ throw new DdlException("Execute actions are not supported for
table type: "
+ table.getClass().getSimpleName());
} else {
// Handle internal tables in the future
// TODO: Implement internal table action factory
- throw new DdlException("Optimize actions for internal tables are
not yet supported");
+ throw new DdlException("Execute actions for internal tables are
not yet supported");
}
}
@@ -75,7 +75,7 @@ public class OptimizeActionFactory {
*/
public static String[] getSupportedActions(TableIf table) {
if (table instanceof IcebergExternalTable) {
- return IcebergOptimizeActionFactory.getSupportedActions();
+ return IcebergExecuteActionFactory.getSupportedActions();
}
// Add support for other table types in the future
return new String[0];
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
index 8c78e8583f8..5f679090ffe 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
@@ -132,6 +132,7 @@ import
org.apache.doris.nereids.trees.plans.commands.DropViewCommand;
import org.apache.doris.nereids.trees.plans.commands.DropWorkloadGroupCommand;
import org.apache.doris.nereids.trees.plans.commands.DropWorkloadPolicyCommand;
import org.apache.doris.nereids.trees.plans.commands.EmptyCommand;
+import org.apache.doris.nereids.trees.plans.commands.ExecuteActionCommand;
import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
import org.apache.doris.nereids.trees.plans.commands.ExplainDictionaryCommand;
import org.apache.doris.nereids.trees.plans.commands.ExportCommand;
@@ -145,7 +146,6 @@ import
org.apache.doris.nereids.trees.plans.commands.KillConnectionCommand;
import org.apache.doris.nereids.trees.plans.commands.KillQueryCommand;
import org.apache.doris.nereids.trees.plans.commands.LoadCommand;
import org.apache.doris.nereids.trees.plans.commands.LockTablesCommand;
-import org.apache.doris.nereids.trees.plans.commands.OptimizeTableCommand;
import org.apache.doris.nereids.trees.plans.commands.PauseJobCommand;
import org.apache.doris.nereids.trees.plans.commands.PauseMTMVCommand;
import org.apache.doris.nereids.trees.plans.commands.RecoverDatabaseCommand;
@@ -656,8 +656,8 @@ public interface CommandVisitor<R, C> {
return visitCommand(alterTableCommand, context);
}
- default R visitOptimizeTableCommand(OptimizeTableCommand
optimizeTableCommand, C context) {
- return visitCommand(optimizeTableCommand, context);
+ default R visitExecuteActionCommand(ExecuteActionCommand command, C
context) {
+ return visitCommand(command, context);
}
default R visitShowGrantsCommand(ShowGrantsCommand showGrantsCommand, C
context) {
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
index 0d173aed5ce..c8bddd93573 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
@@ -41,9 +41,9 @@ import
org.apache.doris.nereids.trees.plans.commands.CreateMaterializedViewComma
import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand;
import org.apache.doris.nereids.trees.plans.commands.CreateViewCommand;
import org.apache.doris.nereids.trees.plans.commands.DropTableCommand;
+import org.apache.doris.nereids.trees.plans.commands.ExecuteActionCommand;
import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
import
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
-import org.apache.doris.nereids.trees.plans.commands.OptimizeTableCommand;
import org.apache.doris.nereids.trees.plans.commands.ReplayCommand;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalCTE;
@@ -601,38 +601,104 @@ public class NereidsParserTest extends ParserTestBase {
}
@Test
- public void testOptimizeTable() {
+ public void testAlterTableExecute() {
NereidsParser nereidsParser = new NereidsParser();
- // Basic optimize table
- String sql = "optimize table t1 properties('action' = 'compact')";
+ // Basic ALTER TABLE EXECUTE with rewrite_data_files action
+ String sql = "ALTER TABLE t1 EXECUTE
rewrite_data_files(\"target-file-size-bytes\" = \"134217728\")";
LogicalPlan logicalPlan = nereidsParser.parseSingle(sql);
- Assertions.assertInstanceOf(OptimizeTableCommand.class, logicalPlan);
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ ExecuteActionCommand cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("rewrite_data_files", cmd.getActionName());
+ Assertions.assertEquals("134217728",
cmd.getProperties().get("target-file-size-bytes"));
- // Optimize table with partition
- sql = "optimize table t1 partition(p1, p2) properties('action' =
'compact')";
+ // ALTER TABLE EXECUTE with expire_snapshots multiple properties
+ sql = "ALTER TABLE t1 EXECUTE expire_snapshots(\"older_than\" =
\"2024-01-01 00:00:00\", \"retain_last\" = \"5\")";
logicalPlan = nereidsParser.parseSingle(sql);
- Assertions.assertInstanceOf(OptimizeTableCommand.class, logicalPlan);
-
- // Optimize table with where clause
- sql = "optimize table t1 where id > 100 properties('action' =
'compact')";
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("expire_snapshots", cmd.getActionName());
+ Assertions.assertEquals("2024-01-01 00:00:00",
cmd.getProperties().get("older_than"));
+ Assertions.assertEquals("5", cmd.getProperties().get("retain_last"));
+
+ // ALTER TABLE EXECUTE with set_current_snapshot using ref parameter
+ sql = "ALTER TABLE t1 EXECUTE set_current_snapshot(\"ref\" =
\"main\")";
logicalPlan = nereidsParser.parseSingle(sql);
- Assertions.assertInstanceOf(OptimizeTableCommand.class, logicalPlan);
-
- // Optimize table with partition and where clause
- sql = "optimize table t1 partition(p1) where id > 100
properties('action' = 'compact')";
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("set_current_snapshot", cmd.getActionName());
+ Assertions.assertEquals("main", cmd.getProperties().get("ref"));
+ Assertions.assertFalse(cmd.getWhereCondition().isPresent());
+
+ // ALTER TABLE EXECUTE with WHERE clause - simple condition
+ sql = "ALTER TABLE t1 EXECUTE
rewrite_data_files(\"target-file-size-bytes\" = \"134217728\") WHERE id > 100";
logicalPlan = nereidsParser.parseSingle(sql);
- Assertions.assertInstanceOf(OptimizeTableCommand.class, logicalPlan);
-
- // Optimize table with catalog and database
- sql = "optimize table catalog1.db1.t1 properties('action' =
'compact')";
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("rewrite_data_files", cmd.getActionName());
+ Assertions.assertEquals("134217728",
cmd.getProperties().get("target-file-size-bytes"));
+ Assertions.assertTrue(cmd.getWhereCondition().isPresent());
+
+ // ALTER TABLE EXECUTE with WHERE clause - complex condition
+ sql = "ALTER TABLE t1 EXECUTE expire_snapshots(\"older_than\" =
\"2024-01-01 00:00:00\") WHERE partition_col = 'value' AND date_col <
'2024-01-01'";
logicalPlan = nereidsParser.parseSingle(sql);
- Assertions.assertInstanceOf(OptimizeTableCommand.class, logicalPlan);
-
- // Optimize table with multiple properties
- sql = "optimize table t1 properties('action' = 'compact', 'max_files'
= '10')";
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("expire_snapshots", cmd.getActionName());
+ Assertions.assertEquals("2024-01-01 00:00:00",
cmd.getProperties().get("older_than"));
+ Assertions.assertTrue(cmd.getWhereCondition().isPresent());
+
+ // ALTER TABLE EXECUTE with WHERE clause - no properties
+ sql = "ALTER TABLE t1 EXECUTE rollback_to_snapshot(\"snapshot_id\" =
\"3051729675574597004\") WHERE status = 'active'";
+ logicalPlan = nereidsParser.parseSingle(sql);
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("rollback_to_snapshot", cmd.getActionName());
+ Assertions.assertEquals("3051729675574597004",
cmd.getProperties().get("snapshot_id"));
+ Assertions.assertTrue(cmd.getWhereCondition().isPresent());
+
+ // ALTER TABLE EXECUTE with partition specification - single partition
+ sql = "ALTER TABLE t1 EXECUTE
rewrite_data_files(\"target-file-size-bytes\" = \"134217728\") PARTITION (p1)";
+ logicalPlan = nereidsParser.parseSingle(sql);
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("rewrite_data_files", cmd.getActionName());
+ Assertions.assertEquals("134217728",
cmd.getProperties().get("target-file-size-bytes"));
+ Assertions.assertTrue(cmd.getPartitionNamesInfo().isPresent());
+ Assertions.assertEquals(1,
cmd.getPartitionNamesInfo().get().getPartitionNames().size());
+ Assertions.assertEquals("p1",
cmd.getPartitionNamesInfo().get().getPartitionNames().get(0));
+ Assertions.assertFalse(cmd.getPartitionNamesInfo().get().isTemp());
+
+ // ALTER TABLE EXECUTE with partition specification - multiple
partitions
+ sql = "ALTER TABLE t1 EXECUTE expire_snapshots(\"older_than\" =
\"2024-01-01 00:00:00\") PARTITIONS (p1, p2, p3)";
+ logicalPlan = nereidsParser.parseSingle(sql);
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("expire_snapshots", cmd.getActionName());
+ Assertions.assertEquals("2024-01-01 00:00:00",
cmd.getProperties().get("older_than"));
+ Assertions.assertTrue(cmd.getPartitionNamesInfo().isPresent());
+ Assertions.assertEquals(3,
cmd.getPartitionNamesInfo().get().getPartitionNames().size());
+ Assertions.assertFalse(cmd.getPartitionNamesInfo().get().isTemp());
+
+ // ALTER TABLE EXECUTE with temporary partition specification
+ sql = "ALTER TABLE t1 EXECUTE
rewrite_data_files(\"target-file-size-bytes\" = \"134217728\") TEMPORARY
PARTITION (temp_p1)";
+ logicalPlan = nereidsParser.parseSingle(sql);
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("rewrite_data_files", cmd.getActionName());
+ Assertions.assertTrue(cmd.getPartitionNamesInfo().isPresent());
+ Assertions.assertTrue(cmd.getPartitionNamesInfo().get().isTemp());
+ Assertions.assertEquals("temp_p1",
cmd.getPartitionNamesInfo().get().getPartitionNames().get(0));
+
+ // ALTER TABLE EXECUTE with partition and WHERE clause
+ sql = "ALTER TABLE t1 EXECUTE
rewrite_data_files(\"target-file-size-bytes\" = \"134217728\") PARTITION (p1)
WHERE id > 100";
logicalPlan = nereidsParser.parseSingle(sql);
- Assertions.assertInstanceOf(OptimizeTableCommand.class, logicalPlan);
+ Assertions.assertInstanceOf(ExecuteActionCommand.class, logicalPlan);
+ cmd = (ExecuteActionCommand) logicalPlan;
+ Assertions.assertEquals("rewrite_data_files", cmd.getActionName());
+ Assertions.assertTrue(cmd.getPartitionNamesInfo().isPresent());
+ Assertions.assertEquals("p1",
cmd.getPartitionNamesInfo().get().getPartitionNames().get(0));
+ Assertions.assertTrue(cmd.getWhereCondition().isPresent());
}
@Test
diff --git
a/regression-test/data/external_table_p0/iceberg/action/test_iceberg_optimize_actions.out
b/regression-test/data/external_table_p0/iceberg/action/test_iceberg_execute_actions.out
similarity index 100%
rename from
regression-test/data/external_table_p0/iceberg/action/test_iceberg_optimize_actions.out
rename to
regression-test/data/external_table_p0/iceberg/action/test_iceberg_execute_actions.out
diff --git
a/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_optimize_actions.groovy
b/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
similarity index 78%
rename from
regression-test/suites/external_table_p0/iceberg/action/test_iceberg_optimize_actions.groovy
rename to
regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
index 0cd818fe175..94810040e8e 100644
---
a/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_optimize_actions.groovy
+++
b/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
@@ -42,7 +42,7 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
return
}
- String catalog_name = "test_iceberg_optimize_actions_ddl"
+ String catalog_name = "test_iceberg_execute_actions_ddl"
String db_name = "test_db"
String rest_port = context.config.otherConfigs.get("iceberg_rest_uri_port")
String minio_port = context.config.otherConfigs.get("iceberg_minio_port")
@@ -223,8 +223,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Execute rollback to the earliest snapshot
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_rollback
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" =
"${rollbackEarliestSnapshotId}")
+ ALTER TABLE ${catalog_name}.${db_name}.test_rollback
+ EXECUTE rollback_to_snapshot("snapshot_id" =
"${rollbackEarliestSnapshotId}")
"""
qt_after_rollback_to_snapshot """SELECT * FROM test_rollback ORDER BY id"""
@@ -257,8 +257,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Execute timestamp-based rollback
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_rollback_timestamp
- PROPERTIES("action" = "rollback_to_timestamp", "timestamp" =
"${formattedSnapshotTime}")
+ ALTER TABLE ${catalog_name}.${db_name}.test_rollback_timestamp
+ EXECUTE rollback_to_timestamp("timestamp" = "${formattedSnapshotTime}")
"""
qt_after_rollback_to_timestamp """SELECT * FROM test_rollback_timestamp
ORDER BY id"""
@@ -286,8 +286,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Execute set current snapshot by snapshot ID
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_current_snapshot
- PROPERTIES("action" = "set_current_snapshot", "snapshot_id" =
"${targetCurrentSnapshotId}")
+ ALTER TABLE ${catalog_name}.${db_name}.test_current_snapshot
+ EXECUTE set_current_snapshot("snapshot_id" =
"${targetCurrentSnapshotId}")
"""
qt_after_set_current_snapshot_by_snapshotid """SELECT * FROM
test_current_snapshot ORDER BY id"""
@@ -301,16 +301,16 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test setting current snapshot by branch reference
qt_before_set_current_snapshot_by_branch """SELECT * FROM
test_current_snapshot ORDER BY id"""
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_current_snapshot
- PROPERTIES("action" = "set_current_snapshot", "ref" = "dev_branch")
+ ALTER TABLE ${catalog_name}.${db_name}.test_current_snapshot
+ EXECUTE set_current_snapshot("ref" = "dev_branch")
"""
qt_after_set_current_snapshot_by_branch """SELECT * FROM
test_current_snapshot ORDER BY id"""
// Test setting current snapshot by tag reference
qt_before_set_current_snapshot_by_tag """SELECT * FROM
test_current_snapshot ORDER BY id"""
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_current_snapshot
- PROPERTIES("action" = "set_current_snapshot", "ref" = "dev_tag")
+ ALTER TABLE ${catalog_name}.${db_name}.test_current_snapshot
+ EXECUTE set_current_snapshot("ref" = "dev_tag")
"""
qt_after_set_current_snapshot_by_tag """SELECT * FROM
test_current_snapshot ORDER BY id"""
@@ -338,15 +338,15 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Step 1: Rollback to earliest snapshot to create test scenario
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_cherrypick
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" =
"${cherrypickEarliestSnapshotId}")
+ ALTER TABLE ${catalog_name}.${db_name}.test_cherrypick
+ EXECUTE rollback_to_snapshot("snapshot_id" =
"${cherrypickEarliestSnapshotId}")
"""
qt_rollback_snapshot """SELECT * FROM test_cherrypick ORDER BY id"""
// Step 2: Cherrypick changes from the latest snapshot
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_cherrypick
- PROPERTIES("action" = "cherrypick_snapshot", "snapshot_id" =
"${cherrypickLatestSnapshotId}")
+ ALTER TABLE ${catalog_name}.${db_name}.test_cherrypick
+ EXECUTE cherrypick_snapshot("snapshot_id" =
"${cherrypickLatestSnapshotId}")
"""
qt_after_cherrypick_snapshot """SELECT * FROM test_cherrypick ORDER BY
id"""
@@ -381,8 +381,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
qt_before_fast_forword_branch """SELECT * FROM
test_fast_forward@branch(feature_branch) ORDER BY id"""
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.test_fast_forward
- PROPERTIES("action" = "fast_forward", "branch" = "feature_branch",
"to" = "main")
+ ALTER TABLE ${catalog_name}.${db_name}.test_fast_forward
+ EXECUTE fast_forward("branch" = "feature_branch", "to" = "main")
"""
qt_after_fast_forword_branch """SELECT * FROM
test_fast_forward@branch(feature_branch) ORDER BY id"""
@@ -390,24 +390,24 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots action
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "older_than" =
"2024-01-01T00:00:00")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "2024-01-01T00:00:00")
"""
exception "Iceberg expire_snapshots procedure is not implemented yet"
}
// Test rewrite_data_files action
qt_test_rewrite_data_files_results """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rewrite_data_files", "target-file-size-bytes" =
"134217728")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rewrite_data_files
+ ("target-file-size-bytes" = "134217728")
"""
// Test validation - missing required property
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_snapshot")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_snapshot
+ ()
"""
exception "Missing required argument: snapshot_id"
}
@@ -415,8 +415,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test validation - negative snapshot_id
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" =
"-123")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_snapshot
+ ("snapshot_id" = "-123")
"""
exception "snapshot_id must be positive, got: -123"
}
@@ -424,8 +424,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test validation - zero snapshot_id
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "cherrypick_snapshot", "snapshot_id" = "0")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
cherrypick_snapshot
+ ("snapshot_id" = "0")
"""
exception "snapshot_id must be positive, got: 0"
}
@@ -433,8 +433,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test validation - empty snapshot_id
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "set_current_snapshot", "snapshot_id" = "")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
set_current_snapshot
+ ("snapshot_id" = "")
"""
exception "Invalid snapshot_id format:"
}
@@ -442,8 +442,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test validation - missing timestamp for rollback_to_timestamp
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_timestamp")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_timestamp
+ ()
"""
exception "Missing required argument: timestamp"
}
@@ -451,8 +451,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with invalid older_than timestamp
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "older_than" =
"not-a-timestamp")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "not-a-timestamp")
"""
exception "Invalid older_than format"
}
@@ -460,8 +460,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with negative timestamp
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "older_than" = "-1000")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "-1000")
"""
exception "older_than timestamp must be non-negative"
}
@@ -469,8 +469,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test validation - retain_last must be at least 1
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "retain_last" = "0")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("retain_last" = "0")
"""
exception "retain_last must be positive, got: 0"
}
@@ -478,8 +478,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with invalid retain_last format
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "retain_last" =
"not-a-number")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("retain_last" = "not-a-number")
"""
exception "Invalid retain_last format: not-a-number"
}
@@ -487,8 +487,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with negative retain_last
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "retain_last" = "-5")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("retain_last" = "-5")
"""
exception "retain_last must be positive, got: -5"
}
@@ -496,8 +496,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with neither older_than nor retain_last
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ()
"""
exception "At least one of 'older_than' or 'retain_last' must be
specified"
}
@@ -505,8 +505,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with valid timestamp format (milliseconds)
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "older_than" =
"1640995200000")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "1640995200000")
"""
exception "Iceberg expire_snapshots procedure is not implemented yet"
}
@@ -514,8 +514,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with valid ISO datetime
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "older_than" =
"2024-01-01T12:30:45")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "2024-01-01T12:30:45")
"""
exception "Iceberg expire_snapshots procedure is not implemented yet"
}
@@ -523,8 +523,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test expire_snapshots with valid retain_last and older_than
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "expire_snapshots", "older_than" =
"2024-01-01T00:00:00", "retain_last" = "5")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "2024-01-01T00:00:00", "retain_last" = "5")
"""
exception "Iceberg expire_snapshots procedure is not implemented yet"
}
@@ -532,8 +532,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test unknown action
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "unknown_action")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
unknown_action
+ ()
"""
exception "Unsupported Iceberg procedure: unknown_action."
}
@@ -541,17 +541,16 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test missing action property
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("some_param" = "value")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
"""
- exception "OPTIMIZE TABLE requires 'action' property to be specified"
+ exception "mismatched input '<EOF>'"
}
// Test unknown property for specific action
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" =
"123", "unknown_param" = "value")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_snapshot
+ ("snapshot_id" = "123", "unknown_param" = "value")
"""
exception "Unknown argument: unknown_param"
}
@@ -559,8 +558,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test rewrite_data_files with invalid target-file-size-bytes
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rewrite_data_files",
"target-file-size-bytes" = "0")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rewrite_data_files
+ ("target-file-size-bytes" = "0")
"""
exception "target-file-size-bytes must be positive, got: 0"
}
@@ -568,8 +567,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test rewrite_data_files with invalid file size format
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rewrite_data_files",
"target-file-size-bytes" = "not-a-number")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rewrite_data_files
+ ("target-file-size-bytes" = "not-a-number")
"""
exception "Invalid target-file-size-bytes format: not-a-number"
}
@@ -577,8 +576,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test set_current_snapshot with both snapshot_id and ref
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "set_current_snapshot", "snapshot_id" =
"123", "ref" = "main")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
set_current_snapshot
+ ("snapshot_id" = "123", "ref" = "main")
"""
exception "snapshot_id and ref are mutually exclusive, only one can be
provided"
}
@@ -586,8 +585,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test set_current_snapshot with neither snapshot_id nor ref
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "set_current_snapshot")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
set_current_snapshot
+ ()
"""
exception "Either snapshot_id or ref must be provided"
}
@@ -595,8 +594,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test very large snapshot_id (within Long range)
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" =
"9223372036854775807")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_snapshot
+ ("snapshot_id" = "9223372036854775807")
"""
exception "Snapshot 9223372036854775807 not found in table"
}
@@ -604,8 +603,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test snapshot_id exceeding Long.MAX_VALUE
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" =
"99999999999999999999")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_snapshot
+ ("snapshot_id" = "99999999999999999999")
"""
exception "Invalid snapshot_id format: 99999999999999999999"
}
@@ -613,8 +612,8 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test whitespace handling in parameters
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "rollback_to_snapshot", "snapshot_id" = "
123456789 ")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rollback_to_snapshot
+ ("snapshot_id" = " 123456789 ")
"""
exception "Snapshot 123456789 not found in table"
}
@@ -622,9 +621,18 @@ suite("test_iceberg_optimize_actions_ddl",
"p0,external,doris,external_docker,ex
// Test case sensitivity in action names
test {
sql """
- OPTIMIZE TABLE ${catalog_name}.${db_name}.${table_name}
- PROPERTIES("action" = "ROLLBACK_TO_SNAPSHOT", "snapshot_id" =
"123456789")
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
ROLLBACK_TO_SNAPSHOT
+ ("snapshot_id" = "123456789")
"""
exception "Snapshot 123456789 not found in table"
}
+
+ // Test with multiple partitions
+ test {
+ sql """
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
expire_snapshots
+ ("older_than" = "2024-01-01T00:00:00") PARTITIONS (p1, p2, p3)
+ """
+ exception "Action 'expire_snapshots' does not support partition
specification"
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]