001package gudusoft.gsqlparser.sqlenv.catalog; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 005import gudusoft.gsqlparser.sqlenv.IdentifierProfile; 006import gudusoft.gsqlparser.sqlenv.IdentifierService; 007import gudusoft.gsqlparser.sqlenv.TSQLCatalog; 008import gudusoft.gsqlparser.sqlenv.TSQLEnv; 009import gudusoft.gsqlparser.sqlenv.TSQLSchemaObject; 010import gudusoft.gsqlparser.sqlenv.CatalogStore; 011 012import java.util.ArrayList; 013import java.util.List; 014import java.util.concurrent.ConcurrentHashMap; 015import java.util.Map; 016 017/** 018 * CatalogStore Provider(新实现) 019 * 020 * <p>此实现基于 CatalogStore,使用 IdentifierService 进行标识符处理。 021 * 022 * @since 3.2.0 (Phase 1) 023 */ 024public class CatalogStoreProvider implements ICatalogProvider { 025 026 private final EDbVendor vendor; 027 private final CatalogStore catalogStore; 028 private final IdentifierService identifierService; 029 private String defaultCatalogName; 030 031 // Cache for TSQLCatalog objects (for compatibility with TSQLEnv API) 032 private final Map<String, TSQLCatalog> catalogCache = new ConcurrentHashMap<>(); 033 034 /** 035 * Creates a CatalogStoreProvider with default flags 036 * 037 * @param vendor database vendor 038 */ 039 public CatalogStoreProvider(EDbVendor vendor) { 040 this(vendor, IdentifierProfile.VendorFlags.defaults()); 041 } 042 043 /** 044 * Creates a CatalogStoreProvider with custom vendor flags 045 * 046 * @param vendor database vendor 047 * @param flags vendor-specific flags 048 */ 049 public CatalogStoreProvider(EDbVendor vendor, IdentifierProfile.VendorFlags flags) { 050 this(IdentifierProfile.forVendor(vendor, flags)); 051 } 052 053 /** 054 * Creates a CatalogStoreProvider under ONE analysis's identifier configuration. 055 * 056 * <p>The profile reaches the catalog store and every index built inside it, so registration, 057 * lookup and enumeration observe the same per-category rules the rest of the analysis does. 058 * A provider built from a bare vendor keeps the vendor default. 059 * 060 * @param profile the effective identifier configuration; its vendor is the provider's vendor 061 */ 062 public CatalogStoreProvider(IdentifierProfile profile) { 063 this(IdentifierService.forProfile(profile)); 064 } 065 066 /** 067 * Creates a CatalogStoreProvider over an existing analysis service. 068 * 069 * @param identifierService the frozen service of the current analysis 070 */ 071 public CatalogStoreProvider(IdentifierService identifierService) { 072 this.vendor = identifierService.getProfile().getVendor(); 073 this.identifierService = identifierService; 074 this.catalogStore = new CatalogStore(this.vendor, identifierService); 075 } 076 077 /** 078 * Creates a CatalogStoreProvider wrapping existing CatalogStore 079 * 080 * @param catalogStore existing catalog store 081 * @param identifierService identifier service 082 */ 083 public CatalogStoreProvider(CatalogStore catalogStore, IdentifierService identifierService) { 084 this.vendor = catalogStore.getVendor(); 085 this.catalogStore = catalogStore; 086 this.identifierService = identifierService; 087 } 088 089 @Override 090 public TSQLCatalog getCatalog(String catalogName) { 091 if (catalogName == null || catalogName.isEmpty()) { 092 return null; 093 } 094 095 // Normalize catalog name 096 String normalizedName = identifierService.normalize(catalogName, ESQLDataObjectType.dotCatalog); 097 098 // Return cached catalog if exists 099 return catalogCache.get(normalizedName); 100 } 101 102 @Override 103 public TSQLCatalog createCatalog(String catalogName) { 104 if (catalogName == null || catalogName.isEmpty()) { 105 throw new IllegalArgumentException("catalogName cannot be null or empty"); 106 } 107 108 // Normalize catalog name 109 String normalizedName = identifierService.normalize(catalogName, ESQLDataObjectType.dotCatalog); 110 111 // Return existing if already cached 112 TSQLCatalog existing = catalogCache.get(normalizedName); 113 if (existing != null) { 114 return existing; 115 } 116 117 // Note: We cannot create TSQLCatalog here because it requires TSQLEnv 118 // This is a limitation of the current architecture 119 // For now, return null and let the caller handle it 120 // In Phase 2-3, we'll refactor TSQLCatalog to not require TSQLEnv 121 122 return null; 123 } 124 125 @Override 126 public List<TSQLCatalog> getAllCatalogs() { 127 return new ArrayList<>(catalogCache.values()); 128 } 129 130 @Override 131 public String getDefaultCatalogName() { 132 return defaultCatalogName; 133 } 134 135 @Override 136 public void setDefaultCatalogName(String name) { 137 this.defaultCatalogName = name; 138 } 139 140 @Override 141 public TSQLSchemaObject findObject(String catalog, String schema, 142 String objectName, ESQLDataObjectType type) { 143 // Delegate directly to CatalogStore (it handles normalization internally) 144 // The ICatalogProvider contract: TSQLEnv normalizes the segments before it asks. 145 return catalogStore.getNormalized(catalog, schema, objectName, type); 146 } 147 148 @Override 149 public void addObject(TSQLSchemaObject object) { 150 if (object == null) { 151 return; 152 } 153 154 // Add to CatalogStore 155 catalogStore.put(object); 156 157 // Update catalog cache if needed 158 if (object.getSchema() != null && object.getSchema().getCatalog() != null) { 159 TSQLCatalog catalog = object.getSchema().getCatalog(); 160 String normalizedName = identifierService.normalize( 161 catalog.getName(), 162 ESQLDataObjectType.dotCatalog 163 ); 164 catalogCache.putIfAbsent(normalizedName, catalog); 165 } 166 } 167 168 @Override 169 public boolean removeObject(TSQLSchemaObject object) { 170 if (object == null) { 171 return false; 172 } 173 174 return catalogStore.remove(object); 175 } 176 177 @Override 178 public void clear() { 179 catalogStore.clear(); 180 catalogCache.clear(); 181 } 182 183 @Override 184 public int size() { 185 return catalogStore.size(); 186 } 187 188 /** 189 * Get the underlying CatalogStore 190 * 191 * @return catalog store 192 */ 193 public CatalogStore getCatalogStore() { 194 return catalogStore; 195 } 196 197 /** 198 * Get the IdentifierService 199 * 200 * @return identifier service 201 */ 202 public IdentifierService getIdentifierService() { 203 return identifierService; 204 } 205 206 /** 207 * Register a catalog in the cache (used by TSQLEnv during migration) 208 * 209 * @param catalog the catalog to register 210 */ 211 public void registerCatalog(TSQLCatalog catalog) { 212 if (catalog == null) { 213 return; 214 } 215 216 String normalizedName = identifierService.normalize( 217 catalog.getName(), 218 ESQLDataObjectType.dotCatalog 219 ); 220 catalogCache.put(normalizedName, catalog); 221 } 222}