001 002package gudusoft.gsqlparser.dlineage.dataflow.model; 003 004import java.util.LinkedHashSet; 005import java.util.Set; 006 007import gudusoft.gsqlparser.EDbVendor; 008import gudusoft.gsqlparser.EExpressionType; 009import gudusoft.gsqlparser.ESetOperatorType; 010import gudusoft.gsqlparser.TSourceToken; 011import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 012import gudusoft.gsqlparser.dlineage.util.Pair3; 013import gudusoft.gsqlparser.nodes.TObjectName; 014import gudusoft.gsqlparser.nodes.TResultColumn; 015import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 016import gudusoft.gsqlparser.sqlenv.TSQLEnv; 017import gudusoft.gsqlparser.stmt.TSelectSqlStatement; 018import gudusoft.gsqlparser.util.SQLUtil; 019 020public class SelectSetResultColumn extends ResultColumn { 021 022 private LinkedHashSet<String> aliasSet = new LinkedHashSet<String>(); 023 024 public SelectSetResultColumn(ResultSet resultSet, 025 TResultColumn resultColumnObject, int index) { 026 super(resultSet, resultColumnObject); 027 aliasSet.clear(); 028 if (isNotSameAlias(resultSet, index)) { 029 this.name = aliasSet.iterator().next(); 030 // Named by a branch's alias: a column, not the first branch's star. 031 setStarColumn(false); 032 } else { 033 if (resultColumnObject.getAliasClause() != null) { 034 this.name = resultColumnObject.getAliasClause().toString(); 035 } else if (resultColumnObject.getColumnNameOnly() != null 036 && !"".equals(resultColumnObject.getColumnNameOnly())) { 037 this.name = resultColumnObject.getColumnNameOnly(); 038 } else if (resultColumnObject.getExpr().getExpressionType() == EExpressionType.simple_constant_t) { 039 this.name = resultColumnObject.getExpr().toString(); 040 } 041 else { 042 this.name = quote(resultColumnObject.toString()); 043 } 044 } 045 046 this.fullName = this.name; 047 } 048 049 private boolean isNotSameAlias(ResultSet resultSet, int index) { 050 if (resultSet instanceof SelectSetResultSet) { 051 SelectSetResultSet selectSetResultSet = (SelectSetResultSet) resultSet; 052 if (selectSetResultSet 053 .getSetOperatorType() == ESetOperatorType.none) { 054 return false; 055 } 056 TSelectSqlStatement select = selectSetResultSet.getSelectObject(); 057 return isNotSameAlias(select, index); 058 } else if (resultSet instanceof SelectResultSet) { 059 SelectResultSet selectResultSet = (SelectResultSet) resultSet; 060 if (selectResultSet.getSelectStmt() 061 .getSetOperatorType() == ESetOperatorType.none) { 062 return false; 063 } 064 TSelectSqlStatement select = selectResultSet.getSelectStmt(); 065 return isNotSameAlias(select, index); 066 } 067 return false; 068 } 069 070 private boolean isNotSameAlias(TSelectSqlStatement select, int index) { 071 if (starBefore(select, index)) { 072 return false; 073 } 074 collectSelectAlias(select, index, aliasSet); 075 aliasSet.remove("*"); 076 return aliasSet.size() > 1; 077 } 078 079 /** 080 * Whether a select of the set operation {@code select} has a star before its item at {@code index}: the star's width 081 * leaves the item's position unknown, so the items at that index of the selects are no one column (Mantis 4914). 082 */ 083 private static boolean starBefore(TSelectSqlStatement select, int index) { 084 java.util.Deque<TSelectSqlStatement> stack = new java.util.ArrayDeque<>(); 085 stack.push(select); 086 while (!stack.isEmpty()) { 087 TSelectSqlStatement current = stack.pop(); 088 if (current.getSetOperatorType() != ESetOperatorType.none) { 089 if (current.getRightStmt() != null) stack.push(current.getRightStmt()); 090 if (current.getLeftStmt() != null) stack.push(current.getLeftStmt()); 091 continue; 092 } 093 if (current.getResultColumnList() == null) { 094 continue; 095 } 096 for (int i = 0; i < index && i < current.getResultColumnList().size(); i++) { 097 TResultColumn item = current.getResultColumnList().getResultColumn(i); 098 if (item.getExpr() != null && item.getExpr().getExpressionType() == EExpressionType.simple_object_name_t 099 && DlineageUtil.isStarName(item.getExpr().getObjectOperand())) { 100 return true; 101 } 102 } 103 } 104 return false; 105 } 106 107 private void collectSelectAlias(TSelectSqlStatement select, int index, 108 Set<String> aliasSet) { 109 // Iterative traversal using explicit stack to avoid StackOverflow 110 java.util.Deque<TSelectSqlStatement> stack = new java.util.ArrayDeque<>(); 111 stack.push(select); 112 113 while (!stack.isEmpty()) { 114 TSelectSqlStatement current = stack.pop(); 115 if (current.getSetOperatorType() == ESetOperatorType.none) { 116 if (current.getResultColumnList() == null) { 117 continue; 118 } 119 TResultColumn column = current.getResultColumnList() 120 .getResultColumn(index); 121 122 String alias = null; 123 if (column == null) { 124 continue; 125 } 126 if (column.getAliasClause() != null) { 127 alias = column.getAliasClause().toString(); 128 } else if (column.getColumnNameOnly() != null && !"".equals(column.getColumnNameOnly())) { 129 alias = column.getColumnNameOnly(); 130 } else if (column.getExpr().getExpressionType() == EExpressionType.simple_constant_t) { 131 alias = column.getExpr().toString(); 132 } else { 133 alias = quote(column.toString()); 134 } 135 aliasSet.add(alias); 136 } else { 137 // Push right first so left is processed first 138 if (current.getRightStmt() != null) stack.push(current.getRightStmt()); 139 if (current.getLeftStmt() != null) stack.push(current.getLeftStmt()); 140 } 141 } 142 } 143 144 private String quote(String column) { 145 EDbVendor vendor = ModelBindingManager.getGlobalVendor(); 146 if (!DlineageUtil.isQuote(column)){ 147 return SQLUtil.quoteDottedName(vendor, ESQLDataObjectType.dotColumn, column); 148 } 149 else return column; 150 } 151 152 public SelectSetResultColumn(ResultSet resultSet, 153 ResultColumn resultColumn) { 154 if (resultColumn == null || resultSet == null) 155 throw new IllegalArgumentException( 156 "ResultColumn arguments can't be null."); 157 158 id = ++ModelBindingManager.get().TABLE_COLUMN_ID; 159 160 this.resultSet = resultSet; 161 resultSet.addColumn(this); 162 this.setStruct(resultColumn.isStruct()); 163 inheritIdentifier(resultColumn); 164 inheritStarColumn(resultColumn); 165 166 if(resultColumn.getRefColumnName()!=null) { 167 TResultColumn resultColumnObject = (TResultColumn) resultColumn 168 .getColumnObject(); 169 TSourceToken startToken = resultColumnObject.getStartToken(); 170 TSourceToken endToken = resultColumnObject.getEndToken(); 171 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 172 startToken.columnNo, ModelBindingManager.getGlobalHash()); 173 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 174 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 175 this.columnObject = resultColumnObject; 176 this.refColumnName = resultColumn.getRefColumnName(); 177 this.name = resultColumn.getName(); 178 } 179 else if (resultColumn.getColumnObject() instanceof TResultColumn) { 180 TResultColumn resultColumnObject = (TResultColumn) resultColumn 181 .getColumnObject(); 182 if (resultColumnObject.getAliasClause() != null) { 183 this.alias = resultColumnObject.getAliasClause().toString(); 184 TSourceToken startToken = resultColumnObject.getAliasClause() 185 .getStartToken(); 186 TSourceToken endToken = resultColumnObject.getAliasClause() 187 .getEndToken(); 188 this.aliasStartPosition = new Pair3<Long, Long, String>( 189 startToken.lineNo, startToken.columnNo, ModelBindingManager.getGlobalHash()); 190 this.aliasEndPosition = new Pair3<Long, Long, String>(endToken.lineNo, 191 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 192 193 this.name = this.alias; 194 // Named by its alias: a column, even over a whole-row struct. 195 setStarColumn(false); 196 } else if (resultColumnObject.getExpr() 197 .getExpressionType() == EExpressionType.simple_object_name_t) { 198 this.name = resultColumnObject.getColumnNameOnly(); 199 } else if (resultColumnObject.getFieldAttr() != null) { 200 this.name = resultColumnObject.getColumnNameOnly(); 201 } else { 202 if (resultColumnObject.getExpr() 203 .getExpressionType() == EExpressionType.simple_constant_t) { 204 this.name = resultColumnObject.toString(); 205 } else if (resultColumnObject.getExpr() 206 .getExpressionType() == EExpressionType.function_t) { 207 this.name = resultColumnObject.getCompactString(); 208 } else if (resultColumnObject.getColumnNameOnly() != null 209 && !"".equals( 210 resultColumnObject.getColumnNameOnly())) { 211 this.name = resultColumnObject.getColumnNameOnly(); 212 } else { 213 this.name = resultColumnObject.toString(); 214 } 215 } 216 217 if (resultColumnObject.getExpr() 218 .getExpressionType() == EExpressionType.function_t) { 219 this.fullName = resultColumnObject.getExpr() 220 .getFunctionCall() 221 .getFunctionName() 222 .toString(); 223 } else { 224 this.fullName = resultColumnObject.toString(); 225 } 226 227 TSourceToken startToken = resultColumnObject.getStartToken(); 228 TSourceToken endToken = resultColumnObject.getEndToken(); 229 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 230 startToken.columnNo, ModelBindingManager.getGlobalHash()); 231 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 232 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 233 this.columnObject = resultColumnObject; 234 } else if (resultColumn.getColumnObject() instanceof TObjectName) { 235 TObjectName resultColumnObject = (TObjectName) resultColumn 236 .getColumnObject(); 237 238 if (resultColumnObject.getColumnNameOnly() != null 239 && !"".equals(resultColumnObject.getColumnNameOnly())) { 240 this.name = resultColumnObject.getColumnNameOnly(); 241 } else { 242 this.name = resultColumnObject.toString(); 243 } 244 245 this.fullName = this.name; 246 247 TSourceToken startToken = resultColumnObject.getStartToken(); 248 TSourceToken endToken = resultColumnObject.getEndToken(); 249 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 250 startToken.columnNo, ModelBindingManager.getGlobalHash()); 251 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 252 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 253 this.columnObject = resultColumnObject; 254 } else { 255 this.name = resultColumn.getName(); 256 this.fullName = this.name; 257 258 TSourceToken startToken = resultColumn.getColumnObject() 259 .getStartToken(); 260 TSourceToken endToken = resultColumn.getColumnObject() 261 .getEndToken(); 262 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 263 startToken.columnNo, ModelBindingManager.getGlobalHash()); 264 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 265 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 266 this.columnObject = resultColumn.getColumnObject(); 267 } 268 } 269 270 public Set<String> getAliasSet() { 271 return aliasSet; 272 } 273}