001package gudusoft.gsqlparser.nodes;
002
003
004import java.util.ArrayList;
005
006public class TExceptReplaceClause extends TParseTreeNode {
007
008    public static final int EXCEPT_CLAUSE = 1;
009    public static final int REPLACE_CLAUSE = 2;
010    public static final int EXCEPT_AND_REPLACE_CLAUSE = 3;
011    public static final int EXCEPT_AND_REPLACE_UNKNOWN = 0;
012
013    private int except_replace_clause = EXCEPT_AND_REPLACE_UNKNOWN;
014
015    private TObjectNameList columnList;
016    private ArrayList<TReplaceExprAsIdentifier> exprAsIdentifiers;
017
018    public TObjectNameList getColumnList() {
019        return columnList;
020    }
021
022    public ArrayList<TReplaceExprAsIdentifier> getExprAsIdentifiers() {
023        return exprAsIdentifiers;
024    }
025
026    /**
027     * Convert a parsed EXCEPT item list into the column list this clause carries.
028     *
029     * <p>ClickHouse parses its <code>EXCEPT (...)</code> items as general expressions, because the
030     * clause also accepts a regular expression (<code>EXCEPT('^tmp_')</code>) and arbitrary
031     * expressions. Only a list in which EVERY item is a plain column reference names a set of
032     * columns we can actually prove; anything else is arbitrary text whose excluded set is not
033     * statically knowable.
034     *
035     * <p>Returns <code>null</code> in that unprovable case ON PURPOSE, so the caller keeps the
036     * pre-existing behaviour (no clause, wildcard expands in full) rather than publishing a
037     * guessed exclusion set. Dropping a real column is as damaging as keeping an excluded one.
038     *
039     * @param items the parsed EXCEPT items, may be null
040     * @return the column list, or null when any item is not a plain column reference
041     */
042    public static TObjectNameList exceptNamesFromExpressions(TExpressionList items){
043        if ((items == null) || (items.size() == 0)){
044            return null;
045        }
046        TObjectNameList names = null;
047        for (int i = 0; i < items.size(); i++){
048            TExpression item = items.getExpression(i);
049            if ((item == null) || (item.getExpressionType() != gudusoft.gsqlparser.EExpressionType.simple_object_name_t)){
050                return null;
051            }
052            TObjectName name = item.getObjectOperand();
053            if (name == null){
054                return null;
055            }
056            if (names == null){
057                names = new TObjectNameList();
058            }
059            names.addObjectName(name);
060        }
061        return names;
062    }
063
064    public void init(Object arg1, Object arg2){
065        columnList = (TObjectNameList)arg1;
066        exprAsIdentifiers = (ArrayList<TReplaceExprAsIdentifier>)arg2;
067        if (columnList == null){
068            except_replace_clause = REPLACE_CLAUSE;
069        }else{
070            except_replace_clause = EXCEPT_AND_REPLACE_CLAUSE;
071        }
072    }
073
074    public void init(Object arg1){
075        columnList = (TObjectNameList)arg1;
076        except_replace_clause = EXCEPT_CLAUSE;
077    }
078
079    public void accept(TParseTreeVisitor v){
080        v.preVisit(this);
081        v.postVisit(this);
082    }
083
084    public void acceptChildren(TParseTreeVisitor v){
085        v.preVisit(this);
086        if ((except_replace_clause == EXCEPT_CLAUSE)||(except_replace_clause == EXCEPT_AND_REPLACE_CLAUSE)){
087            columnList.acceptChildren(v);
088        }
089        if ((except_replace_clause == REPLACE_CLAUSE)||(except_replace_clause == EXCEPT_AND_REPLACE_CLAUSE)){
090            for(TReplaceExprAsIdentifier r:exprAsIdentifiers){
091                r.acceptChildren(v);
092            }
093        }
094        v.postVisit(this);
095    }
096}