001package gudusoft.gsqlparser.sqlenv; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.EExpressionType; 005import gudusoft.gsqlparser.TCustomSqlStatement; 006import gudusoft.gsqlparser.TGSqlParser; 007import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 008import gudusoft.gsqlparser.dlineage.util.Pair3; 009import gudusoft.gsqlparser.nodes.TColumnDefinition; 010import gudusoft.gsqlparser.nodes.TDeclareVariable; 011import gudusoft.gsqlparser.nodes.TDeclareVariableList; 012import gudusoft.gsqlparser.nodes.TFunctionCall; 013import gudusoft.gsqlparser.nodes.TObjectName; 014import gudusoft.gsqlparser.nodes.TParseTreeNode; 015import gudusoft.gsqlparser.nodes.TResultColumn; 016import gudusoft.gsqlparser.nodes.TTableElement; 017import gudusoft.gsqlparser.nodes.TTableElementList; 018import gudusoft.gsqlparser.nodes.TTypeName; 019import gudusoft.gsqlparser.nodes.TViewAliasItem; 020import gudusoft.gsqlparser.stmt.TCreateFunctionStmt; 021import gudusoft.gsqlparser.stmt.TCreateProcedureStmt; 022import gudusoft.gsqlparser.stmt.TCreateSchemaSqlStatement; 023import gudusoft.gsqlparser.stmt.TCreateSynonymStmt; 024import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement; 025import gudusoft.gsqlparser.stmt.TCreateTriggerStmt; 026import gudusoft.gsqlparser.stmt.TCreateViewSqlStatement; 027import gudusoft.gsqlparser.stmt.TStoredProcedureSqlStatement; 028import gudusoft.gsqlparser.stmt.TUseDatabase; 029import gudusoft.gsqlparser.stmt.mssql.TMssqlCreateFunction; 030import gudusoft.gsqlparser.stmt.mssql.TMssqlDeclare; 031import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateFunction; 032import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage; 033import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateProcedure; 034import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateTrigger; 035import gudusoft.gsqlparser.stmt.teradata.TTeradataCreateProcedure; 036import gudusoft.gsqlparser.stmt.snowflake.TUseSchema; 037import gudusoft.gsqlparser.util.SQLUtil; 038 039import java.io.ByteArrayInputStream; 040import java.io.IOException; 041import java.util.ArrayList; 042import java.util.List; 043import java.util.Properties; 044import java.util.Stack; 045 046public class TDDLSQLEnv extends TSQLEnv { 047 048 private String sql; 049 050 private TSQLEnv metadataSQLEnv; 051 052 private String globalDatabase = null; 053 054 private String globalSchema = null; 055 /** 056 * A Snowflake {@code USE <database>} unset the current schema. Distinct from 057 * {@code globalSchema == null} ("never set"), which is allowed to fall back 058 * to the batch-global {@link #getDefaultSchemaName()}. See GitHub #715. 059 */ 060 private boolean schemaUnsetByDatabaseSwitch = false; 061 062 private boolean init = false; 063 064 private boolean includeLocalTemporaryTables = true; 065 066 /** Disable for whole-script catalog preloading; call-frame temporary DDL needs positional scope. */ 067 public void setIncludeLocalTemporaryTables(boolean include) { 068 this.includeLocalTemporaryTables = include; 069 } 070 071 private Stack<TCustomSqlStatement> stmtStack = new Stack<TCustomSqlStatement>(); 072 073 public boolean isInit() { 074 return init; 075 } 076 077 public TDDLSQLEnv(String defaultServer, String defaultDatabase, String defaultSchema, EDbVendor dbVendor, String sql) { 078 this(defaultServer, defaultDatabase, defaultSchema, dbVendor, sql, null); 079 } 080 081 /** 082 * Same input, analyzed under an explicit identifier configuration. 083 * 084 * <p>DDL in the script registers objects in this environment, so the rules used to key them 085 * must be the run's rules — otherwise a later reference is compared by a relation the 086 * registration never used. A profile belonging to another vendor is not applied 087 * ({@link IdentifierProfile#forVendorOr}); null means the vendor default. 088 */ 089 public TDDLSQLEnv(String defaultServer, String defaultDatabase, String defaultSchema, EDbVendor dbVendor, 090 String sql, IdentifierProfile identifierProfile) { 091 super(dbVendor, IdentifierProfile.forVendorOr(identifierProfile, dbVendor)); 092 if(!SQLUtil.isEmpty(defaultServer) && !defaultServer.equals(TSQLEnv.DEFAULT_SERVER_NAME)) { 093 setDefaultServerName(defaultServer); 094 } 095 if(!SQLUtil.isEmpty(defaultDatabase) && !defaultDatabase.equals(TSQLEnv.DEFAULT_DB_NAME)) { 096 setDefaultCatalogName(defaultDatabase); 097 } 098 if(!SQLUtil.isEmpty(defaultSchema) && !defaultSchema.equals(TSQLEnv.DEFAULT_SCHEMA_NAME)) { 099 setDefaultSchemaName(defaultSchema); 100 } 101 this.sql = sql; 102 } 103 104 public TDDLSQLEnv(String defaultServer, String defaultDatabase, String defaultSchema, TSQLEnv metadataSQLEnv, EDbVendor dbVendor, String sql) { 105 this(defaultServer, defaultDatabase, defaultSchema, metadataSQLEnv, dbVendor, sql, null); 106 } 107 108 /** 109 * Same input, analyzed under an explicit identifier configuration. 110 * 111 * <p>DDL in the script registers objects in this environment, so the rules used to key them 112 * must be the run's rules — otherwise a later reference is compared by a relation the 113 * registration never used. A profile belonging to another vendor is not applied 114 * ({@link IdentifierProfile#forVendorOr}); null means the vendor default. 115 */ 116 public TDDLSQLEnv(String defaultServer, String defaultDatabase, String defaultSchema, TSQLEnv metadataSQLEnv, 117 EDbVendor dbVendor, String sql, IdentifierProfile identifierProfile) { 118 super(dbVendor, IdentifierProfile.forVendorOr( 119 identifierProfile != null || metadataSQLEnv == null 120 ? identifierProfile 121 // A metadata environment carries the configuration its own catalog was 122 // indexed with; this DDL environment merges into it, so it must agree. 123 : metadataSQLEnv.getIdentifierProfile(), 124 dbVendor)); 125 if(!SQLUtil.isEmpty(defaultServer) && !defaultServer.equals(TSQLEnv.DEFAULT_SERVER_NAME)) { 126 setDefaultServerName(defaultServer); 127 } 128 if(!SQLUtil.isEmpty(defaultDatabase) && !defaultDatabase.equals(TSQLEnv.DEFAULT_DB_NAME)) { 129 setDefaultCatalogName(defaultDatabase); 130 } 131 if(!SQLUtil.isEmpty(defaultSchema) && !defaultSchema.equals(TSQLEnv.DEFAULT_SCHEMA_NAME)) { 132 setDefaultSchemaName(defaultSchema); 133 } 134 this.sql = sql; 135 this.metadataSQLEnv = metadataSQLEnv; 136 if(metadataSQLEnv!=null) { 137 this.setDefaultServerName(metadataSQLEnv.getDefaultServerName()); 138 } 139 } 140 141 @Override 142 public void initSQLEnv() { 143 synchronized (this) { 144 if (sql == null || init) 145 return; 146 TGSqlParser sqlparser = new TGSqlParser(getDBVendor()); 147 try { 148 // This parser reads THIS environment's own DDL, so it runs under THIS 149 // environment's identifier configuration. Without this, a parser with neither an 150 // environment nor a profile makes TGSqlParser.freezeIdentifierProfile build a 151 // second environment on the vendor default, and the analysis briefly holds two 152 // configurations at once — measured on the BigQuery I6D5KX fixture, whose 153 // sidecar asks for case-insensitive table names while that second environment 154 // answered a lookup for CUSTOMERS with a miss under the default sensitive rule. 155 // 156 // No known output changes: the objects this method registers land in THIS 157 // environment, keyed by its own service, so the second environment is never read. 158 // This restores the one-configuration-per-analysis invariant rather than fixing a 159 // wrong answer, and the fixture's lineage is byte-identical with and without it. 160 // 161 // Only when there is no metadata environment. With one, the parser takes that 162 // environment's profile, and freezeIdentifierProfile already raises a conflict 163 // when the two disagree — setting ours here would turn that into a throw. 164 if (metadataSQLEnv == null) { 165 sqlparser.setIdentifierProfile(getIdentifierProfile()); 166 } 167 sqlparser.setSqlEnv(metadataSQLEnv); 168 sqlparser.sqltext = sql; 169 sqlparser.parse(); 170 } catch (Exception e) { 171 // Parse failure - log and continue with whatever statements were parsed 172 } 173 List<TCustomSqlStatement> stmts = new ArrayList<TCustomSqlStatement>(); 174 if (sqlparser.sqlstatements != null) { 175 for (int j = 0; j < sqlparser.sqlstatements.size(); j++) { 176 TCustomSqlStatement stmt = sqlparser.sqlstatements.get(j); 177 extractDDLStmts(stmts, stmt); 178 } 179 } 180 181 if (!stmts.isEmpty()) { 182 for (int j = 0; j < stmts.size(); j++) { 183 TCustomSqlStatement stmt = stmts.get(j); 184 analyzeSQLEnv(stmt); 185 } 186 init = true; 187 } 188 stmts.clear(); 189 sql = null; 190 } 191 } 192 193 private void extractDDLStmts(List<TCustomSqlStatement> stmts, TCustomSqlStatement stmt) { 194 if (stmt instanceof TUseDatabase || stmt instanceof TUseSchema 195 || stmt instanceof TCreateSchemaSqlStatement 196 || stmt instanceof TCreateTableSqlStatement || stmt instanceof TMssqlDeclare 197 || stmt instanceof TStoredProcedureSqlStatement 198 || (stmt instanceof TMssqlCreateFunction 199 && ((TMssqlCreateFunction) stmt).getReturnTableDefinitions() != null)) { 200 stmts.add(stmt); 201 } else if (stmt instanceof TCreateViewSqlStatement) { 202 stmts.add(stmt); 203 } else if (stmt instanceof TCreateSynonymStmt) { 204 stmts.add(stmt); 205 } else if (stmt.getStatements() != null && stmt.getStatements().size() > 0) { 206 for (int i = 0; i < stmt.getStatements().size(); i++) { 207 extractDDLStmts(stmts, stmt.getStatements().get(i)); 208 } 209 } 210 } 211 212 private void analyzeSQLEnv(TCustomSqlStatement stmt) { 213 stmtStack.push(stmt); 214 if (stmt instanceof TUseDatabase) { 215 TUseDatabase useDatabase = (TUseDatabase) stmt; 216 analyzeUseDatabase(useDatabase); 217 } else if (stmt instanceof TUseSchema) { 218 // A Snowflake schema switch parses to its own statement class, not to 219 // TUseDatabase, so it has to be seen here or the "schema was unset by 220 // a database switch" flag would survive a subsequent USE SCHEMA and 221 // register later objects under DEFAULT instead of the schema the 222 // script just named. We only lift the flag: the schema name itself 223 // still comes from getDefaultSchemaName(), exactly as before, so this 224 // restores the previous behaviour rather than changing it. 225 schemaUnsetByDatabaseSwitch = false; 226 } else if (stmt instanceof TMssqlDeclare) { 227 TMssqlDeclare declare = (TMssqlDeclare) stmt; 228 analyzeMssqlDeclare(declare); 229 } else if (stmt instanceof TMssqlCreateFunction) { 230 TMssqlCreateFunction createFunction = (TMssqlCreateFunction) stmt; 231 analyzeMssqlCreateFunction(createFunction); 232 } else if (stmt instanceof TCreateSchemaSqlStatement) { 233 TCreateSchemaSqlStatement createSchema = (TCreateSchemaSqlStatement) stmt; 234 analyzeCreateSchema(createSchema); 235 } else if (stmt instanceof TCreateTableSqlStatement) { 236 TCreateTableSqlStatement createTable = (TCreateTableSqlStatement) stmt; 237 analyzeCreateTable(createTable); 238 } else if (stmt instanceof TCreateViewSqlStatement) { 239 TCreateViewSqlStatement createView = (TCreateViewSqlStatement) stmt; 240 analyzeCreateView(createView); 241 } else if (stmt instanceof TCreateSynonymStmt) { 242 TCreateSynonymStmt createSynonym = (TCreateSynonymStmt) stmt; 243 analyzeCreateSynonym(createSynonym); 244 } else if (stmt instanceof TStoredProcedureSqlStatement) { 245 TStoredProcedureSqlStatement procedure = (TStoredProcedureSqlStatement) stmt; 246 analyzeStoredProcedureStmt(procedure); 247 } 248 stmtStack.pop(); 249 } 250 251 private void analyzeStoredProcedureStmt(TStoredProcedureSqlStatement procedure) { 252 if (procedure instanceof TPlsqlCreatePackage) { 253 analyzeProcedure(procedure, ESQLDataObjectType.dotOraclePackage); 254 return; 255 } 256 if (procedure instanceof TCreateTriggerStmt) { 257 analyzeProcedure(procedure, ESQLDataObjectType.dotTrigger); 258 return; 259 } 260 if (procedure instanceof TCreateFunctionStmt) { 261 analyzeProcedure(procedure, ESQLDataObjectType.dotFunction); 262 return; 263 } 264 if (procedure instanceof TCreateProcedureStmt) { 265 analyzeProcedure(procedure, ESQLDataObjectType.dotProcedure); 266 return; 267 } 268 } 269 270 private void analyzeProcedure(TStoredProcedureSqlStatement procedure, ESQLDataObjectType type) { 271 TObjectName procedureName = getProcedureName(procedure); 272 if(procedureName == null){ 273 return; 274 } 275 TSQLRoutine sqlProcedure = addSQLRoutineToSQLEnv(procedureName, type); 276 sqlProcedure.setDefinition(procedure.toString()); 277 278 if(procedure instanceof TPlsqlCreatePackage) { 279 TPlsqlCreatePackage oraclePackage = (TPlsqlCreatePackage)procedure; 280 if (oraclePackage.getDeclareStatements() != null) { 281 for (int i = 0; i < oraclePackage.getDeclareStatements().size(); ++i) { 282 TCustomSqlStatement stmt = oraclePackage.getDeclareStatements().get(i); 283 if (stmt instanceof TPlsqlCreateTrigger) { 284 analyzePackageProcedure((TSQLOraclePackage) sqlProcedure, (TStoredProcedureSqlStatement)stmt, 285 ESQLDataObjectType.dotTrigger); 286 } 287 if (stmt instanceof TPlsqlCreateFunction) { 288 analyzePackageProcedure((TSQLOraclePackage) sqlProcedure, (TStoredProcedureSqlStatement)stmt, 289 ESQLDataObjectType.dotFunction); 290 } 291 if (stmt instanceof TPlsqlCreateProcedure) { 292 analyzePackageProcedure((TSQLOraclePackage) sqlProcedure, (TStoredProcedureSqlStatement)stmt, 293 ESQLDataObjectType.dotProcedure); 294 } 295 } 296 } 297 } 298 } 299 300 private void analyzePackageProcedure(TSQLOraclePackage oraclePackage, TStoredProcedureSqlStatement procedure, ESQLDataObjectType type) { 301 TObjectName procedureName = getProcedureName(procedure); 302 if(procedureName == null){ 303 return; 304 } 305 TSQLProcedure object = (TSQLProcedure) oraclePackage 306 .createSchemaObject(getQualifiedTableName(procedureName), type); 307 object.setDefinition(procedure.toString()); 308 } 309 310 311 private TObjectName getProcedureName(TParseTreeNode procedureObject) { 312 if(procedureObject instanceof TTeradataCreateProcedure) 313 { 314 return ((TTeradataCreateProcedure)procedureObject).getProcedureName(); 315 } 316 if(procedureObject instanceof TStoredProcedureSqlStatement) 317 { 318 return ((TStoredProcedureSqlStatement)procedureObject).getStoredProcedureName(); 319 } 320 if(procedureObject instanceof TFunctionCall) 321 { 322 return ((TFunctionCall)procedureObject).getFunctionName(); 323 } 324 return null; 325 } 326 327 private void analyzeCreateTable(TCreateTableSqlStatement createTable) { 328 // A call-frame table (SQL Server #t) is registered at its declaration by resolver2, where it is visible. 329 if (!includeLocalTemporaryTables 330 && TemporaryTableSemantics.ofDeclaration(createTable) == TemporaryTableSemantics.Scope.CALL) return; 331 if (createTable.getTables() != null && createTable.getTables().size() > 0) { 332 if (createTable.getColumnList() != null && createTable.getColumnList().size() > 0) { 333 TObjectName tableName = createTable.getTableName(); 334 TSQLTable table = addTableToSQLEnv(tableName); 335 for (int i = 0; i < createTable.getColumnList().size(); i++) { 336 TColumnDefinition column = createTable.getColumnList().getColumn(i); 337 if (column != null && column.getColumnName() != null) { 338 TObjectName columnName = column.getColumnName(); 339 addTableColumnToSQLEnv(table, columnName, column.getDatatype()); 340 } 341 } 342 table.setPriority(2); 343 } else if (createTable.getSubQuery() != null && createTable.getSubQuery().getResultColumnList() != null) { 344 if(createTable.getSubQuery().getResultColumnList().toString().indexOf("*") != -1) { 345 return; 346 } 347 TSQLTable table = addTableToSQLEnv(createTable.getTargetTable().getTableName()); 348 if (table.getColumns(true) == null || table.getColumns(true).isEmpty()) { 349 for (int i = 0; i < createTable.getSubQuery().getResultColumnList().size(); i++) { 350 TResultColumn resultColumn = createTable.getSubQuery().getResultColumnList().getResultColumn(i); 351 addTableColumnToSQLEnv(table, getObjectName(resultColumn)); 352 } 353 } 354 } 355 } 356 } 357 358 private void analyzeCreateView(TCreateViewSqlStatement createView) { 359 if (createView.getViewName() != null) { 360 if (createView.getViewAliasClause() != null) { 361 TSQLTable table = addTableToSQLEnv(createView.getViewName()); 362 table.setView(true); 363 for (int i = 0; i < createView.getViewAliasClause().getViewAliasItemList().size(); i++) { 364 TViewAliasItem column = createView.getViewAliasClause().getViewAliasItemList().getViewAliasItem(i); 365 if (column != null && column.getAlias() != null) { 366 TObjectName columnName = column.getAlias(); 367 addTableColumnToSQLEnv(table, columnName); 368 } 369 } 370 table.setPriority(2); 371 } else if (createView.getSubquery().getResultColumnList() != null) { 372 if(createView.getSubquery().getResultColumnList().toString().indexOf("*") != -1) { 373 return; 374 } 375 TSQLTable table = addTableToSQLEnv(createView.getViewName()); 376 table.setView(true); 377 for (int i = 0; i < createView.getSubquery().getResultColumnList().size(); i++) { 378 TResultColumn resultColumn = createView.getSubquery().getResultColumnList().getResultColumn(i); 379 addTableColumnToSQLEnv(table, getObjectName(resultColumn)); 380 } 381 } 382 } 383 } 384 385 private void analyzeCreateSynonym(TCreateSynonymStmt createSynonym) { 386 TObjectName synonymName = createSynonym.getSynonymName(); 387 TObjectName forName = createSynonym.getForName(); 388 if (synonymName == null || forName == null) { 389 return; 390 } 391 if (!isEnableGetMetadataFromDDL()) { 392 return; 393 } 394 String qualifiedSynonymName = buildFullyQualifiedTableName(synonymName); 395 TSQLSchemaObject schemaObject = doAddSchemaObject(qualifiedSynonymName, ESQLDataObjectType.dotSynonyms); 396 if (!(schemaObject instanceof TSQLSynonyms)) { 397 return; 398 } 399 TSQLSynonyms synonym = (TSQLSynonyms) schemaObject; 400 synonym.setBaseTarget( 401 TSQLEnv.getDatabaseName(forName), 402 TSQLEnv.getSchemaName(forName), 403 TSQLEnv.getObjectName(forName)); 404 synonym.setPriority(2); 405 } 406 407 private TObjectName getObjectName(TResultColumn resultColumn) { 408 if (resultColumn.getAliasClause() != null && resultColumn.getAliasClause().getAliasName() != null) { 409 return resultColumn.getAliasClause().getAliasName(); 410 } 411 if (resultColumn.getFieldAttr() != null) { 412 return resultColumn.getFieldAttr(); 413 } 414 if (resultColumn.getExpr() != null 415 && resultColumn.getExpr().getExpressionType() == EExpressionType.simple_object_name_t) { 416 return resultColumn.getExpr().getObjectOperand(); 417 } else if (!SQLUtil.isEmpty(resultColumn.getColumnNameOnly())) { 418 TObjectName objectName = new TObjectName(); 419 objectName.setString(resultColumn.getColumnNameOnly()); 420 return objectName; 421 } else { 422 return null; 423 } 424 } 425 426 private void analyzeUseDatabase(TUseDatabase useDatabase) { 427 TObjectName databaseName = useDatabase.getDatabaseName(); 428 429 if (databaseName == null) { 430 return; 431 } 432 433 // MantisBT 4677 — Snowflake states the form outright, so do not re-guess 434 // it from catalog contents. There, USE <name> with an unqualified name 435 // is a DATABASE switch and USE <db>.<schema> is a SCHEMA switch; the 436 // splitter and the grammar already classified the statement on that 437 // rule. Guessing here would silently flip a bare USE back to a schema 438 // whenever the current database happens to contain a same-named schema 439 // — a wrong session context with nothing to flag it. Other vendors, 440 // whose bare USE really is ambiguous, keep the catalog-based guess. 441 if (getDBVendor() == EDbVendor.dbvsnowflake) { 442 if (useDatabase.isSchema()) { 443 globalSchema = databaseName.toString(); 444 schemaUnsetByDatabaseSwitch = false; 445 } else { 446 String catalogName = databaseName.toString(); 447 getSQLCatalog(catalogName, true); 448 globalDatabase = catalogName; 449 // The schema carried over from the PREVIOUS database is no 450 // longer valid once the database changes; leaving it would 451 // qualify later names as <newdb>.<oldschema>. See the matching 452 // note in DatabaseContextTracker. 453 globalSchema = null; 454 // Nulling globalSchema alone is not enough: getCurrentSchemaName 455 // falls back to getDefaultSchemaName(), which TUseSchema wrote 456 // while PARSING and which therefore holds the last USE SCHEMA of 457 // the whole script - the very value this switch invalidated. The 458 // flag says "unset", as opposed to "never set", so the fallback 459 // is skipped and objects created after the switch register under 460 // DEFAULT_SCHEMA_NAME instead of the old database's schema. 461 // GitHub #715. 462 schemaUnsetByDatabaseSwitch = true; 463 } 464 return; 465 } 466 String qualifiedSchemaName = databaseName.toString(); 467 if (getNumberOfPart(databaseName) == 1) { 468 qualifiedSchemaName = getCurrentDatabaseName() + "." + qualifiedSchemaName; 469 } 470 if (getSQLSchema(qualifiedSchemaName, false) != null) { 471 globalSchema = databaseName.toString(); 472 } else { 473 String catalogName = databaseName.toString(); 474 getSQLCatalog(catalogName, true); 475 globalDatabase = catalogName; 476 } 477 } 478 479 private int getNumberOfPart(TObjectName name) { 480 return SQLUtil.parseNames(name.toString()).size(); 481 } 482 483 private int getNumberOfPart(String tableName) { 484 return SQLUtil.parseNames(tableName).size(); 485 } 486 487 private void analyzeCreateSchema(TCreateSchemaSqlStatement createSchema) { 488 TObjectName schemaName = createSchema.getSchemaName(); 489 if (schemaName != null) { 490 String qualifiedSchemaName = schemaName.toString(); 491 if (getNumberOfPart(schemaName) == 1) { 492 qualifiedSchemaName = getCurrentDatabaseName() + "." + qualifiedSchemaName; 493 } 494 getSQLSchema(qualifiedSchemaName, true); 495 } 496 } 497 498 private String getCurrentDatabaseName() { 499 Pair3<String, String, String> info = fillSchemaInfo(); 500 if(!SQLUtil.isEmpty(info.second)) { 501 return info.second; 502 } 503 if (!SQLUtil.isEmpty(globalDatabase)) { 504 return globalDatabase; 505 } else if (!SQLUtil.isEmpty(getDefaultCatalogName())) { 506 return getDefaultCatalogName(); 507 } else 508 getSQLCatalog(DEFAULT_DB_NAME, true); 509 return DEFAULT_DB_NAME; 510 } 511 512 private String getCurrentSchemaName() { 513 Pair3<String, String, String> info = fillSchemaInfo(); 514 if(!SQLUtil.isEmpty(info.third)) { 515 return info.third; 516 } 517 if (!SQLUtil.isEmpty(globalSchema)) { 518 return globalSchema; 519 } else if (schemaUnsetByDatabaseSwitch) { 520 // Unset - unless this catalog proves the new database has a PUBLIC, 521 // which is what Snowflake makes current. See 522 // TSQLEnv.findSchemaAfterDatabaseSwitch. 523 String afterSwitch = findSchemaAfterDatabaseSwitch(getCurrentDatabaseName()); 524 return SQLUtil.isEmpty(afterSwitch) ? DEFAULT_SCHEMA_NAME : afterSwitch; 525 } else if (!SQLUtil.isEmpty(getDefaultSchemaName())) { 526 return getDefaultSchemaName(); 527 } else 528 return DEFAULT_SCHEMA_NAME; 529 } 530 531 private Pair3<String, String, String> fillSchemaInfo() { 532 String server = null; 533 String database = null; 534 String schema = null; 535 536 TCustomSqlStatement stmt = DlineageUtil.getTopStmt(stmtStack.peek()); 537 String sqlComment = null; 538 try { 539 sqlComment = stmt.getCommentBeforeNode(); 540 } catch (Exception e) { 541 // e.printStackTrace(); 542 } 543 if (!SQLUtil.isEmpty(sqlComment) && (sqlComment.indexOf("db") != -1 || sqlComment.indexOf("schema") != -1)) { 544 Properties properties = new Properties(); 545 try { 546 properties.load( 547 new ByteArrayInputStream(sqlComment.replace("--", "").trim().replace(",", "\n").getBytes())); 548 if (SQLUtil.isEmpty(server) && properties.containsKey("db-instance")) { 549 server = properties.getProperty("db-instance"); 550 if (!SQLUtil.isEmpty(server) && !server.equals(TSQLEnv.DEFAULT_SERVER_NAME)) { 551 if (SQLUtil.isEmpty(this.getDefaultServerName()) 552 || this.getDefaultServerName().equals(TSQLEnv.DEFAULT_SERVER_NAME)) { 553 this.setDefaultServerName(server); 554 } 555 } 556 } 557 if (SQLUtil.isEmpty(database) && properties.containsKey("db")) { 558 database = properties.getProperty("db"); 559 if (database.indexOf(".") != -1) { 560 database = SQLUtil.quoteDottedName(getDBVendor(), ESQLDataObjectType.dotCatalog, database); 561 } 562 } 563 if (SQLUtil.isEmpty(schema) && properties.containsKey("schema")) { 564 schema = properties.getProperty("schema"); 565 if (schema.indexOf(".") != -1) { 566 schema = SQLUtil.quoteDottedName(getDBVendor(), ESQLDataObjectType.dotSchema, schema); 567 } 568 } 569 } catch (IOException e) { 570 e.printStackTrace(); 571 } 572 } 573 574 Pair3<String, String, String> info = new Pair3<String, String, String>(server, database, schema); 575 return info; 576 } 577 578 579 private void analyzeMssqlCreateFunction(TMssqlCreateFunction createFunction) { 580 if (createFunction.getReturnTableVaraible() != null && createFunction.getReturnTableDefinitions() != null) { 581 TObjectName tableName = createFunction.getReturnTableVaraible(); 582 TSQLTable table = addTableToSQLEnv(tableName); 583 584 for (int j = 0; j < createFunction.getReturnTableDefinitions().size(); j++) { 585 TTableElement tableElement = createFunction.getReturnTableDefinitions().getTableElement(j); 586 TColumnDefinition column = tableElement.getColumnDefinition(); 587 if (column != null && column.getColumnName() != null) { 588 TObjectName columnName = column.getColumnName(); 589 addTableColumnToSQLEnv(table, columnName); 590 } 591 } 592 } 593 } 594 595 private void addTableColumnToSQLEnv(TSQLTable table, TObjectName columnName) { 596 if (columnName == null) { 597 return; 598 } 599 String column = columnName.getColumnNameOnly(); 600 if (!SQLUtil.isEmpty(column)) { 601 table.addColumn(column); 602 } else { 603 column = columnName.toString(); 604 if (column.indexOf(".") != -1) { 605 List<String> splits = SQLUtil.parseNames(column); 606 column = splits.get(splits.size() - 1); 607 } 608 table.addColumn(column); 609 } 610 } 611 612 private void addTableColumnToSQLEnv(TSQLTable table, TObjectName columnName, TTypeName dataType) { 613 if(columnName == null){ 614 return; 615 } 616 String column = columnName.getColumnNameOnly(); 617 if (!SQLUtil.isEmpty(column)) { 618 table.addColumn(column, dataType); 619 } else { 620 column = columnName.toString(); 621 if (column.indexOf(".") != -1) { 622 List<String> splits = SQLUtil.parseNames(column); 623 column = splits.get(splits.size() - 1); 624 } 625 table.addColumn(column, dataType); 626 } 627 } 628 629 private TSQLTable addTableToSQLEnv(TObjectName tableName) { 630 return addTable(buildFullyQualifiedTableName(tableName), true); 631 } 632 633 private String buildFullyQualifiedTableName(TObjectName tableName) { 634 String qualifiedTableName = getQualifiedTableName(tableName); 635 if (getNumberOfPart(qualifiedTableName) == 1) { 636 if(!TSQLEnv.supportSchema(getDBVendor())){ 637 qualifiedTableName = TSQLEnv.DEFAULT_DB_NAME + "." + getCurrentDatabaseName() + "." + qualifiedTableName; 638 } 639 else { 640 qualifiedTableName = getCurrentDatabaseName() + "." + getCurrentSchemaName() + "." + qualifiedTableName; 641 } 642 } else if (getNumberOfPart(qualifiedTableName) == 2) { 643 if(!TSQLEnv.supportSchema(getDBVendor())){ 644 qualifiedTableName = TSQLEnv.DEFAULT_DB_NAME + "." + qualifiedTableName; 645 } 646 else { 647 qualifiedTableName = getCurrentDatabaseName() + "." + qualifiedTableName; 648 } 649 } 650 return qualifiedTableName; 651 } 652 653 private TSQLRoutine addSQLRoutineToSQLEnv(TObjectName procedureName, ESQLDataObjectType type) { 654 String qualifiedProcedureName = getQualifiedTableName(procedureName); 655 if (getNumberOfPart(qualifiedProcedureName) == 1) { 656 if(!TSQLEnv.supportSchema(getDBVendor())){ 657 qualifiedProcedureName = TSQLEnv.DEFAULT_DB_NAME + "." + getCurrentDatabaseName() + "." + qualifiedProcedureName; 658 } 659 else { 660 qualifiedProcedureName = getCurrentDatabaseName() + "." + getCurrentSchemaName() + "." + qualifiedProcedureName; 661 } 662 } else if (getNumberOfPart(qualifiedProcedureName) == 2) { 663 if(!TSQLEnv.supportSchema(getDBVendor())){ 664 qualifiedProcedureName = TSQLEnv.DEFAULT_DB_NAME + "." + qualifiedProcedureName; 665 } 666 else { 667 qualifiedProcedureName = getCurrentDatabaseName() + "." + qualifiedProcedureName; 668 } 669 } 670 return addSQLRoutine(qualifiedProcedureName, true, type); 671 } 672 673 private String getQualifiedTableName(TObjectName table) { 674 String tableName = table.toString(); 675 if (metadataSQLEnv == null) { 676 return tableName; 677 } 678 List<String> segments = SQLUtil.parseNames(tableName); 679 if (segments.size() > 2) { 680 return tableName; 681 } 682 String schemaName = null; 683 if (segments.size() > 1) { 684 schemaName = segments.get(segments.size() - 2); 685 } 686 int occurrence = 0; 687 int maxPriority = -1; 688 String tableDatabase = null; 689 String tableSchema = null; 690 String simpleTableName = DlineageUtil.getSimpleTableName(tableName); 691 for (TSQLCatalog catalog : metadataSQLEnv.getCatalogList()) { 692 if (SQLUtil.isEmpty(schemaName)) { 693 for (TSQLSchema schema : catalog.getSchemaList()) { 694 TSQLTable tsqlTable = schema.findTable(simpleTableName); 695 if (tsqlTable != null) { 696 occurrence += 1; 697 if (tsqlTable.getPriority() > maxPriority) { 698 tableDatabase = catalog.getName(); 699 tableSchema = schema.getName(); 700 maxPriority = tsqlTable.getPriority(); 701 } 702 } 703 } 704 if (occurrence > 1) { 705 break; 706 } 707 } else { 708 TSQLSchema schema = catalog.getSchema(schemaName, false); 709 if (schema != null) { 710 TSQLTable tsqlTable = schema.findTable(simpleTableName); 711 if (tsqlTable != null) { 712 occurrence += 1; 713 if (tsqlTable.getPriority() > maxPriority) { 714 tableDatabase = catalog.getName(); 715 tableSchema = schema.getName(); 716 maxPriority = tsqlTable.getPriority(); 717 } 718 } 719 } 720 } 721 } 722 if (occurrence == 1 || maxPriority > 0) { 723 StringBuilder qualifiedTableName = new StringBuilder(); 724 if (tableDatabase != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(tableDatabase)) { 725 qualifiedTableName.append(tableDatabase).append("."); 726 } 727 if (tableSchema != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(tableSchema)) { 728 qualifiedTableName.append(tableSchema).append("."); 729 } 730 return qualifiedTableName.append(simpleTableName).toString(); 731 } 732 return tableName; 733 } 734 735 private void analyzeMssqlDeclare(TMssqlDeclare declare) { 736 TDeclareVariableList variables = declare.getVariables(); 737 if (variables == null) { 738 return; 739 } 740 for (int i = 0; i < variables.size(); i++) { 741 TDeclareVariable variable = variables.getDeclareVariable(i); 742 if (variable.getTableTypeDefinitions() == null || variable.getTableTypeDefinitions().size() == 0) { 743 continue; 744 } 745 746 TObjectName tableName = variable.getVariableName(); 747 TSQLTable table = addTableToSQLEnv(tableName); 748 749 TTableElementList columns = variable.getTableTypeDefinitions(); 750 for (int j = 0; j < columns.size(); j++) { 751 TTableElement tableElement = columns.getTableElement(j); 752 TColumnDefinition column = tableElement.getColumnDefinition(); 753 if (column != null && column.getColumnName() != null) { 754 TObjectName columnName = column.getColumnName(); 755 addTableColumnToSQLEnv(table, columnName); 756 } 757 } 758 } 759 } 760 761 public static void main(String[] args) { 762 TSQLEnv sqlenv = new TDDLSQLEnv("deawirddap001", "mio", "public", EDbVendor.dbvredshift, SQLUtil.getFileContent("C:\\Users\\KK\\Desktop\\ddl.sql")); 763 sqlenv.initSQLEnv(); 764 System.out.println(sqlenv.toString()); 765 } 766}