001package gudusoft.gsqlparser; 002 003import gudusoft.gsqlparser.compiler.TSymbol; 004import gudusoft.gsqlparser.nodes.TColumnDefinition; 005import gudusoft.gsqlparser.nodes.TObjectName; 006import gudusoft.gsqlparser.nodes.TResultColumn; 007import gudusoft.gsqlparser.nodes.TTable; 008import gudusoft.gsqlparser.sqlenv.TSQLColumn; 009 010import java.util.ArrayList; 011import java.util.Objects; 012 013/** 014 * TAttributeNode 类似 column,但含义更广泛。用来表示 SQL 语句中 table 包含的字段(table 或许用 relation 更准确)。 015 * 这里的 table 可以是数据库的基本表,也可以是 from clause 中出现的子查询,或者是 CTE。 016 * 017 * GSP 会把 SQL 语句中出现的每个 table 都生成对应的 TAttributeNode 列表,表示该 table 可以在 SQL 中被使用的字段。 018 * 例如:一般 table 019 * select column1 from table1 020 * 021 * GSP 会在 SQLEnv 中查找 table1 的定义,如果找到(column1,column2,column3), 则 table 会创建三个对应的 TAttributeNode。 022 * 用户可以通过 {@link TTable#getAttributes()} 来获取。 023 * 024 * 如果SQLEnv 中没有查找 table1 的定义,则创建一个 star column TAttributeNode, 形如 table1.* 025 * 026 * 例如:子查询 027 * select column1 from (select c1,c2 from table1) t1 028 * 针对上例中的 t1 子查询, GSP 会创建两个 TAttributeNode,对应 t1.c1, t1.c2 029 * 030 * 针对其他类型的 table, 也做类似处理。为 SQL 中的每个 table 准备好 TAttributeNode 列表, 031 * 在接下来的分析中,SQL 语句中出现的 column 引用都应该能找到对应的来源表和 TAttributeNode 032 * 033 * 相关的属性 034 * {@link TAttributeNode#getName()}, 字段名,不带前缀。 035 * {@link TAttributeNode#getTable_ref()}, 该字段对应的 table,每个在 SQL 语句中出现的 table 都有对应的 {@link TTable} 对象。 036 * {@link TAttributeNode#getSqlColumn()}, 如果在 SQLEnv 中找到该 table 的定义,这个方法返回数据库中定义的字段、 037 * {@link TAttributeNode#getSubLevelResultColumn()}, 如果 table 类型为子查询,该方法返回子查询 select list 中的 {@link TResultColumn} 对象,为该字段的数据来源。 038 * 或者是 values() 中的 result column。 039 * 040 */ 041public class TAttributeNode extends TSymbol { 042 043 // USING (empno INTEGER, 044 //name VARCHAR(50), 045 //salary INTEGER) 046 //MERGE INTO employee AS t 047 //USING VALUES (:empno, :name, :salary) AS s(empno, name, salary) 048 //ON t.empno=s.empno 049 //WHEN MATCHED THEN UPDATE 050 //SET salary=s.salary 051 //WHEN NOT MATCHED THEN INSERT (empno, name, salary) 052 //VALUES (s.empno, s.name, s.salary); 053 054 // 如果 TAttributeNode 来自 VALUES (:empno, :name, :salary) AS s(empno, name, salary) 中的 s(empno, name, salary) 055 // 则 attributeCreatedFromAliasColumn = true, 056 // 当 target column 关联上该 TAttributeNode 后, target column 的 {@link TObjectName#setSourceColumn(TResultColumn)} 需要关联到 057 // 该 node 的 getSubLevelResultColumn() 上。 058 059// public void setAttributeCreatedFromAliasColumn(boolean attributeCreatedFromAliasColumn) { 060// this.attributeCreatedFromAliasColumn = attributeCreatedFromAliasColumn; 061// } 062// 063// public boolean isAttributeCreatedFromAliasColumn() { 064// return attributeCreatedFromAliasColumn; 065// } 066// 067// private boolean attributeCreatedFromAliasColumn; 068 069 070 public static boolean addNodeToList(TAttributeNode node, ArrayList<TAttributeNode> list){ 071 if ((node == null)||(list == null)) return false; 072 073 // 检查是否已存在同名节点 074 for (TAttributeNode existing : list) { 075 if (existing.getName().equals(node.getName())) { 076 return false; 077 } 078 } 079 080 list.add(node); 081 return true; 082 } 083 084 public static boolean addAllNodesToList(ArrayList<TAttributeNode> nodes, ArrayList<TAttributeNode> list){ 085 if ((nodes == null)||(list == null)) return false; 086 087 boolean b = true; 088 for (TAttributeNode node : nodes) { 089 b = addNodeToList(node, list); 090 } 091 return b; 092 } 093 094 // 当一个 attribute node 从 subQuery 产生,然后这个 subQuery 又是 combined query 时, 095 // 这个 attribute node 会有一组同伴 attribute node, 他们是从 combined query 的 不同 subQuery 的 select list 中产生的 096 private ArrayList<TAttributeNode> accompaniedAttributeNodes = new ArrayList<>(); 097 098 public ArrayList<TAttributeNode> getAccompaniedAttributeNodes() { 099 return accompaniedAttributeNodes; 100 } 101 102 private String name; 103 104 // https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type 105 // Typed struct syntax 106 // STRUCT<[field_name] field_type, ...>( expr1 [, ... ]) 107 private TResultColumn structResultColumn; 108 109 public TResultColumn getStructResultColumn() { 110 return structResultColumn; 111 } 112 113 private TColumnDefinition columnDefinition; // this attribute is created from field definition struct<> 114 public TAttributeNode(String n, TTable table,TColumnDefinition columnDef, TResultColumn resultColumn){ 115 this(n,table); 116 this.columnDefinition = columnDef; 117 this.structResultColumn = resultColumn; 118 // System.out.println("Attribute node hashcode"+this.hashCode()+"Add "+this.subLevelResultColumn.toString()+" for table: "+table_ref.toString()+" hashcode:"+ table_ref.hashCode()); 119 } 120 public TColumnDefinition getColumnDefinition() { 121 return columnDefinition; 122 } 123 124 public TResultColumn getSubLevelResultColumn() { 125 return subLevelResultColumn; 126 } 127 128 public TSQLColumn getSqlColumn() { 129 return sqlColumn; 130 } 131 132 private TResultColumn subLevelResultColumn; 133 private TTable table_ref;// table reference in the script that derived this attribute 134 // SELECT col_1, col_2 135 //FROM ( 136 // select * 137 // FROM table_a 138 // ) a 139 private int index;// a.* 在 select * from table_a 的 result list 中的位置 140 141 /** 142 * 把关联上的 column 加入到 attributeNode 中来。 143 * 144 * 另外,如果这个 attributeNode 的源来自 sub-query 中的 select list 的 star column, 145 * 那么把这个 column 加到 star column 中来,完成自顶向下的数据传递, 146 * @param objectName 147 */ 148 public void addAttributeRefToThisNode(TObjectName objectName){ 149 attributesRefToThisNode.add(objectName); 150 objectName.setSourceAttributeNode(this); 151 if ((subLevelResultColumn != null) && (subLevelResultColumn.toString().endsWith("*"))){ 152 if(!subLevelResultColumn.getAttributesFromUpLevelReferenceToStarColumn().contains(objectName)){ 153 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 154 TBaseType.log(String.format("Add reference %s to star column %s in attribute node: %s",objectName.toString(),subLevelResultColumn.toString(),this.getName()),TLog.DEBUG); 155 } 156 subLevelResultColumn.getAttributesFromUpLevelReferenceToStarColumn().add(objectName); 157 } 158 } 159 } 160 private ArrayList<TObjectName> attributesRefToThisNode = new ArrayList<>(); 161 162// public ArrayList<TObjectName> getAttributesRefToThisNode() { 163// return attributesRefToThisNode; 164// } 165 166 public int getIndex() { 167 return index; 168 } 169 170 public String getName() { 171 return name; 172 } 173 174 public String getLastPartOfName() { 175 176 String last_part = name; 177 for(int i=name.length()-1;i>=0;i--){ 178 if (name.charAt(i) == '.'){ 179 last_part = name.substring(i+1,name.length()); 180 break; 181 } 182 } 183 return last_part; 184 } 185 public TTable getTable_ref() { 186 return table_ref; 187 } 188 189 public TAttributeNode(String n, TTable table){ 190 this.name = n; 191 this.table_ref = table; 192 } 193 194 private TSQLColumn sqlColumn; // 如果这个attribute 来自 DDL 或数据库中,那么关联上 column definition 195 public TAttributeNode(String n, TTable table,TSQLColumn columnDef){ 196 this(n,table); 197 this.sqlColumn = columnDef; 198 // System.out.println("Attribute node hashcode"+this.hashCode()+"Add "+this.subLevelResultColumn.toString()+" for table: "+table_ref.toString()+" hashcode:"+ table_ref.hashCode()); 199 } 200 201 202 public TAttributeNode(String n, TTable table,TResultColumn attribute){ 203 this(n,table); 204 this.subLevelResultColumn = attribute; 205 // System.out.println("Attribute node hashcode"+this.hashCode()+"Add "+this.subLevelResultColumn.toString()+" for table: "+table_ref.toString()+" hashcode:"+ table_ref.hashCode()); 206 } 207 208 public TAttributeNode(String n, TTable table,TSQLColumn columnDef,TResultColumn attribute){ 209 this(n,table,columnDef); 210 this.subLevelResultColumn = attribute; 211 // System.out.println("Attribute node hashcode"+this.hashCode()+"Add "+this.subLevelResultColumn.toString()+" for table: "+table_ref.toString()+" hashcode:"+ table_ref.hashCode()); 212 } 213 214 public TAttributeNode(String n, TTable table,TResultColumn attribute,int index){ 215 this(n,table,attribute); 216 //this.subLevelResultColumn = attribute; 217 this.index = index; 218 } 219 220 public TAttributeNode(String n, TTable table,TSQLColumn columnDef,TResultColumn attribute,int index){ 221 this(n,table,columnDef, attribute); 222 //this.subLevelResultColumn = attribute; 223 this.index = index; 224 } 225 226 @Override 227 public String toString(){ 228 return name;//+"( table ref: "+table_ref.toString()+")"; 229 } 230 231 @Override 232 public boolean equals(Object o) { 233 if (this == o) return true; 234 if (o == null || getClass() != o.getClass()) return false; 235 TAttributeNode that = (TAttributeNode) o; 236 return Objects.equals(getName(), that.getName()); 237 } 238 239 @Override 240 public int hashCode() { 241 return Objects.hash(getName()); 242 } 243 244}