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}