001 002package gudusoft.gsqlparser.dlineage.dataflow.model; 003 004import gudusoft.gsqlparser.EDbVendor; 005import gudusoft.gsqlparser.TCustomSqlStatement; 006import gudusoft.gsqlparser.TSourceToken; 007import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 008import gudusoft.gsqlparser.dlineage.util.Pair3; 009import gudusoft.gsqlparser.nodes.TParseTreeNode; 010import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 011import gudusoft.gsqlparser.sqlenv.TSQLEnv; 012import gudusoft.gsqlparser.util.Logger; 013import gudusoft.gsqlparser.util.LoggerFactory; 014import gudusoft.gsqlparser.util.SQLUtil; 015 016import java.io.ByteArrayInputStream; 017import java.io.IOException; 018import java.util.*; 019import java.util.concurrent.atomic.AtomicInteger; 020 021public class ResultSet { 022 private static final Logger logger = LoggerFactory.getLogger(ResultSet.class); 023 private long id; 024 protected String server; 025 protected String schema; 026 protected String database; 027 private Pair3<Long, Long, String> startPosition; 028 private Pair3<Long, Long, String> endPosition; 029 private List<ResultColumn> columns = new ArrayList<ResultColumn>(); 030 031 private TParseTreeNode gspObject; 032 private boolean isTarget; 033 private boolean isDetermined; 034 035 private ResultSetRelationRows relationRows = new ResultSetRelationRows(this); 036 037 private Map<String, AtomicInteger> aliasMap = new HashMap<>(); 038 039 private String procedureId; 040 041 public ResultSet(TParseTreeNode gspObject, boolean isTarget) { 042 if (gspObject == null) { 043 throw new IllegalArgumentException("ResultSet arguments can't be null."); 044 } 045 046 id = ++ModelBindingManager.get().TABLE_COLUMN_ID; 047 048 this.gspObject = gspObject; 049 this.isTarget = isTarget; 050 051 TSourceToken startToken = gspObject.getStartToken(); 052 TSourceToken endToken = gspObject.getEndToken(); 053 if (startToken != null) { 054 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 055 startToken.columnNo, ModelBindingManager.getGlobalHash()); 056 } 057 058 if (endToken != null) { 059 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 060 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 061 } 062 063 this.schema = ModelBindingManager.getGlobalSchema(); 064 this.database = ModelBindingManager.getGlobalDatabase(); 065 066 EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor(); 067 boolean supportCatalog = TSQLEnv.supportCatalog(vendor); 068 boolean supportSchema = TSQLEnv.supportSchema(vendor); 069 070 fillSchemaInfo(); 071 072 if (!supportCatalog) { 073 this.database = null; 074 } else if (this.database == null && !TSQLEnv.DEFAULT_DB_NAME.equals(getDefaultDatabase())) { 075 this.database = getDefaultDatabase(); 076 } 077 078 if (!supportSchema) { 079 this.schema = null; 080 } else if (this.schema == null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equals(getDefaultSchema())) { 081 this.schema = getDefaultSchema(); 082 } 083 084 if (this.server == null && !TSQLEnv.DEFAULT_SERVER_NAME.equals(getDefaultServer())) { 085 this.server = getDefaultServer(); 086 } 087 } 088 089 private void fillSchemaInfo() { 090 TCustomSqlStatement stmt = DlineageUtil.getTopStmt(ModelBindingManager.getGlobalStmtStack().peek()); 091 String sqlComment = null; 092 try { 093 sqlComment = stmt.getCommentBeforeNode(); 094 } catch (Exception e) { 095 } 096 if (!SQLUtil.isEmpty(sqlComment) && (sqlComment.indexOf("db") != -1 || sqlComment.indexOf("schema") != -1)) { 097 Properties properties = new Properties(); 098 try { 099 properties.load( 100 new ByteArrayInputStream(sqlComment.replace("--", "").trim().replace(",", "\n").getBytes())); 101 if (SQLUtil.isEmpty(this.server) && properties.containsKey("db-instance")) { 102 this.server = properties.getProperty("db-instance"); 103 } 104 if (SQLUtil.isEmpty(this.database) && properties.containsKey("db")) { 105 this.database = properties.getProperty("db"); 106 if(this.database.indexOf(".")!=-1) { 107 this.database = SQLUtil.quoteDottedName(ModelBindingManager.getGlobalOption().getVendor(), ESQLDataObjectType.dotCatalog, this.database); 108 } 109 } 110 if (SQLUtil.isEmpty(this.schema) && properties.containsKey("schema")) { 111 this.schema = properties.getProperty("schema"); 112 if(this.schema.indexOf(".")!=-1) { 113 this.schema = SQLUtil.quoteDottedName(ModelBindingManager.getGlobalOption().getVendor(), ESQLDataObjectType.dotSchema, this.schema); 114 } 115 } 116 } catch (IOException e) { 117 logger.error("load sql comment properties failed.", e); 118 } 119 } 120 } 121 122 protected String getDefaultServer() { 123 String defaultServer = null; 124 if (ModelBindingManager.getGlobalSQLEnv() != null) { 125 defaultServer = ModelBindingManager.getGlobalSQLEnv().getDefaultServerName(); 126 } 127 if (!SQLUtil.isEmpty(defaultServer)) 128 return defaultServer; 129 return TSQLEnv.DEFAULT_SERVER_NAME; 130 } 131 132 protected String getDefaultSchema() { 133 return ModelBindingManager.getEffectiveDefaultSchema(); 134 } 135 136 protected String getDefaultDatabase() { 137 return ModelBindingManager.getEffectiveDefaultDatabase(); 138 } 139 140 public Pair3<Long, Long, String> getStartPosition() { 141 return startPosition; 142 } 143 144 public Pair3<Long, Long, String> getEndPosition() { 145 return endPosition; 146 } 147 148 public List<ResultColumn> getColumns() { 149 return columns; 150 } 151 152 public void addColumn(ResultColumn column) { 153 if (column != null && !columns.contains(column)) { 154 this.columns.add(column); 155 } 156 } 157 158 /** 159 * STRUCT tree: the field nodes below this result set's columns ({@code customer.address.city} below 160 * {@code customer}), made for a field read through a CTE or derived table. They are not columns of their own, so 161 * they are kept out of {@link #getColumns()}, which star expansion and positional writes walk; the output lists 162 * them after their columns ({@link #getColumnsWithFieldPaths()}), as a table lists its field path nodes 163 * (Mantis 4836). 164 */ 165 private final List<ResultColumn> fieldPathColumns = new ArrayList<ResultColumn>(); 166 private final java.util.Map<ResultColumn, ResultColumn> fieldPathBases = 167 new java.util.IdentityHashMap<ResultColumn, ResultColumn>(); 168 169 /** The field nodes by their structural identity ({@link FieldNodeKey}: base column and path), as made. */ 170 private final java.util.Map<FieldNodeKey, ResultColumn> fieldPathIndex = 171 new java.util.LinkedHashMap<FieldNodeKey, ResultColumn>(); 172 173 /** Makes {@code node}, a field node below {@code base}, one of the field path columns rather than a column. */ 174 public void addFieldPathColumn(ResultColumn node, ResultColumn base) { 175 addFieldPathColumn(node, base, null); 176 } 177 178 /** 179 * Makes {@code node}, the field node at {@code segments} below {@code base}, one of the field path columns rather 180 * than a column, and indexes it by its identity when the path is given. 181 */ 182 public void addFieldPathColumn(ResultColumn node, ResultColumn base, 183 java.util.List<gudusoft.gsqlparser.common.structured.StructuredPathSegment> segments) { 184 columns.remove(node); 185 if (!fieldPathColumns.contains(node)) { 186 fieldPathColumns.add(node); 187 fieldPathBases.put(node, base); 188 if (segments != null) { 189 FieldNodeKey key = FieldNodeKey.of(base, segments); 190 if (!fieldPathIndex.containsKey(key)) { 191 fieldPathIndex.put(key, node); 192 } 193 } 194 } 195 } 196 197 /** The field node with identity {@code key}, or null. */ 198 public ResultColumn getFieldPathNode(FieldNodeKey key) { 199 return fieldPathIndex.get(key); 200 } 201 202 /** The columns as the output lists them: each column followed by the field nodes below it. */ 203 public List<ResultColumn> getColumnsWithFieldPaths() { 204 if (fieldPathColumns.isEmpty()) { 205 return columns; 206 } 207 List<ResultColumn> published = new ArrayList<ResultColumn>(columns.size() + fieldPathColumns.size()); 208 for (ResultColumn column : columns) { 209 published.add(column); 210 for (ResultColumn node : fieldPathColumns) { 211 if (fieldPathBases.get(node) == column) { 212 published.add(node); 213 } 214 } 215 } 216 for (ResultColumn node : fieldPathColumns) { 217 if (!published.contains(node)) { 218 published.add(node); 219 } 220 } 221 return published; 222 } 223 224 public TParseTreeNode getGspObject() { 225 return gspObject; 226 } 227 228 public long getId() { 229 return id; 230 } 231 232 public boolean isTarget() { 233 return isTarget; 234 } 235 236 public String getSchema() { 237 return schema; 238 } 239 240 public String getDatabase() { 241 return database; 242 } 243 244 public ResultSetRelationRows getRelationRows(){ 245 return relationRows; 246 } 247 248 public String getServer() { 249 return server; 250 } 251 252 public boolean isDetermined() { 253 return isDetermined; 254 } 255 256 public void setDetermined(boolean isDetermined) { 257 this.isDetermined = isDetermined; 258 } 259 260 public void setTarget(boolean isTarget) { 261 this.isTarget = isTarget; 262 } 263 264 Map<String, AtomicInteger> getAliasMap() { 265 return aliasMap; 266 } 267 268 public String getProcedureId() { 269 return procedureId; 270 } 271 272 public void setProcedureId(String procedureId) { 273 this.procedureId = procedureId; 274 } 275}