001package gudusoft.gsqlparser.sqlenv;
002
003import gudusoft.gsqlparser.EDbVendor;
004
005import java.util.EnumMap;
006import java.util.Objects;
007
008/**
009 * 厂商标识符配置档案(Vendor Identifier Profile)
010 *
011 * <p>封装每个数据库厂商的完整标识符配置,包括:
012 * <ul>
013 * <li>按对象组(NAME_GROUP, COLUMN_GROUP, ROUTINE_GROUP)的标识符规则
014 * <li>Vendor-specific flags(如 MySQL lower_case_table_names, SQL Server collation)
015 * </li>
016 *
017 * <p>设计目标:
018 * <ul>
019 * <li>集中管理所有 vendor-specific 配置
020 * <li>统一注入路径,避免配置散落在各处
021 * <li>支持缓存失效(通过 fingerprint)
022 * </ul>
023 *
024 * <p>使用示例:
025 * <pre>
026 * // 创建 Oracle profile(使用默认 flags)
027 * IdentifierProfile oracleProfile = IdentifierProfile.forVendor(
028 *     EDbVendor.dbvoracle,
029 *     VendorFlags.defaults()
030 * );
031 *
032 * // 创建 MySQL profile(指定 lower_case_table_names)
033 * IdentifierProfile mysqlProfile = IdentifierProfile.forVendor(
034 *     EDbVendor.dbvmysql,
035 *     new VendorFlags(1, null, false, false)  // lower_case_table_names = 1
036 * );
037 *
038 * // 查询规则
039 * IdentifierRules tableRules = oracleProfile.getRules(ESQLDataObjectType.dotTable);
040 * </pre>
041 *
042 * @since 3.1.0.9
043 */
044public final class IdentifierProfile {
045
046    private final EDbVendor vendor;
047
048    // ===== 按对象组的规则 =====
049    private final EnumMap<ObjectGroup, IdentifierRules> rulesByGroup;
050
051    // ===== Vendor-specific flags =====
052    private final VendorFlags flags;
053
054    // ===== 对象组定义 =====
055
056    /**
057     * 对象组(用于区分不同对象类型的标识符规则)
058     *
059     * <p>某些数据库对不同对象类型使用不同的大小写规则:
060     * <ul>
061     * <li>BigQuery: 表名敏感,列名不敏感
062     * <li>MySQL: 表名根据 lower_case_table_names,列名始终不敏感
063     * </ul>
064     */
065    public enum ObjectGroup {
066        /**
067         * 名称组(catalog, schema, table, view, procedure, trigger)
068         */
069        NAME_GROUP,
070
071        /**
072         * 列组(column)
073         */
074        COLUMN_GROUP,
075
076        /**
077         * 函数组(function)
078         * <p>某些数据库函数名规则与表名不同
079         */
080        ROUTINE_GROUP
081    }
082
083    // ===== Vendor flags 封装 =====
084
085    /**
086     * Vendor-specific flags(厂商特定配置)
087     *
088     * <p>封装各数据库厂商的特殊配置参数
089     */
090    public static class VendorFlags {
091        /**
092         * MySQL: lower_case_table_names 系统变量(0, 1, 2)
093         * <ul>
094         * <li>0: 大小写敏感(Unix/Linux)
095         * <li>1: 存储为小写,比较不敏感(Windows)
096         * <li>2: 存储保留原样,比较不敏感(macOS)
097         * </ul>
098         */
099        public final int mysqlLowerCaseTableNames;
100
101        /**
102         * SQL Server / Azure SQL: 默认 collation 名称
103         * <p>例如: "SQL_Latin1_General_CP1_CI_AS"
104         */
105        public final String defaultCollation;
106
107        /**
108         * Redshift: enable_case_sensitive_identifier 参数
109         * <p>默认 false(与 PostgreSQL 一致)
110         */
111        public final boolean redshiftEnableCaseSensitive;
112
113        /**
114         * Snowflake: QUOTED_IDENTIFIERS_IGNORE_CASE 会话参数
115         * <p>默认 false(quoted 标识符大小写敏感)
116         */
117        public final boolean snowflakeQuotedIdentifiersIgnoreCase;
118
119        /**
120         * 构造 vendor flags
121         *
122         * @param mysqlLowerCaseTableNames MySQL lower_case_table_names (0, 1, 2)
123         * @param defaultCollation SQL Server collation 名称
124         * @param redshiftEnableCaseSensitive Redshift case sensitive 开关
125         * @param snowflakeQuotedIdentifiersIgnoreCase Snowflake quoted ignore case 开关
126         */
127        public VendorFlags(int mysqlLowerCaseTableNames,
128                          String defaultCollation,
129                          boolean redshiftEnableCaseSensitive,
130                          boolean snowflakeQuotedIdentifiersIgnoreCase) {
131            this.mysqlLowerCaseTableNames = mysqlLowerCaseTableNames;
132            this.defaultCollation = defaultCollation;
133            this.redshiftEnableCaseSensitive = redshiftEnableCaseSensitive;
134            this.snowflakeQuotedIdentifiersIgnoreCase = snowflakeQuotedIdentifiersIgnoreCase;
135        }
136
137        /**
138         * 默认 flags(用于大部分数据库)
139         */
140        public static VendorFlags defaults() {
141            return new VendorFlags(
142                0,                            // MySQL lower_case_table_names = 0(敏感)
143                "SQL_Latin1_General_CP1_CI_AS",  // SQL Server 默认 collation
144                false,                        // Redshift case sensitive = false
145                false                         // Snowflake quoted ignore case = false
146            );
147        }
148
149        @Override
150        public boolean equals(Object o) {
151            if (this == o) return true;
152            if (o == null || getClass() != o.getClass()) return false;
153            VendorFlags that = (VendorFlags) o;
154            return mysqlLowerCaseTableNames == that.mysqlLowerCaseTableNames &&
155                   redshiftEnableCaseSensitive == that.redshiftEnableCaseSensitive &&
156                   snowflakeQuotedIdentifiersIgnoreCase == that.snowflakeQuotedIdentifiersIgnoreCase &&
157                   Objects.equals(defaultCollation, that.defaultCollation);
158        }
159
160        @Override
161        public int hashCode() {
162            return Objects.hash(mysqlLowerCaseTableNames, defaultCollation,
163                              redshiftEnableCaseSensitive, snowflakeQuotedIdentifiersIgnoreCase);
164        }
165    }
166
167    // ===== 构造函数 =====
168
169    /**
170     * 构造标识符配置档案
171     *
172     * @param vendor 数据库厂商
173     * @param rulesByGroup 按对象组的规则
174     * @param flags vendor-specific flags
175     */
176    private IdentifierProfile(EDbVendor vendor,
177                             EnumMap<ObjectGroup, IdentifierRules> rulesByGroup,
178                             VendorFlags flags) {
179        this.vendor = vendor;
180        this.rulesByGroup = rulesByGroup;
181        this.flags = flags;
182    }
183
184    // ===== 工厂方法:根据厂商和 flags 创建 =====
185
186    /**
187     * 为指定厂商创建标识符配置档案
188     *
189     * @param vendor 数据库厂商
190     * @param flags vendor-specific flags
191     * @return 标识符配置档案
192     */
193    public static IdentifierProfile forVendor(EDbVendor vendor, VendorFlags flags) {
194        EnumMap<ObjectGroup, IdentifierRules> rules = new EnumMap<>(ObjectGroup.class);
195
196        switch (vendor) {
197            case dbvoracle: {
198                IdentifierRules rule = IdentifierRules.forOracle();
199                rules.put(ObjectGroup.NAME_GROUP, rule);
200                rules.put(ObjectGroup.COLUMN_GROUP, rule);
201                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
202                break;
203            }
204
205            case dbvpostgresql:
206            case dbvgreenplum:
207            case dbvgaussdb: {
208                // PostgreSQL 家族(包括 Greenplum, GaussDB)
209                IdentifierRules rule = IdentifierRules.forPostgreSQL();
210                rules.put(ObjectGroup.NAME_GROUP, rule);
211                rules.put(ObjectGroup.COLUMN_GROUP, rule);
212                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
213                break;
214            }
215
216            case dbvredshift: {
217                // Redshift: 根据 enable_case_sensitive_identifier 决定
218                IdentifierRules rule = flags.redshiftEnableCaseSensitive
219                    ? IdentifierRules.forClickHouse()  // 敏感
220                    : IdentifierRules.forPostgreSQL(); // 不敏感(默认)
221                rules.put(ObjectGroup.NAME_GROUP, rule);
222                rules.put(ObjectGroup.COLUMN_GROUP, rule);
223                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
224                break;
225            }
226
227            case dbvclickhouse: {
228                IdentifierRules rule = IdentifierRules.forClickHouse();
229                rules.put(ObjectGroup.NAME_GROUP, rule);
230                rules.put(ObjectGroup.COLUMN_GROUP, rule);
231                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
232                break;
233            }
234
235            case dbvcouchbase: {
236                IdentifierRules rule = IdentifierRules.forCouchbase();
237                rules.put(ObjectGroup.NAME_GROUP, rule);
238                rules.put(ObjectGroup.COLUMN_GROUP, rule);
239                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
240                break;
241            }
242
243            case dbvmssql:
244            case dbvazuresql: {
245                IdentifierRules rule = IdentifierRules.forSQLServer();
246                rules.put(ObjectGroup.NAME_GROUP, rule);
247                rules.put(ObjectGroup.COLUMN_GROUP, rule);
248                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
249                break;
250            }
251
252            case dbvmysql: {
253                // MySQL: 表名根据 lower_case_table_names,列名始终不敏感
254                rules.put(ObjectGroup.NAME_GROUP,
255                         IdentifierRules.forMySQL(flags.mysqlLowerCaseTableNames));
256                rules.put(ObjectGroup.COLUMN_GROUP, IdentifierRules.forMySQLColumn());
257                rules.put(ObjectGroup.ROUTINE_GROUP, IdentifierRules.forMySQLRoutine());
258                break;
259            }
260
261            case dbvbigquery: {
262                // BigQuery: 表名敏感,列名不敏感
263                rules.put(ObjectGroup.NAME_GROUP, IdentifierRules.forBigQueryTable());
264                rules.put(ObjectGroup.COLUMN_GROUP, IdentifierRules.forBigQueryColumn());
265                rules.put(ObjectGroup.ROUTINE_GROUP, IdentifierRules.forBigQueryTable());
266                break;
267            }
268
269            case dbvdb2:
270            case dbvnetezza:
271            case dbvexasol: {
272                // DB2 家族(DB2, Netezza, Exasol)
273                IdentifierRules rule = IdentifierRules.forDB2();
274                rules.put(ObjectGroup.NAME_GROUP, rule);
275                rules.put(ObjectGroup.COLUMN_GROUP, rule);
276                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
277                break;
278            }
279
280            case dbvsnowflake: {
281                // Snowflake: 根据 QUOTED_IDENTIFIERS_IGNORE_CASE 决定
282                IdentifierRules rule = IdentifierRules.forSnowflake();
283                // TODO: 如果 snowflakeQuotedIdentifiersIgnoreCase = true,需要调整 quotedCompare
284                rules.put(ObjectGroup.NAME_GROUP, rule);
285                rules.put(ObjectGroup.COLUMN_GROUP, rule);
286                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
287                break;
288            }
289
290            case dbvhana: {
291                IdentifierRules rule = IdentifierRules.forHANA();
292                rules.put(ObjectGroup.NAME_GROUP, rule);
293                rules.put(ObjectGroup.COLUMN_GROUP, rule);
294                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
295                break;
296            }
297
298            case dbvpresto:
299            case dbvtrino: {
300                IdentifierRules rule = IdentifierRules.forPresto();
301                rules.put(ObjectGroup.NAME_GROUP, rule);
302                rules.put(ObjectGroup.COLUMN_GROUP, rule);
303                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
304                break;
305            }
306
307            case dbvvertica: {
308                IdentifierRules rule = IdentifierRules.forVertica();
309                rules.put(ObjectGroup.NAME_GROUP, rule);
310                rules.put(ObjectGroup.COLUMN_GROUP, rule);
311                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
312                break;
313            }
314
315            case dbvhive:
316            case dbvsparksql:
317            case dbvimpala:
318            case dbvdatabricks: {
319                // Hive 家族(Hive, SparkSQL, Impala, Databricks)
320                IdentifierRules rule = IdentifierRules.forHive();
321                rules.put(ObjectGroup.NAME_GROUP, rule);
322                rules.put(ObjectGroup.COLUMN_GROUP, rule);
323                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
324                break;
325            }
326
327            case dbvteradata: {
328                IdentifierRules rule = IdentifierRules.forTeradata();
329                rules.put(ObjectGroup.NAME_GROUP, rule);
330                rules.put(ObjectGroup.COLUMN_GROUP, rule);
331                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
332                break;
333            }
334
335            case dbvathena: {
336                IdentifierRules rule = IdentifierRules.forAthena();
337                rules.put(ObjectGroup.NAME_GROUP, rule);
338                rules.put(ObjectGroup.COLUMN_GROUP, rule);
339                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
340                break;
341            }
342
343            // 其他数据库使用通用规则(与 PostgreSQL 相同)
344            default: {
345                IdentifierRules rule = IdentifierRules.forGeneric();
346                rules.put(ObjectGroup.NAME_GROUP, rule);
347                rules.put(ObjectGroup.COLUMN_GROUP, rule);
348                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
349                break;
350            }
351        }
352
353        return new IdentifierProfile(vendor, rules, flags);
354    }
355
356    // ===== 查询接口 =====
357
358    /**
359     * 获取指定对象类型的标识符规则
360     *
361     * @param objectType 对象类型
362     * @return 标识符规则
363     */
364    public IdentifierRules getRules(ESQLDataObjectType objectType) {
365        ObjectGroup group = mapToGroup(objectType);
366        return rulesByGroup.get(group);
367    }
368
369    /**
370     * 获取 vendor flags
371     *
372     * @return vendor flags
373     */
374    public VendorFlags getFlags() {
375        return flags;
376    }
377
378    /**
379     * 获取数据库厂商
380     *
381     * @return 厂商
382     */
383    public EDbVendor getVendor() {
384        return vendor;
385    }
386
387    /**
388     * 按对象组获取规则(内部使用)
389     *
390     * @param group 对象组
391     * @return 标识符规则
392     */
393    IdentifierRules getRulesByGroup(ObjectGroup group) {
394        return rulesByGroup.get(group);
395    }
396
397    /**
398     * 将对象类型映射到对象组
399     */
400    private ObjectGroup mapToGroup(ESQLDataObjectType type) {
401        if (type == null) return ObjectGroup.NAME_GROUP;
402
403        switch (type) {
404            case dotColumn:
405                return ObjectGroup.COLUMN_GROUP;
406
407            case dotFunction:
408                return ObjectGroup.ROUTINE_GROUP;
409
410            // 其他所有类型归入 NAME_GROUP
411            case dotCatalog:
412            case dotSchema:
413            case dotTable:
414            case dotProcedure:
415            case dotTrigger:
416            case dotOraclePackage:
417            default:
418                return ObjectGroup.NAME_GROUP;
419        }
420    }
421
422    // ===== 指纹计算(用于缓存失效) =====
423
424    /**
425     * 计算配置指纹(用于 TObjectName 缓存失效)
426     *
427     * <p>当 vendor 或 flags 变化时,指纹会改变,触发缓存失效
428     *
429     * @return 配置指纹(64位哈希值)
430     */
431    public long getFingerprint() {
432        return Objects.hash(
433            vendor,
434            flags.mysqlLowerCaseTableNames,
435            flags.defaultCollation,
436            flags.redshiftEnableCaseSensitive,
437            flags.snowflakeQuotedIdentifiersIgnoreCase
438        );
439    }
440
441    // ===== toString 方法(用于调试) =====
442
443    @Override
444    public String toString() {
445        return String.format("IdentifierProfile{vendor=%s, flags=%s}",
446            vendor, flags);
447    }
448}