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]

Reply via email to