001package gudusoft.gsqlparser.sqlenv; 002 003 004import gudusoft.gsqlparser.TBaseType; 005import gudusoft.gsqlparser.util.SQLUtil; 006 007import java.util.*; 008 009/** 010 * SQL schema, contains a list of schema objects. 011 */ 012public class TSQLSchema extends TSQLObject { 013 014 015 public String getQualifiedName(){ 016 return catalog.name+"."+name; 017 } 018 019 private TSQLCatalog catalog; 020 021 public TSQLCatalog getCatalog() { 022 return catalog; 023 } 024 025 // ===== Shadow Introduction: New type-specific indexes (Phase 2) ===== 026 // These LinkedHashMaps provide O(1) lookup per object type, replacing the mixed schemaObjectMap 027 private final LinkedHashMap<String, TSQLTable> tables = new LinkedHashMap<>(); 028 private final LinkedHashMap<String, TSQLFunction> functions = new LinkedHashMap<>(); 029 private final LinkedHashMap<String, TSQLProcedure> procedures = new LinkedHashMap<>(); 030 private final LinkedHashMap<String, TSQLTrigger> triggers = new LinkedHashMap<>(); 031 private final LinkedHashMap<String, TSQLOraclePackage> oraclePackages = new LinkedHashMap<>(); 032 private final LinkedHashMap<String, TSQLSynonyms> synonyms = new LinkedHashMap<>(); 033 034 // ===== Phase 3: Bucketed indexes for SQL Server COLLATION_BASED ===== 035 // These provide ~25x performance improvement for SQL Server (10,000 objects: 20μs → 800ns) 036 private BucketedIndex bucketedTables; 037 private BucketedIndex bucketedFunctions; 038 private BucketedIndex bucketedProcedures; 039 private BucketedIndex bucketedTriggers; 040 private BucketedIndex bucketedOraclePackages; 041 private BucketedIndex bucketedSynonyms; 042 043 // IdentifierService for consistent key generation (lazy initialization) 044 private IdentifierService identifierService; 045 046 // CollatorProvider for SQL Server (lazy initialization) 047 private CollatorProvider collatorProvider; 048 049 // ===== Phase 6: Schema seal mechanism for thread-safety hardening ===== 050 /** 051 * Seal state flag (volatile for thread visibility). 052 */ 053 private volatile boolean sealed = false; 054 055 /** 056 * Seal this schema to prevent further modifications (Phase 6). 057 * 058 * <p>See {@link TSQLEnv#seal()} for detailed documentation. 059 */ 060 public void seal() { 061 this.sealed = true; 062 } 063 064 /** 065 * Check if this schema is sealed (Phase 6). 066 * 067 * @return true if sealed, false otherwise 068 */ 069 public boolean isSealed() { 070 return sealed; 071 } 072 073 /** 074 * Check if schema is not sealed, throw exception if sealed and enforcement is enabled. 075 * 076 * @throws IllegalStateException if sealed and TBaseType.ENFORCE_CATALOG_SEAL is true 077 */ 078 private void checkNotSealed() { 079 if (sealed && TBaseType.ENFORCE_CATALOG_SEAL) { 080 throw new IllegalStateException("Cannot modify sealed schema. Call seal() marks schema as read-only."); 081 } 082 } 083 084 /** 085 * Create a new instance of the schema, added to the catalog. 086 * 087 * @param sqlCatalog catalog contains this schema 088 * @param schemaName name of the schema 089 */ 090 public TSQLSchema(TSQLCatalog sqlCatalog,String schemaName){ 091 super(sqlCatalog.getSqlEnv(), schemaName,ESQLDataObjectType.dotSchema); 092 this.catalog = sqlCatalog; 093 this.catalog.addSchema(this); 094 } 095 096 /** 097 * Get or create IdentifierService (lazy initialization) 098 */ 099 private IdentifierService getIdentifierService() { 100 if (identifierService == null) { 101 IdentifierProfile profile = IdentifierProfile.forVendor( 102 this.sqlEnv.getDBVendor(), 103 IdentifierProfile.VendorFlags.defaults() 104 ); 105 identifierService = new IdentifierService(profile, null); 106 } 107 return identifierService; 108 } 109 110 /** 111 * Get or create CollatorProvider (lazy initialization, SQL Server only) 112 */ 113 private CollatorProvider getCollatorProvider() { 114 if (collatorProvider == null) { 115 collatorProvider = new CollatorProvider(); 116 } 117 return collatorProvider; 118 } 119 120 /** 121 * Check if SQL Server and bucketed index is enabled 122 */ 123 private boolean shouldUseBucketedIndex() { 124 return TBaseType.USE_BUCKETED_INDEX && 125 (this.sqlEnv.getDBVendor() == gudusoft.gsqlparser.EDbVendor.dbvmssql || 126 this.sqlEnv.getDBVendor() == gudusoft.gsqlparser.EDbVendor.dbvazuresql); 127 } 128 129 /** 130 * Slice S3: cache of whether the hierarchical type-specific map is globally 131 * legacy-compatible for a given {@code (vendor, objectType)} pair. 132 * 133 * <p>Key format: {@code "<EDbVendor.name()>|<ESQLDataObjectType.name()>"}. 134 * Both the IdentifierProfile (built from {@link IdentifierProfile#forVendor}) 135 * and the legacy {@link TSQLEnv} per-vendor case-sensitivity maps are static 136 * relative to the (vendor, type) tuple, so the answer is stable for the 137 * JVM lifetime and safe to cache process-wide. 138 */ 139 private static final java.util.concurrent.ConcurrentHashMap<String, Boolean> 140 HIERARCHICAL_COMPAT_CACHE = new java.util.concurrent.ConcurrentHashMap<>(); 141 142 /** 143 * Slice S3: detect whether the hierarchical type-specific map can be safely 144 * consulted for the entire {@code (vendor, objectType)} pair. 145 * 146 * <p>The hierarchical map keys come from {@link IdentifierService#keyForMap}. 147 * The legacy {@code schemaObjectMap} keys come from 148 * {@link gudusoft.gsqlparser.util.SQLUtil#getIdentifierNormalName}. 149 * 150 * <p>For several vendor/type combinations the two key functions diverge: 151 * <ul> 152 * <li>SQL Server / Azure SQL with {@code COLLATION_BASED} rules 153 * ({@code IdentifierRules.forSQLServer}: {@code CaseFold.NONE}) when 154 * {@link TSQLEnv#tableCollationCaseSensitive} reports {@code false} 155 * (legacy adds a {@code toUpperCase} pass).</li> 156 * <li>BigQuery tables ({@code IdentifierRules.forBigQueryTable}: 157 * {@code CaseFold.NONE / SENSITIVE}) where 158 * {@link TSQLEnv#tableCollationCaseSensitive} is {@code false}.</li> 159 * <li>Hive/Teradata routines and any vendor whose {@link IdentifierRules} 160 * differ from the legacy {@link TSQLEnv} per-type case-sensitivity 161 * map.</li> 162 * </ul> 163 * 164 * <p>When the two diverge, distinct case-different writes land under 165 * different keys in hierarchical (both retained) but collapse to the same 166 * key in legacy (last write wins). A subsequent lookup that happens to 167 * use a probe input where the two functions <em>locally</em> agree (e.g. 168 * an already-uppercase {@code "FOO"} on BigQuery) would still hit the 169 * stale earlier hierarchical entry while legacy holds the authoritative 170 * later write. So input-local parity is insufficient — the gate must be 171 * vendor/type-global. 172 * 173 * <p>We probe once with a case-mixed ASCII input and cache the result. 174 * If the two key functions agree on the probe they agree on every input 175 * (they only differ in fold direction; a probe that survives both folds 176 * is sufficient). When they diverge, hierarchical is skipped permanently 177 * for that {@code (vendor, type)} and the lookup falls through to legacy. 178 * 179 * <p>This is intentionally conservative; once the strict-mode switch from 180 * plan §3.3 lands (slice S7) the gate can flip to "always trust 181 * hierarchical" and accept the (more correct) behavior change. 182 */ 183 private boolean isHierarchicalCompatibleForType(ESQLDataObjectType objectType) { 184 try { 185 gudusoft.gsqlparser.EDbVendor vendor = this.sqlEnv.getDBVendor(); 186 String cacheKey = vendor.name() + "|" + objectType.name(); 187 Boolean cached = HIERARCHICAL_COMPAT_CACHE.get(cacheKey); 188 if (cached != null) { 189 return cached; 190 } 191 // Probe both unquoted and quoted representative inputs because 192 // IdentifierRules has independent {@code unquotedFold/Compare} and 193 // {@code quotedFold/Compare} axes; a vendor/type can match for one 194 // representation and diverge for the other (e.g. Snowflake where 195 // unquoted folds to UPPER on both sides but quoted preserves case 196 // in keyForMap while legacy still appends toUpperCase via 197 // tableCollationCaseSensitive=false). 198 String unquotedProbe = "ProbeXyz"; 199 String quotedProbe = quoteIdentifierForProbe(vendor, unquotedProbe); 200 IdentifierService svc = getIdentifierService(); 201 boolean compat = probeMatches(svc, vendor, unquotedProbe, objectType) 202 && probeMatches(svc, vendor, quotedProbe, objectType); 203 HIERARCHICAL_COMPAT_CACHE.put(cacheKey, compat); 204 return compat; 205 } catch (Throwable ignore) { 206 return false; 207 } 208 } 209 210 private boolean probeMatches(IdentifierService svc, 211 gudusoft.gsqlparser.EDbVendor vendor, 212 String probe, 213 ESQLDataObjectType objectType) { 214 String hierarchicalKey = svc.keyForMap(probe, objectType); 215 String legacyKey = SQLUtil.getIdentifierNormalName(vendor, probe, objectType); 216 return hierarchicalKey != null && hierarchicalKey.equals(legacyKey); 217 } 218 219 /** 220 * Wrap {@code name} in the vendor's quoted-identifier delimiter so the 221 * probe exercises {@code IdentifierRules.quotedFold/quotedCompare} and the 222 * legacy {@link gudusoft.gsqlparser.util.SQLUtil#normalizeIdentifier} 223 * branch that strips quotes before folding. Mirrors the dispatch in 224 * {@link TSQLEnv#isDelimitedIdentifier(gudusoft.gsqlparser.EDbVendor, String)}. 225 */ 226 private static String quoteIdentifierForProbe(gudusoft.gsqlparser.EDbVendor vendor, String name) { 227 switch (vendor) { 228 case dbvmssql: 229 case dbvazuresql: 230 return "[" + name + "]"; 231 case dbvmysql: 232 case dbvbigquery: 233 case dbvcouchbase: 234 case dbvhive: 235 case dbvimpala: 236 return "`" + name + "`"; 237 case dbvdax: 238 return "'" + name + "'"; 239 default: 240 return "\"" + name + "\""; 241 } 242 } 243 244 /** 245 * Get or create bucketed index for a specific object type 246 */ 247 private BucketedIndex getBucketedIndex(ESQLDataObjectType objectType) { 248 if (!shouldUseBucketedIndex()) { 249 return null; 250 } 251 252 String collation = getIdentifierService().getProfile().getFlags().defaultCollation; 253 CollatorProvider provider = getCollatorProvider(); 254 255 switch (objectType) { 256 case dotTable: 257 if (bucketedTables == null) { 258 bucketedTables = new BucketedIndex(provider, collation, objectType); 259 } 260 return bucketedTables; 261 262 case dotFunction: 263 if (bucketedFunctions == null) { 264 bucketedFunctions = new BucketedIndex(provider, collation, objectType); 265 } 266 return bucketedFunctions; 267 268 case dotProcedure: 269 if (bucketedProcedures == null) { 270 bucketedProcedures = new BucketedIndex(provider, collation, objectType); 271 } 272 return bucketedProcedures; 273 274 case dotTrigger: 275 if (bucketedTriggers == null) { 276 bucketedTriggers = new BucketedIndex(provider, collation, objectType); 277 } 278 return bucketedTriggers; 279 280 case dotOraclePackage: 281 if (bucketedOraclePackages == null) { 282 bucketedOraclePackages = new BucketedIndex(provider, collation, objectType); 283 } 284 return bucketedOraclePackages; 285 286 case dotSynonyms: 287 if (bucketedSynonyms == null) { 288 bucketedSynonyms = new BucketedIndex(provider, collation, objectType); 289 } 290 return bucketedSynonyms; 291 292 default: 293 return null; 294 } 295 } 296 297 public List<TSQLSchemaObject> getSchemaObjectList() { 298 List<TSQLSchemaObject> schemaObjectList = new LinkedList<>(); 299 synchronized (schemaObjectMap) { 300 for(String schemaObjectKey: schemaObjectMap.keySet()){ 301 TSQLSchemaObject schemaObject = schemaObjectMap.get(schemaObjectKey); 302 if(schemaObject instanceof TSQLProcedure){ 303 if(((TSQLProcedure)schemaObject).isOraclePackageProcedure()){ 304 continue; 305 } 306 } 307 schemaObjectList.add(schemaObject); 308 } 309 } 310 return schemaObjectList; 311 } 312 313 public List<TSQLSchemaObject> getPackageObjectList(TSQLOraclePackage oraclePackage) { 314 List<TSQLSchemaObject> schemaObjectList = new LinkedList<>(); 315 synchronized (schemaObjectMap) { 316 for (String schemaObjectKey : schemaObjectMap.keySet()) { 317 TSQLSchemaObject schemaObject = schemaObjectMap.get(schemaObjectKey); 318 if (schemaObject instanceof TSQLProcedure) { 319 if (!((TSQLProcedure) schemaObject).isOraclePackageProcedure()) { 320 continue; 321 } 322 TSQLProcedure procedure = (TSQLProcedure) schemaObject; 323 if (procedure.getOraclePackage() == oraclePackage) { 324 schemaObjectList.add(schemaObject); 325 } 326 } 327 } 328 } 329 return schemaObjectList; 330 } 331 332 private Map<String, TSQLSchemaObject> schemaObjectMap = Collections.synchronizedMap(new LinkedHashMap<String, TSQLSchemaObject>( )); 333 334// public boolean addTable(TSQLTable sqlTable){ 335// return addDataObject(sqlTable); 336// } 337// 338// public boolean addProcedure(TSQLProcedure sqlProcedure){ 339// return addDataObject(sqlProcedure); 340// } 341// 342// public boolean addFunction(TSQLFunction sqlFunction){ 343// return addDataObject(sqlFunction); 344// } 345// 346// public boolean addTrigger(TSQLTrigger sqlTrigger){ 347// return addDataObject(sqlTrigger); 348// } 349 350 /** 351 * add database object 352 * 353 * <p><strong>Dual-write strategy:</strong> Updates both legacy schemaObjectMap 354 * and new type-specific maps for backward compatibility and performance optimization. 355 * 356 * @param schemaObject schema object to add 357 */ 358 protected void addSchemaObject(TSQLSchemaObject schemaObject){ 359 checkNotSealed(); // Phase 6: Prevent modification after seal 360 // ===== Legacy path: Update schemaObjectMap (backward compatibility) ===== 361 String normalName = SQLUtil.getIdentifierNormalName(this.sqlEnv.getDBVendor(), schemaObject.name, schemaObject.getDataObjectType()); 362 if (schemaObject.getDataObjectType() == ESQLDataObjectType.dotFunction) 363 { 364 normalName = normalName+"$function"; 365 } 366 else if (schemaObject.getDataObjectType() == ESQLDataObjectType.dotProcedure) 367 { 368 normalName = normalName+"$procedure"; 369 } 370 else if (schemaObject.getDataObjectType() == ESQLDataObjectType.dotTrigger) 371 { 372 normalName = normalName+"$trigger"; 373 } 374 else if (schemaObject.getDataObjectType() == ESQLDataObjectType.dotOraclePackage) 375 { 376 normalName = normalName+"$package"; 377 } 378 schemaObjectMap.put(normalName, schemaObject); 379 this.catalog.getSqlEnv().putSchemaObject(schemaObject.getQualifiedName(),schemaObject); 380 381 // ===== New path: Update type-specific maps (Phase 2 optimization) ===== 382 if (TBaseType.USE_HIERARCHICAL_INDEX) { 383 try { 384 String key = getIdentifierService().keyForMap(schemaObject.name, schemaObject.getDataObjectType()); 385 386 switch (schemaObject.getDataObjectType()) { 387 case dotTable: 388 tables.put(key, (TSQLTable) schemaObject); 389 break; 390 case dotFunction: 391 functions.put(key, (TSQLFunction) schemaObject); 392 break; 393 case dotProcedure: 394 procedures.put(key, (TSQLProcedure) schemaObject); 395 break; 396 case dotTrigger: 397 triggers.put(key, (TSQLTrigger) schemaObject); 398 break; 399 case dotOraclePackage: 400 oraclePackages.put(key, (TSQLOraclePackage) schemaObject); 401 break; 402 case dotSynonyms: 403 synonyms.put(key, (TSQLSynonyms) schemaObject); 404 break; 405 } 406 } catch (Throwable ignore) { 407 // Silently fail to maintain backward compatibility 408 } 409 } 410 411 // ===== Phase 3: Update bucketed index for SQL Server ===== 412 if (shouldUseBucketedIndex()) { 413 try { 414 BucketedIndex bucketedIndex = getBucketedIndex(schemaObject.getDataObjectType()); 415 if (bucketedIndex != null) { 416 bucketedIndex.put(schemaObject.name, schemaObject); 417 } 418 } catch (Throwable ignore) { 419 // Silently fail to maintain backward compatibility 420 } 421 } 422 } 423 424 TSQLSchemaObject findSchemaObject(ESQLDataObjectType dataObjectType, String schemaObjectName) { 425 // Phase 3.5: Use bucketed index for SQL Server (25x faster for 10,000+ objects) 426 if (shouldUseBucketedIndex()) { 427 try { 428 BucketedIndex bucketedIndex = getBucketedIndex(dataObjectType); 429 if (bucketedIndex != null) { 430 TSQLSchemaObject result = bucketedIndex.get(schemaObjectName); 431 if (result != null) { 432 if (TBaseType.LOG_INDEX_HIT_RATE) { 433 System.out.println("[BucketedIndex] Hit: " + dataObjectType + " - " + schemaObjectName); 434 } 435 return result; 436 } 437 } 438 } catch (Throwable ignore) { 439 // Fall through to legacy path 440 } 441 } 442 443 // Phase 2: Use hierarchical index (type-specific maps) when flag is enabled. 444 // 445 // Slice S3: Only consult hierarchical when its IdentifierService.keyForMap 446 // key function is globally compatible with legacy 447 // SQLUtil.getIdentifierNormalName for this {@code (vendor, type)} pair. 448 // See {@link #isHierarchicalCompatibleForType} for the rationale; in 449 // particular, an input-local parity check is insufficient because a 450 // case-different earlier write may already have populated hierarchical 451 // under a key that legacy collapsed (e.g. BigQuery: writes "FOO" then 452 // "foo"; legacy retains only the last; hierarchical retains both; 453 // querying "FOO" would still return the stale earlier hierarchical 454 // entry). Falling through to legacy preserves write/read symmetry. 455 if (TBaseType.USE_HIERARCHICAL_INDEX 456 && isHierarchicalCompatibleForType(dataObjectType)) { 457 try { 458 String key = getIdentifierService().keyForMap(schemaObjectName, dataObjectType); 459 TSQLSchemaObject result = null; 460 461 switch (dataObjectType) { 462 case dotTable: 463 result = tables.get(key); 464 break; 465 case dotFunction: 466 result = functions.get(key); 467 break; 468 case dotProcedure: 469 result = procedures.get(key); 470 break; 471 case dotTrigger: 472 result = triggers.get(key); 473 break; 474 case dotOraclePackage: 475 result = oraclePackages.get(key); 476 break; 477 case dotSynonyms: 478 result = synonyms.get(key); 479 break; 480 } 481 482 if (result != null) { 483 // Log hit rate if enabled 484 if (TBaseType.LOG_INDEX_HIT_RATE) { 485 System.out.println("[HierarchicalIndex] Hit: " + dataObjectType + " - " + schemaObjectName); 486 } 487 return result; 488 } 489 } catch (Throwable ignore) { 490 // Fall through to legacy path 491 } 492 } 493 494 // Legacy path: use suffix hacks and local map (backward compatibility) 495 String normalName = SQLUtil.getIdentifierNormalName(this.sqlEnv.getDBVendor(), schemaObjectName, dataObjectType); 496 if (dataObjectType == ESQLDataObjectType.dotFunction) 497 { 498 normalName = normalName+"$function"; 499 } 500 else if (dataObjectType == ESQLDataObjectType.dotProcedure) 501 { 502 normalName = normalName+"$procedure"; 503 } 504 else if (dataObjectType == ESQLDataObjectType.dotTrigger) 505 { 506 normalName = normalName+"$trigger"; 507 } 508 else if (dataObjectType == ESQLDataObjectType.dotOraclePackage) 509 { 510 normalName = normalName+"$package"; 511 } 512 return schemaObjectMap.get(normalName); 513 } 514 515 /** 516 * create a oracle package belong to this schema 517 * 518 * @param oraclePackageName oracle package name 519 * @return an instance of the oracle package 520 */ 521 public TSQLOraclePackage createOraclePackage(String oraclePackageName){ 522 return (TSQLOraclePackage)createSchemaObject(oraclePackageName,ESQLDataObjectType.dotOraclePackage); 523 } 524 525 /** 526 * create a procedure belong to this schema 527 * 528 * @param procedureName procedure name 529 * @return an instance of the SQL procedure 530 */ 531 public TSQLProcedure createProcedure(String procedureName){ 532 return (TSQLProcedure)createSchemaObject(procedureName,ESQLDataObjectType.dotProcedure); 533 } 534 535 public TSQLProcedure createProcedure(String procedureName, ESQLDataObjectType type){ 536 return (TSQLProcedure)createSchemaObject(procedureName,type); 537 } 538 539 /** 540 * create a function belong to this schema 541 * 542 * @param functionName function name 543 * @return an instance of the SQL function. 544 */ 545 public TSQLFunction createFunction(String functionName){ 546 return (TSQLFunction)createSchemaObject(functionName,ESQLDataObjectType.dotFunction); 547 } 548 549 /** 550 * create a trigger belong to this schema 551 * 552 * @param triggerName trigger name 553 * @return an instance of the SQL trigger. 554 */ 555 public TSQLTrigger createTrigger(String triggerName){ 556 return (TSQLTrigger)createSchemaObject(triggerName,ESQLDataObjectType.dotTrigger); 557 } 558 559 /** 560 * create a synonyms belong to this schema 561 * 562 * @param synonymsName synonyms name 563 * @return an instance of the SQL synonyms 564 */ 565 public TSQLSynonyms createSynonyms(String synonymsName){ 566 return (TSQLSynonyms)createSchemaObject(synonymsName,ESQLDataObjectType.dotSynonyms); 567 } 568 569 /** 570 * create a table belong to this schema. If table with the same name already exists in the schema 571 * return the existing table. 572 * 573 * @param tableName table name 574 * @return an instance of the SQL table 575 */ 576 public TSQLTable createTable(String tableName){ 577 return (TSQLTable)createSchemaObject(tableName,ESQLDataObjectType.dotTable); 578 } 579 580 public TSQLTable createTable(String tableName, int priority){ 581 return (TSQLTable)createSchemaObject(tableName,ESQLDataObjectType.dotTable, priority); 582 } 583 584 // Slice S3: route public lookups through findSchemaObject so they go through 585 // the bucketed → hierarchical (IdentifierService.keyForMap) → legacy fallback 586 // chain, instead of bypassing both indexes via raw schemaObjectMap. 587 public boolean containsTable(String tableName) { 588 return findSchemaObject(ESQLDataObjectType.dotTable, tableName) != null; 589 } 590 591 public TSQLTable findTable(String tableName) { 592 return (TSQLTable) findSchemaObject(ESQLDataObjectType.dotTable, tableName); 593 } 594 595 public TSQLSchemaObject findSchemaObject(String schemaObjectName) { 596 TSQLSchemaObject object = findSchemaObject(ESQLDataObjectType.dotFunction, schemaObjectName); 597 if (object == null) { 598 object = findSchemaObject(ESQLDataObjectType.dotProcedure, schemaObjectName); 599 } 600 if (object == null) { 601 object = findSchemaObject(ESQLDataObjectType.dotTrigger, schemaObjectName); 602 } 603 if (object == null) { 604 object = findSchemaObject(ESQLDataObjectType.dotOraclePackage, schemaObjectName); 605 } 606 return object; 607 } 608 609 /** 610 * 611 * @param schemaObjectName 该名称不带 catalog, schema 前缀 612 * @param dataObjectType 613 * @return 614 */ 615 public TSQLSchemaObject createSchemaObject(String schemaObjectName, ESQLDataObjectType dataObjectType){ 616 return createSchemaObject(schemaObjectName, dataObjectType, 0); 617 } 618 619 /** 620 * 621 * @param schemaObjectName 该名称不带 catalog, schema 前缀 622 * @param dataObjectType 623 * @param priority 624 * @return 625 */ 626 protected TSQLSchemaObject createSchemaObject(String schemaObjectName, ESQLDataObjectType dataObjectType, int priority){ 627 TSQLSchemaObject result = null; 628 TSQLSchemaObject schemaObject = findSchemaObject(dataObjectType, schemaObjectName); 629 if (schemaObject == null){ 630 switch (dataObjectType){ 631 case dotTable: 632 result = new TSQLTable(this,schemaObjectName); 633 break; 634 case dotOraclePackage: 635 result = new TSQLOraclePackage(this,schemaObjectName); 636 break; 637 case dotProcedure: 638 result = new TSQLProcedure(this,schemaObjectName); 639 break; 640 case dotFunction: 641 result = new TSQLFunction(this,schemaObjectName); 642 break; 643 case dotTrigger: 644 result = new TSQLTrigger(this,schemaObjectName); 645 break; 646 case dotSynonyms: 647 result = new TSQLSynonyms(this,schemaObjectName); 648 break; 649 } 650 }else if (dataObjectType == schemaObject.getDataObjectType()){ 651 result = schemaObject; 652 }else{ 653 System.out.println("object name conflict:"+getQualifiedName()+"."+schemaObjectName+",type:"+dataObjectType+" VS "+schemaObject.getQualifiedName()+", type:"+schemaObject.getDataObjectType()); 654 }; 655 656 if (result!=null && priority > result.getPriority()) { 657 result.setPriority(priority); 658 } 659 return result; 660 } 661 662}