Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ statementBase
| supportedDmlStatement #supportedDmlStatementAlias
| supportedCreateStatement #supportedCreateStatementAlias
| supportedAlterStatement #supportedAlterStatementAlias
| supportedOptimizeStatement #supportedOptimizeStatementAlias
| materializedViewStatement #materializedViewStatementAlias
| supportedJobStatement #supportedJobStatementAlias
| constraintStatement #constraintStatementAlias
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@
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";
Expand All @@ -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)
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,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.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;
Expand All @@ -728,7 +729,6 @@
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;
Expand Down Expand Up @@ -7048,25 +7048,27 @@ public LogicalPlan visitUseDatabase(UseDatabaseContext ctx) {
}

@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
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;
Expand All @@ -42,29 +42,38 @@
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");
Expand All @@ -81,44 +90,30 @@ public void run(ConnectContext ctx, StmtExecutor executor) throws Exception {
}

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
Expand All @@ -130,15 +125,19 @@ public TableNameInfo getTableNameInfo() {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -44,9 +44,9 @@
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;
Expand All @@ -59,17 +59,14 @@ 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;
this.properties = properties != null ? properties : Maps.newHashMap();
this.partitionNamesInfo = partitionNamesInfo;
this.whereCondition = whereCondition;

// Add OPTIMIZE TABLE specific allowed arguments
this.namedArguments.addAllowedArgument("action");

// Register arguments specific to this action
registerArguments();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,12 +29,12 @@
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.
*
Expand Down Expand Up @@ -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();
}
Loading
Loading