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.calcite.CatalogStore;
011
012import java.util.ArrayList;
013import java.util.List;
014import java.util.HashMap;
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 HashMap<>();
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.vendor = vendor;
051
052        // Create IdentifierProfile and IdentifierService
053        IdentifierProfile profile = IdentifierProfile.forVendor(vendor, flags);
054        gudusoft.gsqlparser.sqlenv.CollatorProvider collatorProvider = null;
055        if (vendor == EDbVendor.dbvmssql || vendor == EDbVendor.dbvazuresql) {
056            collatorProvider = new gudusoft.gsqlparser.sqlenv.CollatorProvider();
057        }
058        this.identifierService = new IdentifierService(profile, collatorProvider);
059
060        // Create CatalogStore with IdentifierService for proper normalization
061        this.catalogStore = new CatalogStore(vendor, this.identifierService);
062    }
063
064    /**
065     * Creates a CatalogStoreProvider wrapping existing CatalogStore
066     *
067     * @param catalogStore existing catalog store
068     * @param identifierService identifier service
069     */
070    public CatalogStoreProvider(CatalogStore catalogStore, IdentifierService identifierService) {
071        this.vendor = catalogStore.getVendor();
072        this.catalogStore = catalogStore;
073        this.identifierService = identifierService;
074    }
075
076    @Override
077    public TSQLCatalog getCatalog(String catalogName) {
078        if (catalogName == null || catalogName.isEmpty()) {
079            return null;
080        }
081
082        // Normalize catalog name
083        String normalizedName = identifierService.normalize(catalogName, ESQLDataObjectType.dotCatalog);
084
085        // Return cached catalog if exists
086        return catalogCache.get(normalizedName);
087    }
088
089    @Override
090    public TSQLCatalog createCatalog(String catalogName) {
091        if (catalogName == null || catalogName.isEmpty()) {
092            throw new IllegalArgumentException("catalogName cannot be null or empty");
093        }
094
095        // Normalize catalog name
096        String normalizedName = identifierService.normalize(catalogName, ESQLDataObjectType.dotCatalog);
097
098        // Return existing if already cached
099        TSQLCatalog existing = catalogCache.get(normalizedName);
100        if (existing != null) {
101            return existing;
102        }
103
104        // Note: We cannot create TSQLCatalog here because it requires TSQLEnv
105        // This is a limitation of the current architecture
106        // For now, return null and let the caller handle it
107        // In Phase 2-3, we'll refactor TSQLCatalog to not require TSQLEnv
108
109        return null;
110    }
111
112    @Override
113    public List<TSQLCatalog> getAllCatalogs() {
114        return new ArrayList<>(catalogCache.values());
115    }
116
117    @Override
118    public String getDefaultCatalogName() {
119        return defaultCatalogName;
120    }
121
122    @Override
123    public void setDefaultCatalogName(String name) {
124        this.defaultCatalogName = name;
125    }
126
127    @Override
128    public TSQLSchemaObject findObject(String catalog, String schema,
129                                        String objectName, ESQLDataObjectType type) {
130        // Delegate directly to CatalogStore (it handles normalization internally)
131        return catalogStore.get(catalog, schema, objectName, type);
132    }
133
134    @Override
135    public void addObject(TSQLSchemaObject object) {
136        if (object == null) {
137            return;
138        }
139
140        // Add to CatalogStore
141        catalogStore.put(object);
142
143        // Update catalog cache if needed
144        if (object.getSchema() != null && object.getSchema().getCatalog() != null) {
145            TSQLCatalog catalog = object.getSchema().getCatalog();
146            String normalizedName = identifierService.normalize(
147                catalog.getName(),
148                ESQLDataObjectType.dotCatalog
149            );
150            catalogCache.putIfAbsent(normalizedName, catalog);
151        }
152    }
153
154    @Override
155    public boolean removeObject(TSQLSchemaObject object) {
156        if (object == null) {
157            return false;
158        }
159
160        return catalogStore.remove(object);
161    }
162
163    @Override
164    public void clear() {
165        catalogStore.clear();
166        catalogCache.clear();
167    }
168
169    @Override
170    public int size() {
171        return catalogStore.size();
172    }
173
174    /**
175     * Get the underlying CatalogStore
176     *
177     * @return catalog store
178     */
179    public CatalogStore getCatalogStore() {
180        return catalogStore;
181    }
182
183    /**
184     * Get the IdentifierService
185     *
186     * @return identifier service
187     */
188    public IdentifierService getIdentifierService() {
189        return identifierService;
190    }
191
192    /**
193     * Register a catalog in the cache (used by TSQLEnv during migration)
194     *
195     * @param catalog the catalog to register
196     */
197    public void registerCatalog(TSQLCatalog catalog) {
198        if (catalog == null) {
199            return;
200        }
201
202        String normalizedName = identifierService.normalize(
203            catalog.getName(),
204            ESQLDataObjectType.dotCatalog
205        );
206        catalogCache.put(normalizedName, catalog);
207    }
208}