RowLevelDmlArgs.java

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.doris.nereids.trees.plans.commands;

import org.apache.doris.catalog.TableIf;
import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.commands.delete.DeleteCommandContext;
import org.apache.doris.nereids.trees.plans.commands.merge.MergeMatchedClause;
import org.apache.doris.nereids.trees.plans.commands.merge.MergeNotMatchedClause;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;

import java.util.List;
import java.util.Optional;

/**
 * Immutable carrier of the per-operation arguments a {@link RowLevelDmlTransform} needs to synthesize a
 * row-level DML plan, plus the already-resolved target {@link TableIf}.
 *
 * <p>The dispatching command ({@code UpdateCommand}/{@code DeleteFromCommand}/{@code MergeIntoCommand})
 * resolves the table (preserving its own swallow/throw discipline) and builds the matching variant via the
 * {@code forDelete}/{@code forUpdate}/{@code forMerge} factories. Fields are a union across the three
 * operations; only the relevant ones are populated per factory. {@code cte} is forwarded for MERGE only ���
 * UPDATE/DELETE drop it, faithful to legacy {@code IcebergUpdateCommand}/{@code IcebergDeleteCommand}, which
 * carry no CTE.</p>
 */
public final class RowLevelDmlArgs {

    private final TableIf table;

    // DELETE / UPDATE
    private final List<String> nameParts;
    private final String tableAlias;
    private final LogicalPlan logicalQuery;
    private final DeleteCommandContext deleteCtx;
    // DELETE only
    private final boolean isTempPart;
    private final List<String> partitions;
    // UPDATE only
    private final List<EqualTo> assignments;

    // MERGE
    private final List<String> targetNameParts;
    private final Optional<String> targetAlias;
    private final Optional<LogicalPlan> cte;
    private final LogicalPlan source;
    private final Expression onClause;
    private final List<MergeMatchedClause> matchedClauses;
    private final List<MergeNotMatchedClause> notMatchedClauses;

    private RowLevelDmlArgs(TableIf table, List<String> nameParts, String tableAlias, LogicalPlan logicalQuery,
            DeleteCommandContext deleteCtx, boolean isTempPart, List<String> partitions, List<EqualTo> assignments,
            List<String> targetNameParts, Optional<String> targetAlias, Optional<LogicalPlan> cte, LogicalPlan source,
            Expression onClause, List<MergeMatchedClause> matchedClauses,
            List<MergeNotMatchedClause> notMatchedClauses) {
        this.table = table;
        this.nameParts = nameParts;
        this.tableAlias = tableAlias;
        this.logicalQuery = logicalQuery;
        this.deleteCtx = deleteCtx;
        this.isTempPart = isTempPart;
        this.partitions = partitions;
        this.assignments = assignments;
        this.targetNameParts = targetNameParts;
        this.targetAlias = targetAlias;
        this.cte = cte;
        this.source = source;
        this.onClause = onClause;
        this.matchedClauses = matchedClauses;
        this.notMatchedClauses = notMatchedClauses;
    }

    /** Arguments for a DELETE (mirrors the legacy {@code IcebergDeleteCommand} constructor inputs). */
    public static RowLevelDmlArgs forDelete(TableIf table, List<String> nameParts, String tableAlias,
            boolean isTempPart, List<String> partitions, LogicalPlan logicalQuery, DeleteCommandContext deleteCtx) {
        return new RowLevelDmlArgs(table, nameParts, tableAlias, logicalQuery, deleteCtx, isTempPart, partitions,
                null, null, null, null, null, null, null, null);
    }

    /** Arguments for an UPDATE (mirrors the legacy {@code IcebergUpdateCommand} constructor inputs). */
    public static RowLevelDmlArgs forUpdate(TableIf table, List<String> nameParts, String tableAlias,
            List<EqualTo> assignments, LogicalPlan logicalQuery, DeleteCommandContext deleteCtx) {
        return new RowLevelDmlArgs(table, nameParts, tableAlias, logicalQuery, deleteCtx, false, null,
                assignments, null, null, null, null, null, null, null);
    }

    /** Arguments for a MERGE INTO (mirrors the legacy {@code IcebergMergeCommand} constructor inputs). */
    public static RowLevelDmlArgs forMerge(TableIf table, List<String> targetNameParts, Optional<String> targetAlias,
            Optional<LogicalPlan> cte, LogicalPlan source, Expression onClause,
            List<MergeMatchedClause> matchedClauses, List<MergeNotMatchedClause> notMatchedClauses) {
        return new RowLevelDmlArgs(table, null, null, null, null, false, null, null,
                targetNameParts, targetAlias, cte, source, onClause, matchedClauses, notMatchedClauses);
    }

    public TableIf getTable() {
        return table;
    }

    public List<String> getNameParts() {
        return nameParts;
    }

    public String getTableAlias() {
        return tableAlias;
    }

    public LogicalPlan getLogicalQuery() {
        return logicalQuery;
    }

    public DeleteCommandContext getDeleteCtx() {
        return deleteCtx;
    }

    public boolean isTempPart() {
        return isTempPart;
    }

    public List<String> getPartitions() {
        return partitions;
    }

    public List<EqualTo> getAssignments() {
        return assignments;
    }

    public List<String> getTargetNameParts() {
        return targetNameParts;
    }

    public Optional<String> getTargetAlias() {
        return targetAlias;
    }

    public Optional<LogicalPlan> getCte() {
        return cte;
    }

    public LogicalPlan getSource() {
        return source;
    }

    public Expression getOnClause() {
        return onClause;
    }

    public List<MergeMatchedClause> getMatchedClauses() {
        return matchedClauses;
    }

    public List<MergeNotMatchedClause> getNotMatchedClauses() {
        return notMatchedClauses;
    }
}