fix(db): 修复表列标识符处理逻辑确保聚合函数正常工作

- 修改 ProcessColumn 方法,table.column 格式不再添加反引号,只添加前缀
- 修改 ProcessColumnNoPrefix 方法,table.column 格式不加引号保持原始格式
- 更新 ProcessConditionString 方法,条件字符串中的 table.column 不加反引号
- 修复聚合函数如 Sum、Avg、Max、Min 在 table.column 格式下的正确性
- 添加完整的 table.column 格式测试用例验证功能一致性
- 确保返回的列名与原始列名一致,便于聚合函数等场景读取结果
This commit is contained in:
2026-02-02 11:02:59 +08:00
parent 2d9e6e8e12
commit bf9bb5807d
2 changed files with 143 additions and 20 deletions
+20 -12
View File
@@ -83,21 +83,22 @@ func (p *IdentifierProcessor) ProcessTableNameNoPrefix(name string) string {
// ProcessColumn 处理 table.column 格式
// 输入: "name" 或 "order.name" 或 "`order`.name" 或 "`order`.`name`"
// 输出: "`name`" 或 "`app_order`.`name`" (MySQL)
// 输出: "`name`" 或 "app_order.name"
// 注意: 单独的列名加引号(避免关键字冲突),table.column 格式不加引号
func (p *IdentifierProcessor) ProcessColumn(name string) string {
// 检查是否包含点号
if !strings.Contains(name, ".") {
// 单独的列名,加引号
// 单独的列名,需要加引号(避免关键字冲突)
return p.dialect.QuoteIdentifier(p.stripQuotes(name))
}
// 处理 table.column 格式
// 处理 table.column 格式,不加引号,只添加前缀
parts := p.splitTableColumn(name)
if len(parts) == 2 {
tableName := p.stripQuotes(parts[0])
columnName := p.stripQuotes(parts[1])
// 表名添加前缀
return p.dialect.QuoteIdentifier(p.prefix+tableName) + "." + p.dialect.QuoteIdentifier(columnName)
// table.column 格式不加反引号
return p.prefix + tableName + "." + columnName
}
// 无法解析,返回原样但转换引号
@@ -107,14 +108,16 @@ func (p *IdentifierProcessor) ProcessColumn(name string) string {
// ProcessColumnNoPrefix 处理 table.column 格式(不添加前缀)
func (p *IdentifierProcessor) ProcessColumnNoPrefix(name string) string {
if !strings.Contains(name, ".") {
// 单独的列名,需要加引号(避免关键字冲突)
return p.dialect.QuoteIdentifier(p.stripQuotes(name))
}
// table.column 格式不加引号
parts := p.splitTableColumn(name)
if len(parts) == 2 {
tableName := p.stripQuotes(parts[0])
columnName := p.stripQuotes(parts[1])
return p.dialect.QuoteIdentifier(tableName) + "." + p.dialect.QuoteIdentifier(columnName)
return tableName + "." + columnName
}
return p.convertQuotes(name)
@@ -122,7 +125,9 @@ func (p *IdentifierProcessor) ProcessColumnNoPrefix(name string) string {
// ProcessConditionString 智能解析条件字符串(如 ON 条件)
// 输入: "user.id = order.user_id AND order.status = 1"
// 输出: "`app_user`.`id` = `app_order`.`user_id` AND `app_order`.`status` = 1" (MySQL)
// 输出: "app_user.id = app_order.user_id AND app_order.status = 1"
// 注意: table.column 格式不加反引号,因为 MySQL/SQLite/PostgreSQL 都能正确解析
// 这样可以保持返回的列名与原始列名一致,便于聚合函数等场景读取结果
func (p *IdentifierProcessor) ProcessConditionString(condition string) string {
if condition == "" {
return condition
@@ -131,20 +136,21 @@ func (p *IdentifierProcessor) ProcessConditionString(condition string) string {
result := condition
// 首先处理已有完整引号的情况 `table`.`column` 或 "table"."column"
// 这些需要先处理,因为它们的格式最明确
// 去除引号,只添加前缀
fullyQuotedPattern := regexp.MustCompile("[`\"]([a-zA-Z_][a-zA-Z0-9_]*)[`\"]\\.[`\"]([a-zA-Z_][a-zA-Z0-9_]*)[`\"]")
result = fullyQuotedPattern.ReplaceAllStringFunc(result, func(match string) string {
parts := fullyQuotedPattern.FindStringSubmatch(match)
if len(parts) == 3 {
tableName := parts[1]
colName := parts[2]
return p.dialect.QuoteIdentifier(p.prefix+tableName) + "." + p.dialect.QuoteIdentifier(colName)
// table.column 格式不加反引号,只添加前缀
return p.prefix + tableName + "." + colName
}
return match
})
// 然后处理部分引号的情况 `table`.column 或 "table".column
// 注意:需要避免匹配已处理的内容(已经是双引号包裹的)
// 去除引号,只添加前缀
quotedTablePattern := regexp.MustCompile("[`\"]([a-zA-Z_][a-zA-Z0-9_]*)[`\"]\\.([a-zA-Z_][a-zA-Z0-9_]*)(?:[^`\"]|$)")
result = quotedTablePattern.ReplaceAllStringFunc(result, func(match string) string {
parts := quotedTablePattern.FindStringSubmatch(match)
@@ -159,7 +165,8 @@ func (p *IdentifierProcessor) ProcessConditionString(condition string) string {
suffix = string(lastChar)
}
}
return p.dialect.QuoteIdentifier(p.prefix+tableName) + "." + p.dialect.QuoteIdentifier(colName) + suffix
// table.column 格式不加反引号,只添加前缀
return p.prefix + tableName + "." + colName + suffix
}
return match
})
@@ -174,7 +181,8 @@ func (p *IdentifierProcessor) ProcessConditionString(condition string) string {
tableName := parts[2]
colName := parts[3]
suffix := parts[4] // 后面的边界字符
return prefix + p.dialect.QuoteIdentifier(p.prefix+tableName) + "." + p.dialect.QuoteIdentifier(colName) + suffix
// table.column 格式不加反引号,只添加前缀
return prefix + p.prefix + tableName + "." + colName + suffix
}
return match
})