public class IdentifierService extends Object
提供所有标识符规范化和比较的统一入口。
为什么需要它(面向入门者):
不同数据库对名称的大小写和引号行为差别很大(是否区分大小写、是否折叠为大/小写、是否受 collation 影响)。
如果在业务代码里到处手写 toLowerCase/equalsIgnoreCase,很容易出错且难以维护。
本服务将“如何折叠与如何比较”的规则集中在一个地方,确保全局一致、可扩展、易测试。
与其它类的关系:
IdentifierRules:一张“规则卡片”(策略),描述未引号/带引号的折叠(fold)与比较(compare)。IdentifierProfile:一个“厂商档案”,为某个数据库厂商打包不同对象组(表/列/函数)的规则,并携带厂商开关(如 MySQL lower_case_table_names、SQL Server collation)。normalize/areEqual/keyForMap 接口(门面)。设计理念与收益:
keyForMap(java.lang.String, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType) 先做规范化,Map 查找 O(1);SQL Server 经 CollatorProvider 做 collation 比较。使用了哪些设计模式:
IdentifierRules 即为可替换的规则策略。IdentifierRules.forOracle()/forPostgreSQL()、IdentifierProfile.forVendor(...) 产出预设策略组合。IdentifierProfile 与可选 CollatorProvider,便于替换与测试。CollatorProvider 解耦 SQL Server 的 collation 依赖。关键约束(必须遵守):
keyForMap(java.lang.String, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType)areEqual(java.lang.String, java.lang.String, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType)String.toUpperCase/toLowerCase/equalsIgnoreCase使用示例:
IdentifierService service = new IdentifierService(profile, collatorProvider);
// 规范化标识符(用于索引键)
String key = service.normalize("MyTable", ESQLDataObjectType.dotTable);
// Oracle: "MYTABLE", PostgreSQL: "mytable", ClickHouse: "MyTable"
// 比较两个标识符
boolean eq = service.areEqual("MyTable", "MYTABLE", ESQLDataObjectType.dotTable);
// Oracle: true, ClickHouse: false
// 构造索引键
String mapKey = service.keyForMap("MyTable", ESQLDataObjectType.dotTable);
| Constructor and Description |
|---|
IdentifierService(IdentifierProfile profile,
CollatorProvider collatorProvider)
构造标识符服务
|
| Modifier and Type | Method and Description |
|---|---|
boolean |
areEqual(String ident1,
String ident2,
ESQLDataObjectType objectType)
比较两个标识符是否相等
|
static boolean |
areEqualStatic(EDbVendor dbVendor,
ESQLDataObjectType objectType,
String ident1,
String ident2)
High-performance static identifier comparison method with caching
|
void |
assertSingleSegmentOrThrow(String identifier,
ESQLDataObjectType objectType)
断言标识符为单段,否则抛出异常
|
String |
buildCompositeKey(List<String> segments,
ESQLDataObjectType objectType)
构造复合键(使用长度前缀编码避免冲突)
|
String |
buildCompositeKey(String qualifiedName,
ESQLDataObjectType objectType)
构造复合键(从完整限定名)
|
boolean |
canUseCompositeKey(String qualifiedName)
判断是否可以使用复合键快速路径
|
List<String> |
expandVendorSpecific(List<String> segments,
EDbVendor vendor)
厂商级预处理(展开特殊语法)
|
List<String> |
expandVendorSpecific(List<String> segments,
EDbVendor vendor,
String defaultSchema)
厂商级预处理(展开特殊语法)
|
CollatorProvider |
getCollatorProvider()
获取 Collator 提供者
|
IdentifierProfile |
getProfile()
获取标识符配置档案
|
String |
keyForMap(String identifier,
ESQLDataObjectType objectType)
为 Map 索引构造键(单个标识符段)
|
List<String> |
keysForHierarchy(String qualifiedName,
List<ESQLDataObjectType> partTypes)
生成层级索引所需的段级键列表
|
String |
normalize(String identifier,
ESQLDataObjectType objectType)
规范化标识符(去引号 + 大小写折叠)
|
String |
normalizeQualifiedName(String qualifiedName,
ESQLDataObjectType objectType)
规范化完整限定名(等价于 SQLUtil.getIdentifierNormalName)
|
String |
normalizeSegment(String segment,
ESQLDataObjectType objectType)
规范化单个段(去引号 + 大小写折叠)
|
static String |
normalizeStatic(EDbVendor dbVendor,
ESQLDataObjectType objectType,
String identifier)
High-performance static normalize method with caching
|
List<String> |
parseQualifiedName(String qualifiedName)
解析完整限定名为段列表
|
public IdentifierService(IdentifierProfile profile, CollatorProvider collatorProvider)
profile - 厂商标识符配置档案collatorProvider - Collator 提供者(SQL Server 专用,可为 null)public static String normalizeStatic(EDbVendor dbVendor, ESQLDataObjectType objectType, String identifier)
This method provides a convenient static interface for identifier normalization while leveraging a pre-populated cache of IdentifierService instances.
Performance characteristics:
Usage example:
String normalized = IdentifierService.normalizeStatic(
EDbVendor.dbvoracle,
ESQLDataObjectType.dotTable,
"MyTable"
);
// Result: "MYTABLE"
dbVendor - database vendorobjectType - object type (table, column, schema, etc.)identifier - identifier to normalize (may be quoted)public static boolean areEqualStatic(EDbVendor dbVendor, ESQLDataObjectType objectType, String ident1, String ident2)
This method provides a convenient static interface for identifier comparison while leveraging a pre-populated cache of IdentifierService instances.
Performance characteristics:
Usage example:
boolean equal = IdentifierService.areEqualStatic(
EDbVendor.dbvoracle,
ESQLDataObjectType.dotTable,
"MyTable",
"MYTABLE"
);
// Result: true (Oracle is case-insensitive for unquoted identifiers)
dbVendor - database vendorobjectType - object type (table, column, schema, etc.)ident1 - first identifier to compare (may be quoted)ident2 - second identifier to compare (may be quoted)public String normalize(String identifier, ESQLDataObjectType objectType)
用于构造索引键,确保相同语义的标识符生成相同的键。
identifier - 原始标识符(可能带引号)objectType - 对象类型public boolean areEqual(String ident1, String ident2, ESQLDataObjectType objectType)
根据数据库厂商的大小写规则进行比较。
ident1 - 标识符 1ident2 - 标识符 2objectType - 对象类型public String keyForMap(String identifier, ESQLDataObjectType objectType)
注意:此方法仅用于分层索引的单段键,不用于复合键。
对于 COLLATION_BASED(SQL Server),不做 fold,返回原始标识符 (后续通过桶+Collator 比较)。
identifier - 标识符objectType - 对象类型public boolean canUseCompositeKey(String qualifiedName)
条件(必须全部满足):
qualifiedName - 完整限定名(如 "db.schema.table")public String buildCompositeKey(List<String> segments, ESQLDataObjectType objectType)
格式: len1#segment1|len2#segment2|len3#segment3|objectType
例如: "3#db1|6#schema|5#table|dotTable"
优势:避免分隔符冲突(标识符可能包含 '.' 或 '|')
segments - 标识符段列表objectType - 对象类型public String buildCompositeKey(String qualifiedName, ESQLDataObjectType objectType)
qualifiedName - 完整限定名(如 "db.schema.table")objectType - 对象类型public List<String> parseQualifiedName(String qualifiedName)
包装 SQLUtil#parseNames(String, EDbVendor) 以支持厂商特定解析:
qualifiedName - 完整限定名(如 "db.schema.table" 或 "db..table")public List<String> expandVendorSpecific(List<String> segments, EDbVendor vendor)
处理厂商特定语法:
segments - 原始段列表vendor - 数据库厂商public List<String> expandVendorSpecific(List<String> segments, EDbVendor vendor, String defaultSchema)
处理厂商特定语法:
segments - 原始段列表vendor - 数据库厂商defaultSchema - 默认 schema,如果为 null 则使用 "dbo"public String normalizeSegment(String segment, ESQLDataObjectType objectType)
与 normalize(String, ESQLDataObjectType) 类似,但语义明确为"单段"处理。
segment - 单个段标识符objectType - 对象类型public String normalizeQualifiedName(String qualifiedName, ESQLDataObjectType objectType)
处理流程:
parseQualifiedName(String)
expandVendorSpecific(List, EDbVendor)
normalizeSegment(String, ESQLDataObjectType)
qualifiedName - 完整限定名objectType - 最终对象类型(dotTable/dotColumn/dotSchema 等)public List<String> keysForHierarchy(String qualifiedName, List<ESQLDataObjectType> partTypes)
用于分层索引(hierarchical index),确保各层键由 keyForMap(java.lang.String, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType) 统一生成。
注意:调用前应先调用 parseQualifiedName(String) 和
expandVendorSpecific(List, EDbVendor) 完成解析与展开。
qualifiedName - 完整限定名partTypes - 各段对应的对象类型列表(长度应与段数一致)IllegalArgumentException - 如果段数与类型数不匹配public void assertSingleSegmentOrThrow(String identifier, ESQLDataObjectType objectType)
用于在 keyForMap(java.lang.String, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType) 入口处确保输入为单段标识符(不包含 '.' 分隔符)。
如果 TBaseType.ALLOW_MULTI_SEGMENT_IN_KEY 为 true(兼容模式),
则仅记录警告日志而不抛异常。
identifier - 待检查的标识符IllegalArgumentException - 如果标识符包含多段且未启用兼容模式public IdentifierProfile getProfile()
public CollatorProvider getCollatorProvider()