001package gudusoft.gsqlparser.ir.semantic; 002 003import gudusoft.gsqlparser.ir.semantic.binding.RelationBinding; 004 005import java.util.ArrayList; 006import java.util.Collections; 007import java.util.List; 008 009/** 010 * Slice 78 — write-side target of an {@code INSERT INTO target SELECT ...} 011 * statement. Carries the target table's binding plus the verbatim column 012 * spellings the SQL author wrote in the INSERT column list (e.g. 013 * {@code INSERT INTO target (a, b) ...} → {@code ["a", "b"]}). 014 * 015 * <p>Empty {@link #columns} means the surface SQL omitted the column list 016 * (e.g. {@code INSERT INTO target SELECT ...}). The IR does NOT 017 * positionally expand the catalog's columns into this list — the source 018 * SELECT's output names are the lineage endpoints, and consumers that 019 * want catalog-mapped target column names can join with the supplied 020 * {@link gudusoft.gsqlparser.ir.semantic.catalog.Catalog}. 021 * 022 * <p>This type is intentionally a 2-field value object so the IR's 023 * navigation stays simple ({@link StatementGraph#getTarget()} is null or 024 * a struct). Other INSERT facets (OUTPUT clause, RETURNING, ON CONFLICT, 025 * partition spec) are out of slice-78 scope and stay rejected via 026 * existing diagnostics. 027 */ 028public final class TargetRelation { 029 030 private final RelationBinding binding; 031 private final List<String> columns; 032 033 public TargetRelation(RelationBinding binding, List<String> columns) { 034 if (binding == null) { 035 throw new IllegalArgumentException("binding must not be null"); 036 } 037 if (binding.getKind() != RelationKind.TABLE) { 038 throw new IllegalArgumentException( 039 "TargetRelation binding kind must be TABLE; got " + binding.getKind()); 040 } 041 if (columns == null) { 042 throw new IllegalArgumentException("columns must not be null (use empty list)"); 043 } 044 this.binding = binding; 045 this.columns = Collections.unmodifiableList(new ArrayList<>(columns)); 046 } 047 048 public RelationBinding getBinding() { 049 return binding; 050 } 051 052 /** 053 * @return verbatim SQL spellings of the INSERT column list. Empty when 054 * the SQL author omitted the column list — in that case the 055 * source SELECT's output names are the lineage endpoints. 056 */ 057 public List<String> getColumns() { 058 return columns; 059 } 060}