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}