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}