001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to you under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package gudusoft.gsqlparser.sqlenv.calcite;
018
019import gudusoft.gsqlparser.EDbVendor;
020import gudusoft.gsqlparser.ext.calcite.sqlnamematcher.SqlNameMatcher;
021import gudusoft.gsqlparser.ext.calcite.sqlnamematcher.SqlNameMatchers;
022import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType;
023import gudusoft.gsqlparser.sqlenv.TSQLEnv;
024
025import java.util.EnumMap;
026import java.util.Map;
027
028/**
029 * Factory for creating SqlNameMatcher instances per database vendor and object type.
030 *
031 * <p>This class bridges GSP's existing case sensitivity configuration (stored in
032 * TSQLEnv's EnumMaps) to Apache Calcite's SqlNameMatcher framework.</p>
033 *
034 * <p>Design rationale: Instead of duplicating vendor-specific case rules, this factory
035 * reads from TSQLEnv's existing static maps and creates appropriate matchers on demand.</p>
036 *
037 * @since 3.2.0.3 (Phase 1)
038 */
039public class NamePolicyFactory {
040
041    private final EDbVendor vendor;
042
043    // Cache matchers per type to avoid repeated creation
044    private final Map<ESQLDataObjectType, SqlNameMatcher> matcherCache =
045        new EnumMap<>(ESQLDataObjectType.class);
046
047    /**
048     * Creates a new NamePolicyFactory for the specified database vendor.
049     *
050     * @param vendor the database vendor
051     */
052    public NamePolicyFactory(EDbVendor vendor) {
053        if (vendor == null) {
054            throw new IllegalArgumentException("vendor cannot be null");
055        }
056        this.vendor = vendor;
057    }
058
059    /**
060     * Returns the database vendor associated with this factory.
061     *
062     * @return the database vendor
063     */
064    public EDbVendor getVendor() {
065        return vendor;
066    }
067
068    /**
069     * Gets or creates a SqlNameMatcher for the specified object type.
070     *
071     * <p>The matcher's case sensitivity is determined by querying TSQLEnv's
072     * static maps (columnCollationCaseSensitive, tableCollationCaseSensitive, etc.)</p>
073     *
074     * <p>Results are cached to avoid repeated map lookups.</p>
075     *
076     * @param type the SQL data object type (table, column, function, etc.)
077     * @return a SqlNameMatcher configured for the vendor/type combination
078     */
079    public SqlNameMatcher getMatcherForType(ESQLDataObjectType type) {
080        // Check cache first
081        SqlNameMatcher cached = matcherCache.get(type);
082        if (cached != null) {
083            return cached;
084        }
085
086        // Create new matcher based on TSQLEnv's existing configuration
087        SqlNameMatcher matcher = createMatcher(type);
088        matcherCache.put(type, matcher);
089        return matcher;
090    }
091
092    /**
093     * Creates a SqlNameMatcher by reading TSQLEnv's case sensitivity maps.
094     *
095     * @param type the object type
096     * @return a newly created SqlNameMatcher
097     */
098    private SqlNameMatcher createMatcher(ESQLDataObjectType type) {
099        boolean caseSensitive;
100
101        switch (type) {
102            case dotCatalog:
103            case dotSchema:
104                // Catalog and schema use the catalogCollationCaseSensitive map
105                caseSensitive = TSQLEnv.catalogCollationCaseSensitive.get(vendor);
106                break;
107
108            case dotTable:
109            case dotProcedure:
110            case dotTrigger:
111            case dotOraclePackage:
112                // Tables, procedures, triggers, and Oracle packages use tableCollationCaseSensitive
113                caseSensitive = TSQLEnv.tableCollationCaseSensitive.get(vendor);
114                break;
115
116            case dotFunction:
117                // Functions have their own map
118                caseSensitive = TSQLEnv.functionCollationCaseSensitive.get(vendor);
119                break;
120
121            case dotColumn:
122                // Columns have their own map
123                caseSensitive = TSQLEnv.columnCollationCaseSensitive.get(vendor);
124                break;
125
126            default:
127                // Everything else uses the default map
128                caseSensitive = TSQLEnv.defaultCollationCaseSensitive.get(vendor);
129                break;
130        }
131
132        // Create a Calcite matcher with the appropriate case sensitivity
133        return SqlNameMatchers.withCaseSensitive(caseSensitive);
134    }
135
136    /**
137     * Convenience method to check if a specific object type is case-sensitive
138     * for this vendor.
139     *
140     * @param type the object type
141     * @return true if case-sensitive, false otherwise
142     */
143    public boolean isCaseSensitive(ESQLDataObjectType type) {
144        return getMatcherForType(type).isCaseSensitive();
145    }
146}