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            case dbvsqlite: {
209                // PostgreSQL 家族(包括 Greenplum, GaussDB, SQLite)
210                IdentifierRules rule = IdentifierRules.forPostgreSQL();
211                rules.put(ObjectGroup.NAME_GROUP, rule);
212                rules.put(ObjectGroup.COLUMN_GROUP, rule);
213                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
214                break;
215            }
216
217            case dbvredshift: {
218                // Redshift: 根据 enable_case_sensitive_identifier 决定
219                IdentifierRules rule = flags.redshiftEnableCaseSensitive
220                    ? IdentifierRules.forCouchbase()   // 敏感
221                    : IdentifierRules.forPostgreSQL(); // 不敏感(默认)
222                rules.put(ObjectGroup.NAME_GROUP, rule);
223                rules.put(ObjectGroup.COLUMN_GROUP, rule);
224                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
225                break;
226            }
227
228            case dbvclickhouse: {
229                // ClickHouse parser removed but enum preserved for future re-implementation
230                // Using Couchbase rules which have the same case-sensitive behavior
231                IdentifierRules rule = IdentifierRules.forCouchbase();
232                rules.put(ObjectGroup.NAME_GROUP, rule);
233                rules.put(ObjectGroup.COLUMN_GROUP, rule);
234                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
235                break;
236            }
237
238            case dbvcouchbase: {
239                IdentifierRules rule = IdentifierRules.forCouchbase();
240                rules.put(ObjectGroup.NAME_GROUP, rule);
241                rules.put(ObjectGroup.COLUMN_GROUP, rule);
242                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
243                break;
244            }
245
246            case dbvmssql:
247            case dbvazuresql: {
248                IdentifierRules rule = IdentifierRules.forSQLServer();
249                rules.put(ObjectGroup.NAME_GROUP, rule);
250                rules.put(ObjectGroup.COLUMN_GROUP, rule);
251                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
252                break;
253            }
254
255            case dbvmysql: {
256                // MySQL: 表名根据 lower_case_table_names,列名始终不敏感
257                rules.put(ObjectGroup.NAME_GROUP,
258                         IdentifierRules.forMySQL(flags.mysqlLowerCaseTableNames));
259                rules.put(ObjectGroup.COLUMN_GROUP, IdentifierRules.forMySQLColumn());
260                rules.put(ObjectGroup.ROUTINE_GROUP, IdentifierRules.forMySQLRoutine());
261                break;
262            }
263
264            case dbvdoris: {
265                // Doris: MySQL-compatible, follows same rules as MySQL
266                rules.put(ObjectGroup.NAME_GROUP, IdentifierRules.forDoris());
267                rules.put(ObjectGroup.COLUMN_GROUP, IdentifierRules.forDorisColumn());
268                rules.put(ObjectGroup.ROUTINE_GROUP, IdentifierRules.forMySQLRoutine());
269                break;
270            }
271
272            case dbvstarrocks: {
273                // StarRocks: Fork of Doris, MySQL-compatible, follows same rules as MySQL
274                rules.put(ObjectGroup.NAME_GROUP, IdentifierRules.forStarrocks());
275                rules.put(ObjectGroup.COLUMN_GROUP, IdentifierRules.forStarrocksColumn());
276                rules.put(ObjectGroup.ROUTINE_GROUP, IdentifierRules.forMySQLRoutine());
277                break;
278            }
279
280            case dbvbigquery: {
281                // BigQuery: 表名敏感,列名不敏感
282                rules.put(ObjectGroup.NAME_GROUP, IdentifierRules.forBigQueryTable());
283                rules.put(ObjectGroup.COLUMN_GROUP, IdentifierRules.forBigQueryColumn());
284                rules.put(ObjectGroup.ROUTINE_GROUP, IdentifierRules.forBigQueryTable());
285                break;
286            }
287
288            case dbvdb2:
289            case dbvnetezza:
290            case dbvexasol: {
291                // DB2 家族(DB2, Netezza, Exasol)
292                IdentifierRules rule = IdentifierRules.forDB2();
293                rules.put(ObjectGroup.NAME_GROUP, rule);
294                rules.put(ObjectGroup.COLUMN_GROUP, rule);
295                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
296                break;
297            }
298
299            case dbvsnowflake: {
300                // Snowflake: 根据 QUOTED_IDENTIFIERS_IGNORE_CASE 决定
301                IdentifierRules rule = IdentifierRules.forSnowflake();
302                // TODO: 如果 snowflakeQuotedIdentifiersIgnoreCase = true,需要调整 quotedCompare
303                rules.put(ObjectGroup.NAME_GROUP, rule);
304                rules.put(ObjectGroup.COLUMN_GROUP, rule);
305                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
306                break;
307            }
308
309            case dbvhana: {
310                IdentifierRules rule = IdentifierRules.forHANA();
311                rules.put(ObjectGroup.NAME_GROUP, rule);
312                rules.put(ObjectGroup.COLUMN_GROUP, rule);
313                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
314                break;
315            }
316
317            case dbvpresto:
318            case dbvtrino: {
319                IdentifierRules rule = IdentifierRules.forPresto();
320                rules.put(ObjectGroup.NAME_GROUP, rule);
321                rules.put(ObjectGroup.COLUMN_GROUP, rule);
322                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
323                break;
324            }
325
326            case dbvvertica: {
327                IdentifierRules rule = IdentifierRules.forVertica();
328                rules.put(ObjectGroup.NAME_GROUP, rule);
329                rules.put(ObjectGroup.COLUMN_GROUP, rule);
330                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
331                break;
332            }
333
334            case dbvhive:
335            case dbvsparksql:
336            case dbvflink:
337            case dbvimpala:
338            case dbvdatabricks: {
339                // Hive 家族(Hive, SparkSQL, Flink, Impala, Databricks)
340                IdentifierRules rule = IdentifierRules.forHive();
341                rules.put(ObjectGroup.NAME_GROUP, rule);
342                rules.put(ObjectGroup.COLUMN_GROUP, rule);
343                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
344                break;
345            }
346
347            case dbvteradata: {
348                IdentifierRules rule = IdentifierRules.forTeradata();
349                rules.put(ObjectGroup.NAME_GROUP, rule);
350                rules.put(ObjectGroup.COLUMN_GROUP, rule);
351                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
352                break;
353            }
354
355            case dbvathena: {
356                IdentifierRules rule = IdentifierRules.forAthena();
357                rules.put(ObjectGroup.NAME_GROUP, rule);
358                rules.put(ObjectGroup.COLUMN_GROUP, rule);
359                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
360                break;
361            }
362
363            // 其他数据库使用通用规则(与 PostgreSQL 相同)
364            default: {
365                IdentifierRules rule = IdentifierRules.forGeneric();
366                rules.put(ObjectGroup.NAME_GROUP, rule);
367                rules.put(ObjectGroup.COLUMN_GROUP, rule);
368                rules.put(ObjectGroup.ROUTINE_GROUP, rule);
369                break;
370            }
371        }
372
373        return new IdentifierProfile(vendor, rules, flags);
374    }
375
376    // ===== 查询接口 =====
377
378    /**
379     * 获取指定对象类型的标识符规则
380     *
381     * @param objectType 对象类型
382     * @return 标识符规则
383     */
384    public IdentifierRules getRules(ESQLDataObjectType objectType) {
385        ObjectGroup group = mapToGroup(objectType);
386        return rulesByGroup.get(group);
387    }
388
389    /**
390     * 获取 vendor flags
391     *
392     * @return vendor flags
393     */
394    public VendorFlags getFlags() {
395        return flags;
396    }
397
398    /**
399     * 获取数据库厂商
400     *
401     * @return 厂商
402     */
403    public EDbVendor getVendor() {
404        return vendor;
405    }
406
407    /**
408     * 按对象组获取规则(内部使用)
409     *
410     * @param group 对象组
411     * @return 标识符规则
412     */
413    IdentifierRules getRulesByGroup(ObjectGroup group) {
414        return rulesByGroup.get(group);
415    }
416
417    /**
418     * 将对象类型映射到对象组
419     */
420    private ObjectGroup mapToGroup(ESQLDataObjectType type) {
421        if (type == null) return ObjectGroup.NAME_GROUP;
422
423        switch (type) {
424            case dotColumn:
425                return ObjectGroup.COLUMN_GROUP;
426
427            case dotFunction:
428                return ObjectGroup.ROUTINE_GROUP;
429
430            // 其他所有类型归入 NAME_GROUP
431            case dotCatalog:
432            case dotSchema:
433            case dotTable:
434            case dotProcedure:
435            case dotTrigger:
436            case dotOraclePackage:
437            default:
438                return ObjectGroup.NAME_GROUP;
439        }
440    }
441
442    // ===== 指纹计算(用于缓存失效) =====
443
444    /**
445     * 计算配置指纹(用于 TObjectName 缓存失效)
446     *
447     * <p>当 vendor 或 flags 变化时,指纹会改变,触发缓存失效
448     *
449     * @return 配置指纹(64位哈希值)
450     */
451    public long getFingerprint() {
452        return Objects.hash(
453            vendor,
454            flags.mysqlLowerCaseTableNames,
455            flags.defaultCollation,
456            flags.redshiftEnableCaseSensitive,
457            flags.snowflakeQuotedIdentifiersIgnoreCase
458        );
459    }
460
461    // ===== toString 方法(用于调试) =====
462
463    @Override
464    public String toString() {
465        return String.format("IdentifierProfile{vendor=%s, flags=%s}",
466            vendor, flags);
467    }
468}