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 @@ -147,11 +147,13 @@ supportedDmlStatement
| explain? cte? UPDATE tableName=multipartIdentifier tableAlias
SET updateAssignmentSeq
fromClause?
whereClause? #update
whereClause?
queryOrganization #update
| explain? cte? DELETE FROM tableName=multipartIdentifier
partitionSpec? tableAlias
(USING relations)?
whereClause? #delete
whereClause?
queryOrganization #delete
| explain? cte? MERGE INTO targetTable=multipartIdentifier
(AS? identifier)? USING srcRelation=relationPrimary
ON expression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@
import org.apache.doris.nereids.trees.expressions.literal.DecimalLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DecimalV3Literal;
import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral;
import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral;
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Interval;
import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
Expand Down Expand Up @@ -2030,6 +2031,8 @@ public LogicalPlan visitUpdate(UpdateContext ctx) {
query = withRelations(query, ((FromRelationsContext) ctx.fromClause()).relations().relation());
}
query = withFilter(query, Optional.ofNullable(ctx.whereClause()));
query = withQueryOrganization(query, ctx.queryOrganization());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When hasQueryOrganization is true (e.g., DELETE FROM dup_table LIMIT 5), this routes to DeleteFromUsingCommand which rejects non-UNIQUE KEY tables with the error "delete command on with using clause only supports unique key model". This is misleading because the user did not use a USING clause.

Plain DELETE FROM dup_table WHERE c1=1 (no LIMIT) works fine on DUP/AGG tables through DeleteHandler.process(), but adding LIMIT changes the error behavior.

Consider either:

  1. Updating DeleteFromUsingCommand.checkTargetTable() to provide a clearer error message when ORDER BY/LIMIT is used (e.g., "DELETE with ORDER BY/LIMIT only supports unique key model"), or
  2. Adding a dedicated check here before routing to DeleteFromUsingCommand that gives a clear error for non-UNIQUE KEY tables.

query = convertSortOrdinalsToUnboundSlot(query);
String tableAlias = null;
if (ctx.tableAlias().strictIdentifier() != null) {
tableAlias = ctx.tableAlias().strictIdentifier().getText();
Expand Down Expand Up @@ -2060,8 +2063,11 @@ public LogicalPlan visitDelete(DeleteContext ctx) {
tableAlias = ctx.tableAlias().strictIdentifier().getText();
}

boolean hasQueryOrganization = ctx.queryOrganization() != null
&& (ctx.queryOrganization().sortClause() != null
|| ctx.queryOrganization().limitClause() != null);
Command deleteCommand;
if (ctx.USING() == null && ctx.cte() == null) {
if (ctx.USING() == null && ctx.cte() == null && !hasQueryOrganization) {
query = withFilter(query, Optional.ofNullable(ctx.whereClause()));
deleteCommand = new DeleteFromCommand(tableName, tableAlias, partitionSpec.first,
partitionSpec.second, query);
Expand All @@ -2071,12 +2077,14 @@ public LogicalPlan visitDelete(DeleteContext ctx) {
query = withRelations(query, ctx.relations().relation());
}
query = withFilter(query, Optional.ofNullable(ctx.whereClause()));
query = withQueryOrganization(query, ctx.queryOrganization());
query = convertSortOrdinalsToUnboundSlot(query);
Optional<LogicalPlan> cte = Optional.empty();
if (ctx.cte() != null) {
cte = Optional.ofNullable(withCte(query, ctx.cte()));
}
deleteCommand = new DeleteFromUsingCommand(tableName, tableAlias,
partitionSpec.first, partitionSpec.second, query, cte);
partitionSpec.first, partitionSpec.second, query, cte, hasQueryOrganization);
}
if (ctx.explain() != null) {
return withExplain(deleteCommand, ctx.explain());
Expand Down Expand Up @@ -4386,6 +4394,37 @@ private LogicalPlan withSort(LogicalPlan input, Optional<SortClauseContext> sort
});
}

/**
* Convert IntegerLikeLiteral expressions in ORDER BY keys to UnboundSlot.
* In SELECT queries, ORDER BY with an integer is treated as an ordinal (position reference).
* In DELETE/UPDATE commands, there is no user-specified SELECT list, so ordinal resolution
* would be meaningless. Convert integer literals to UnboundSlot to prevent the ordinal
* interpretation by BindExpression.
*/
private LogicalPlan convertSortOrdinalsToUnboundSlot(LogicalPlan plan) {
if (plan instanceof LogicalSort) {
LogicalSort<?> sort = (LogicalSort<?>) plan;
List<OrderKey> newOrderKeys = sort.getOrderKeys().stream()
.map(key -> {
if (key.getExpr() instanceof IntegerLikeLiteral) {
return key.withExpression(
new UnboundSlot(String.valueOf(
((IntegerLikeLiteral) key.getExpr()).getIntValue())));
}
return key;
})
.collect(ImmutableList.toImmutableList());
return sort.withOrderKeys(newOrderKeys);
} else if (plan instanceof LogicalLimit) {
LogicalPlan child = (LogicalPlan) ((LogicalLimit<?>) plan).child();
LogicalPlan newChild = convertSortOrdinalsToUnboundSlot(child);
if (newChild != child) {
return (LogicalPlan) ((LogicalLimit<?>) plan).withChildren(newChild);
}
}
return plan;
}

private LogicalPlan withLimit(LogicalPlan input, Optional<LimitClauseContext> limitCtx) {
return input.optionalMap(limitCtx, () -> {
long limit = Long.parseLong(limitCtx.get().limit.getText());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public void run(ConnectContext ctx, StmtExecutor executor) throws Exception {
} catch (Exception e) {
try {
new DeleteFromUsingCommand(nameParts, tableAlias, isTempPart, partitions,
logicalQuery, Optional.empty()).run(ctx, executor);
logicalQuery, Optional.empty(), false).run(ctx, executor);
return;
} catch (Exception e2) {
LOG.warn("delete from command failed", e2);
Expand All @@ -195,7 +195,7 @@ public void run(ConnectContext ctx, StmtExecutor executor) throws Exception {
if (olapTable.getKeysType() == KeysType.UNIQUE_KEYS && olapTable.getEnableUniqueKeyMergeOnWrite()
&& !olapTable.getEnableMowLightDelete()) {
new DeleteFromUsingCommand(nameParts, tableAlias, isTempPart, partitions, logicalQuery,
Optional.empty()).run(ctx, executor);
Optional.empty(), false).run(ctx, executor);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,17 @@
*/
public class DeleteFromUsingCommand extends DeleteFromCommand {
private final Optional<LogicalPlan> cte;
private final boolean hasOrderByLimit;

/**
* constructor
*/
public DeleteFromUsingCommand(List<String> nameParts, String tableAlias,
boolean isTempPart, List<String> partitions, LogicalPlan logicalQuery, Optional<LogicalPlan> cte) {
boolean isTempPart, List<String> partitions, LogicalPlan logicalQuery,
Optional<LogicalPlan> cte, boolean hasOrderByLimit) {
super(nameParts, tableAlias, isTempPart, partitions, logicalQuery);
this.cte = cte;
this.hasOrderByLimit = hasOrderByLimit;
}

@Override
Expand Down Expand Up @@ -80,7 +83,12 @@ public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
@Override
protected void checkTargetTable(OlapTable targetTable) {
if (targetTable.getKeysType() != KeysType.UNIQUE_KEYS) {
throw new AnalysisException("delete command on with using clause only supports unique key model");
if (hasOrderByLimit) {
throw new AnalysisException(
"delete command with ORDER BY/LIMIT only supports unique key model");
}
throw new AnalysisException(
"delete command on with using clause only supports unique key model");
}
}

Expand Down
Loading
Loading