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; 018 019import gudusoft.gsqlparser.EDbVendor; 020import gudusoft.gsqlparser.ext.sqlnamematcher.SqlNameMatcher; 021import gudusoft.gsqlparser.ext.sqlnamematcher.SqlNameMatchers; 022 023import java.util.EnumMap; 024import java.util.Map; 025 026/** 027 * Factory for creating SqlNameMatcher instances per database vendor and object type. 028 * 029 * <p>This class bridges GSP's existing case sensitivity configuration (stored in 030 * TSQLEnv's EnumMaps) to the SqlNameMatcher framework.</p> 031 * 032 * <p>Design rationale: Instead of duplicating vendor-specific case rules, this factory 033 * reads from TSQLEnv's existing static maps and creates appropriate matchers on demand.</p> 034 * 035 * <p><b>Status since the identifier normalization unification (P0d):</b> internal name 036 * equality no longer routes through this factory — {@link NameService} and every other 037 * engine delegate to the canonical relation 038 * ({@link gudusoft.gsqlparser.util.SQLUtil#sameName(EDbVendor, ESQLDataObjectType, String, 039 * String)} / {@link IdentifierService#areEqualStatic(EDbVendor, ESQLDataObjectType, String, 040 * String)}). This class remains only as the public {@code SqlNameMatcher} extension 041 * bridge. New internal code must use the {@code SQLUtil} façade, not a matcher from here.</p> 042 * 043 * @since 3.2.0.3 (Phase 1) 044 */ 045public class NamePolicyFactory { 046 047 private final EDbVendor vendor; 048 049 // Cache matchers per type to avoid repeated creation 050 private final Map<ESQLDataObjectType, SqlNameMatcher> matcherCache = 051 new EnumMap<>(ESQLDataObjectType.class); 052 053 /** 054 * Creates a new NamePolicyFactory for the specified database vendor. 055 * 056 * @param vendor the database vendor 057 */ 058 public NamePolicyFactory(EDbVendor vendor) { 059 if (vendor == null) { 060 throw new IllegalArgumentException("vendor cannot be null"); 061 } 062 this.vendor = vendor; 063 } 064 065 /** 066 * Returns the database vendor associated with this factory. 067 * 068 * @return the database vendor 069 */ 070 public EDbVendor getVendor() { 071 return vendor; 072 } 073 074 /** 075 * Gets or creates a SqlNameMatcher for the specified object type. 076 * 077 * <p>The matcher's case sensitivity is determined by querying TSQLEnv's 078 * static maps (columnCollationCaseSensitive, tableCollationCaseSensitive, etc.)</p> 079 * 080 * <p>Results are cached to avoid repeated map lookups.</p> 081 * 082 * @param type the SQL data object type (table, column, function, etc.) 083 * @return a SqlNameMatcher configured for the vendor/type combination 084 */ 085 public SqlNameMatcher getMatcherForType(ESQLDataObjectType type) { 086 // Check cache first 087 SqlNameMatcher cached = matcherCache.get(type); 088 if (cached != null) { 089 return cached; 090 } 091 092 // Create new matcher based on TSQLEnv's existing configuration 093 SqlNameMatcher matcher = createMatcher(type); 094 matcherCache.put(type, matcher); 095 return matcher; 096 } 097 098 /** 099 * Creates a SqlNameMatcher by reading TSQLEnv's case sensitivity maps. 100 * 101 * @param type the object type 102 * @return a newly created SqlNameMatcher 103 */ 104 private SqlNameMatcher createMatcher(ESQLDataObjectType type) { 105 boolean caseSensitive; 106 107 switch (type) { 108 case dotCatalog: 109 case dotSchema: 110 // Catalog and schema use the catalogCollationCaseSensitive map 111 caseSensitive = TSQLEnv.catalogCollationCaseSensitive.get(vendor); 112 break; 113 114 case dotTable: 115 case dotProcedure: 116 case dotTrigger: 117 case dotOraclePackage: 118 // Tables, procedures, triggers, and Oracle packages use tableCollationCaseSensitive 119 caseSensitive = TSQLEnv.tableCollationCaseSensitive.get(vendor); 120 break; 121 122 case dotFunction: 123 // Functions have their own map 124 caseSensitive = TSQLEnv.functionCollationCaseSensitive.get(vendor); 125 break; 126 127 case dotColumn: 128 // Columns have their own map 129 caseSensitive = TSQLEnv.columnCollationCaseSensitive.get(vendor); 130 break; 131 132 default: 133 // Everything else uses the default map 134 caseSensitive = TSQLEnv.defaultCollationCaseSensitive.get(vendor); 135 break; 136 } 137 138 // Create a matcher with the appropriate case sensitivity 139 return SqlNameMatchers.withCaseSensitive(caseSensitive); 140 } 141 142 /** 143 * Convenience method to check if a specific object type is case-sensitive 144 * for this vendor. 145 * 146 * @param type the object type 147 * @return true if case-sensitive, false otherwise 148 */ 149 public boolean isCaseSensitive(ESQLDataObjectType type) { 150 return getMatcherForType(type).isCaseSensitive(); 151 } 152}