001package gudusoft.gsqlparser.dlineage.dataflow.model;
002
003import gudusoft.gsqlparser.EFunctionType;
004import gudusoft.gsqlparser.ESetOperatorType;
005import gudusoft.gsqlparser.nodes.TCaseExpression;
006import gudusoft.gsqlparser.nodes.TFunctionCall;
007import gudusoft.gsqlparser.nodes.TMergeInsertClause;
008import gudusoft.gsqlparser.nodes.TMergeUpdateClause;
009import gudusoft.gsqlparser.nodes.TOutputClause;
010import gudusoft.gsqlparser.nodes.TParseTreeNode;
011import gudusoft.gsqlparser.stmt.TInsertSqlStatement;
012import gudusoft.gsqlparser.stmt.TUpdateSqlStatement;
013
014/**
015 * The kind of a runtime result set, as a pure function of its runtime class, the parse tree node it is attached to
016 * and its explicit descriptors (plan {@code docs/designs/data-lineage/09-sqllr-v2-runtime-driven-coverage-plan-zh.md},
017 * Section 3.2).
018 *
019 * <p>{@code DataFlowAnalyzer.getResultSetName} decides the same kinds in the same branch order, but it also names the
020 * result set: it allocates display counters ({@code DISPLAY_ID}), fills the name cache ({@code DISPLAY_NAME}) and
021 * sets the target flag from the display options. That method stays as it is, for the legacy output. The SQL-LR
022 * producer classifies with this class only: it allocates nothing, caches nothing, never sets a flag and never
023 * resolves a name, so classifying cannot change a legacy byte or a display number.</p>
024 *
025 * <p>Internal API of the SQL-LR producer.</p>
026 *
027 * @since 4.2.17
028 */
029public final class ResultSetClassifier {
030
031    /** The kinds, in the order {@code getResultSetName} tests them. */
032    public enum Kind {
033        /** An ARRAY(...) constructor ({@code ARRAY-n}). */
034        ARRAY,
035        /** A STRUCT(...) constructor ({@code STRUCT-n}). */
036        STRUCT,
037        /** An aliased query table ({@code RESULT_OF_<alias>-n}). */
038        QUERY_TABLE_ALIAS,
039        /** An aliased reference to a CTE ({@code RESULT_OF_<cte>_<alias>-n}). */
040        CTE_ALIAS,
041        /** An unaliased reference to a CTE ({@code CTE-<cte>-n}). */
042        CTE,
043        /** The SELECT of an INSERT ... SELECT ({@code INSERT-SELECT-n}). */
044        INSERT_SELECT,
045        /** The SELECT of an UPDATE ({@code UPDATE-SELECT-n}). */
046        UPDATE_SELECT,
047        /** A set operation ({@code RESULT_OF_<OPERATOR>-n}); see {@link Result#getSetOperator()}. */
048        SET_OPERATION,
049        /** The WHEN MATCHED UPDATE of a MERGE ({@code MERGE-UPDATE-n}). */
050        MERGE_UPDATE,
051        /** An OUTPUT clause ({@code OUTPUT-n}). */
052        OUTPUT,
053        /** The WHEN NOT MATCHED INSERT of a MERGE ({@code MERGE-INSERT-n}). */
054        MERGE_INSERT,
055        /** The SET of an UPDATE ({@code UPDATE-SET-n}). */
056        UPDATE_SET,
057        /** A CASE expression (named after the function). */
058        CASE,
059        /** A function call (named after the function). */
060        FUNCTION,
061        /** A PIVOT ({@code PIVOT-TABLE-n}). */
062        PIVOT,
063        /** An UNPIVOT ({@code UNPIVOT-TABLE-n}). */
064        UNPIVOT,
065        /** An alias result set ({@code ALIAS-n}). */
066        ALIAS,
067        /** Any other result set: a select list ({@code RS-n}). */
068        SELECT_LIST
069    }
070
071    /** A classification: the kind and the descriptors that refine it. Plain values. */
072    public static final class Result {
073        private final Kind kind;
074        private final ESetOperatorType setOperator;
075
076        Result(Kind kind, ESetOperatorType setOperator) {
077            this.kind = kind;
078            this.setOperator = setOperator;
079        }
080
081        public Kind getKind() {
082            return kind;
083        }
084
085        /** The operator of a {@link Kind#SET_OPERATION}, else {@code null}. */
086        public ESetOperatorType getSetOperator() {
087            return setOperator;
088        }
089
090        @Override
091        public String toString() {
092            return setOperator == null ? kind.name() : kind.name() + "(" + setOperator.name() + ")";
093        }
094    }
095
096    private ResultSetClassifier() {
097    }
098
099    /** Classifies a result set; reads only, in {@code getResultSetName}'s branch order. */
100    public static Result classify(ResultSet rs) {
101        TParseTreeNode gsp = rs.getGspObject();
102        // the parsed type, never getFunctionType(): its lookup of an unknown type caches a built-in check on the node,
103        // and the lookup never answers array_t or struct_t, so the kind is the same (Codex review of slice 1a, #4)
104        if (gsp instanceof TFunctionCall && ((TFunctionCall) gsp).getParsedFunctionType() == EFunctionType.array_t) {
105            return new Result(Kind.ARRAY, null);
106        }
107        if (gsp instanceof TFunctionCall && ((TFunctionCall) gsp).getParsedFunctionType() == EFunctionType.struct_t) {
108            return new Result(Kind.STRUCT, null);
109        }
110        if (rs instanceof QueryTable) {
111            QueryTable table = (QueryTable) rs;
112            boolean cte = table.getTableObject().getCTE() != null;
113            if (table.getAlias() != null && table.getAlias().trim().length() > 0) {
114                return new Result(cte ? Kind.CTE_ALIAS : Kind.QUERY_TABLE_ALIAS, null);
115            }
116            if (cte) {
117                return new Result(Kind.CTE, null);
118            }
119        }
120        if (rs instanceof SelectResultSet) {
121            Object parent = ((SelectResultSet) rs).getSelectStmt().getParentStmt();
122            if (parent instanceof TInsertSqlStatement) {
123                return new Result(Kind.INSERT_SELECT, null);
124            }
125            if (parent instanceof TUpdateSqlStatement) {
126                return new Result(Kind.UPDATE_SELECT, null);
127            }
128        }
129        if (rs instanceof SelectSetResultSet) {
130            return new Result(Kind.SET_OPERATION, ((SelectSetResultSet) rs).getSetOperatorType());
131        }
132        if (gsp instanceof TMergeUpdateClause) {
133            return new Result(Kind.MERGE_UPDATE, null);
134        }
135        if (gsp instanceof TOutputClause) {
136            return new Result(Kind.OUTPUT, null);
137        }
138        if (gsp instanceof TMergeInsertClause) {
139            return new Result(Kind.MERGE_INSERT, null);
140        }
141        if (gsp instanceof TUpdateSqlStatement) {
142            return new Result(Kind.UPDATE_SET, null);
143        }
144        if (gsp instanceof TCaseExpression) {
145            return new Result(Kind.CASE, null);
146        }
147        if (gsp instanceof TFunctionCall || rs instanceof Function) {
148            return new Result(Kind.FUNCTION, null);
149        }
150        if (rs instanceof PivotedTable) {
151            return new Result(((PivotedTable) rs).isUnpivoted() ? Kind.UNPIVOT : Kind.PIVOT, null);
152        }
153        if (rs instanceof Alias) {
154            return new Result(Kind.ALIAS, null);
155        }
156        return new Result(Kind.SELECT_LIST, null);
157    }
158}