Files
streamsql/stream/processor_field.go
T
2025-08-05 00:37:22 +08:00

593 lines
18 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package stream
import (
"fmt"
"strconv"
"strings"
"github.com/rulego/streamsql/expr"
"github.com/rulego/streamsql/functions"
"github.com/rulego/streamsql/logger"
"github.com/rulego/streamsql/utils/fieldpath"
)
// fieldProcessInfo field processing information for caching pre-compiled field processing logic
type fieldProcessInfo struct {
fieldName string // Original field name
outputName string // Output field name
isFunctionCall bool // Whether it's a function call
hasNestedField bool // Whether it contains nested fields
isSelectAll bool // Whether it's SELECT *
isStringLiteral bool // Whether it's a string literal
stringValue string // Pre-processed string literal value (quotes removed)
alias string // Field alias for quick access
}
// expressionProcessInfo expression processing information for caching pre-compiled expression processing logic
type expressionProcessInfo struct {
originalExpr string // Original expression
processedExpr string // Pre-processed expression
isFunctionCall bool // Whether it's a function call
hasNestedFields bool // Whether it contains nested fields
compiledExpr *expr.Expression // Pre-compiled expression object
needsBacktickPreprocess bool // Whether backtick preprocessing is needed
}
// compileFieldProcessInfo pre-compiles field processing information to avoid runtime re-parsing
func (s *Stream) compileFieldProcessInfo() {
s.compiledFieldInfo = make(map[string]*fieldProcessInfo)
s.compiledExprInfo = make(map[string]*expressionProcessInfo)
// Compile SimpleFields information
for _, fieldSpec := range s.config.SimpleFields {
info := s.compileSimpleFieldInfo(fieldSpec)
s.compiledFieldInfo[fieldSpec] = info
}
// Pre-compile expression field information
s.compileExpressionInfo()
}
// compileSimpleFieldInfo compiles simple field information
func (s *Stream) compileSimpleFieldInfo(fieldSpec string) *fieldProcessInfo {
info := &fieldProcessInfo{}
if fieldSpec == "*" {
info.isSelectAll = true
info.fieldName = ""
info.outputName = "*"
info.alias = "*"
return info
}
// Parse alias
parts := strings.Split(fieldSpec, ":")
info.fieldName = parts[0]
// Remove backticks from field name
if len(info.fieldName) >= 2 && info.fieldName[0] == '`' && info.fieldName[len(info.fieldName)-1] == '`' {
info.fieldName = info.fieldName[1 : len(info.fieldName)-1]
}
info.outputName = info.fieldName
if len(parts) > 1 {
info.outputName = parts[1]
// Remove backticks from output name
if len(info.outputName) >= 2 && info.outputName[0] == '`' && info.outputName[len(info.outputName)-1] == '`' {
info.outputName = info.outputName[1 : len(info.outputName)-1]
}
}
// Pre-determine field characteristics
info.isFunctionCall = strings.Contains(info.fieldName, "(") && strings.Contains(info.fieldName, ")")
info.hasNestedField = !info.isFunctionCall && fieldpath.IsNestedField(info.fieldName)
// Check if it's a string literal and preprocess value
info.isStringLiteral = (len(info.fieldName) >= 2 &&
((info.fieldName[0] == '\'' && info.fieldName[len(info.fieldName)-1] == '\'') ||
(info.fieldName[0] == '"' && info.fieldName[len(info.fieldName)-1] == '"')))
// Preprocess string literal value, remove quotes
if info.isStringLiteral && len(info.fieldName) >= 2 {
info.stringValue = info.fieldName[1 : len(info.fieldName)-1]
}
// Set alias for quick access
info.alias = info.outputName
return info
}
// compileExpressionInfo pre-compiles expression processing information
func (s *Stream) compileExpressionInfo() {
bridge := functions.GetExprBridge()
for fieldName, fieldExpr := range s.config.FieldExpressions {
exprInfo := &expressionProcessInfo{
originalExpr: fieldExpr.Expression,
}
// 预处理表达式
processedExpr := fieldExpr.Expression
if bridge.ContainsIsNullOperator(processedExpr) {
if processed, err := bridge.PreprocessIsNullExpression(processedExpr); err == nil {
processedExpr = processed
}
}
if bridge.ContainsLikeOperator(processedExpr) {
if processed, err := bridge.PreprocessLikeExpression(processedExpr); err == nil {
processedExpr = processed
}
}
exprInfo.processedExpr = processedExpr
// 预判断表达式特征
exprInfo.isFunctionCall = strings.Contains(fieldExpr.Expression, "(") && strings.Contains(fieldExpr.Expression, ")")
exprInfo.hasNestedFields = !exprInfo.isFunctionCall && strings.Contains(fieldExpr.Expression, ".")
exprInfo.needsBacktickPreprocess = bridge.ContainsBacktickIdentifiers(fieldExpr.Expression)
// 预编译表达式对象(仅对非函数调用的表达式)
if !exprInfo.isFunctionCall {
exprToCompile := fieldExpr.Expression
if exprInfo.needsBacktickPreprocess {
if processed, err := bridge.PreprocessBacktickIdentifiers(exprToCompile); err == nil {
exprToCompile = processed
}
}
if compiledExpr, err := expr.NewExpression(exprToCompile); err == nil {
exprInfo.compiledExpr = compiledExpr
}
}
s.compiledExprInfo[fieldName] = exprInfo
}
}
// processExpressionField 处理表达式字段
func (s *Stream) processExpressionField(fieldName string, dataMap map[string]interface{}, result map[string]interface{}) {
exprInfo := s.compiledExprInfo[fieldName]
if exprInfo == nil {
// 回退到原逻辑(安全性保证)
s.processExpressionFieldFallback(fieldName, dataMap, result)
return
}
var evalResult interface{}
bridge := functions.GetExprBridge()
if exprInfo.isFunctionCall {
// 对于函数调用,使用桥接器处理
exprResult, err := bridge.EvaluateExpression(exprInfo.processedExpr, dataMap)
if err != nil {
logger.Error("Function call evaluation failed for field %s: %v", fieldName, err)
result[fieldName] = nil
return
}
evalResult = exprResult
} else if exprInfo.hasNestedFields {
// 使用预编译的表达式对象
if exprInfo.compiledExpr != nil {
// 使用EvaluateValueWithNull获取实际值包括字符串
exprResult, isNull, err := exprInfo.compiledExpr.EvaluateValueWithNull(dataMap)
if err != nil {
logger.Error("Expression evaluation failed for field %s: %v", fieldName, err)
result[fieldName] = nil
return
}
if isNull {
evalResult = nil
} else {
evalResult = exprResult
}
} else {
// 回退到动态编译
s.processExpressionFieldFallback(fieldName, dataMap, result)
return
}
} else {
// 尝试使用桥接器处理其他表达式
exprResult, err := bridge.EvaluateExpression(exprInfo.processedExpr, dataMap)
if err != nil {
// 如果桥接器失败,使用预编译的表达式对象
if exprInfo.compiledExpr != nil {
// 使用EvaluateValueWithNull获取实际值包括字符串
exprResult, isNull, evalErr := exprInfo.compiledExpr.EvaluateValueWithNull(dataMap)
if evalErr != nil {
logger.Error("Expression evaluation failed for field %s: %v", fieldName, evalErr)
result[fieldName] = nil
return
}
if isNull {
evalResult = nil
} else {
evalResult = exprResult
}
} else {
// 回退到动态编译
s.processExpressionFieldFallback(fieldName, dataMap, result)
return
}
} else {
evalResult = exprResult
}
}
result[fieldName] = evalResult
}
// processExpressionFieldFallback 表达式字段处理的回退逻辑
func (s *Stream) processExpressionFieldFallback(fieldName string, dataMap map[string]interface{}, result map[string]interface{}) {
fieldExpr, exists := s.config.FieldExpressions[fieldName]
if !exists {
result[fieldName] = nil
return
}
// 使用桥接器计算表达式支持IS NULL等语法
bridge := functions.GetExprBridge()
// 预处理表达式中的IS NULL和LIKE语法
processedExpr := fieldExpr.Expression
if bridge.ContainsIsNullOperator(processedExpr) {
if processed, err := bridge.PreprocessIsNullExpression(processedExpr); err == nil {
processedExpr = processed
}
}
if bridge.ContainsLikeOperator(processedExpr) {
if processed, err := bridge.PreprocessLikeExpression(processedExpr); err == nil {
processedExpr = processed
}
}
// 检查表达式是否是函数调用(包含括号)
isFunctionCall := strings.Contains(fieldExpr.Expression, "(") && strings.Contains(fieldExpr.Expression, ")")
// 检查表达式是否包含嵌套字段(但排除函数调用中的点号)
hasNestedFields := false
if !isFunctionCall && strings.Contains(fieldExpr.Expression, ".") {
hasNestedFields = true
}
var evalResult interface{}
if isFunctionCall {
// 对于函数调用,优先使用桥接器处理
exprResult, err := bridge.EvaluateExpression(processedExpr, dataMap)
if err != nil {
logger.Error("Function call evaluation failed for field %s: %v", fieldName, err)
result[fieldName] = nil
return
}
evalResult = exprResult
} else if hasNestedFields {
// 检测到嵌套字段(非函数调用),使用自定义表达式引擎
exprToUse := fieldExpr.Expression
if bridge.ContainsBacktickIdentifiers(exprToUse) {
if processed, err := bridge.PreprocessBacktickIdentifiers(exprToUse); err == nil {
exprToUse = processed
}
}
expression, parseErr := expr.NewExpression(exprToUse)
if parseErr != nil {
logger.Error("Expression parse failed for field %s: %v", fieldName, parseErr)
result[fieldName] = nil
return
}
// 使用EvaluateValueWithNull获取实际值包括字符串
exprResult, isNull, err := expression.EvaluateValueWithNull(dataMap)
if err != nil {
logger.Error("Expression evaluation failed for field %s: %v", fieldName, err)
result[fieldName] = nil
return
}
if isNull {
evalResult = nil
} else {
evalResult = exprResult
}
} else {
// 尝试使用桥接器处理其他表达式
exprResult, err := bridge.EvaluateExpression(processedExpr, dataMap)
if err != nil {
// 如果桥接器失败,回退到原来的表达式引擎
exprToUse := fieldExpr.Expression
if bridge.ContainsBacktickIdentifiers(exprToUse) {
if processed, err := bridge.PreprocessBacktickIdentifiers(exprToUse); err == nil {
exprToUse = processed
}
}
expression, parseErr := expr.NewExpression(exprToUse)
if parseErr != nil {
logger.Error("Expression parse failed for field %s: %v", fieldName, parseErr)
result[fieldName] = nil
return
}
// 使用EvaluateValueWithNull获取实际值包括字符串
exprResult, isNull, evalErr := expression.EvaluateValueWithNull(dataMap)
if evalErr != nil {
logger.Error("Expression evaluation failed for field %s: %v", fieldName, evalErr)
result[fieldName] = nil
return
}
if isNull {
evalResult = nil
} else {
evalResult = exprResult
}
} else {
evalResult = exprResult
}
}
result[fieldName] = evalResult
}
// processSimpleField 处理简单字段
func (s *Stream) processSimpleField(fieldSpec string, dataMap map[string]interface{}, data interface{}, result map[string]interface{}) {
info := s.compiledFieldInfo[fieldSpec]
if info == nil {
// 如果没有预编译信息,回退到原逻辑(安全性保证)
s.processSingleFieldFallback(fieldSpec, dataMap, data, result)
return
}
if info.isSelectAll {
// SELECT *:批量复制所有字段,跳过表达式字段
for k, v := range dataMap {
if _, isExpression := s.config.FieldExpressions[k]; !isExpression {
result[k] = v
}
}
return
}
// 跳过已经通过表达式字段处理的字段
if _, isExpression := s.config.FieldExpressions[info.outputName]; isExpression {
return
}
if info.isStringLiteral {
// 字符串字面量处理:使用预编译的字符串值
result[info.alias] = info.stringValue
} else if info.isFunctionCall {
// 执行函数调用
if funcResult, err := s.executeFunction(info.fieldName, dataMap); err == nil {
result[info.outputName] = funcResult
} else {
logger.Error("Function execution error %s: %v", info.fieldName, err)
result[info.outputName] = nil
}
} else {
// 普通字段处理
var value interface{}
var exists bool
if info.hasNestedField {
value, exists = fieldpath.GetNestedField(data, info.fieldName)
} else {
value, exists = dataMap[info.fieldName]
}
if exists {
result[info.outputName] = value
} else {
result[info.outputName] = nil
}
}
}
// processSingleFieldFallback 回退处理单个字段(当预编译信息缺失时)
func (s *Stream) processSingleFieldFallback(fieldSpec string, dataMap map[string]interface{}, data interface{}, result map[string]interface{}) {
// 处理SELECT *的特殊情况
if fieldSpec == "*" {
// SELECT *:返回所有字段,但跳过已经通过表达式字段处理的字段
for k, v := range dataMap {
// 如果该字段已经通过表达式字段处理,则跳过,保持表达式计算结果
if _, isExpression := s.config.FieldExpressions[k]; !isExpression {
result[k] = v
}
}
return
}
// 处理别名
parts := strings.Split(fieldSpec, ":")
fieldName := parts[0]
outputName := fieldName
if len(parts) > 1 {
outputName = parts[1]
}
// 跳过已经通过表达式字段处理的字段
if _, isExpression := s.config.FieldExpressions[outputName]; isExpression {
return
}
// 检查是否是函数调用
if strings.Contains(fieldName, "(") && strings.Contains(fieldName, ")") {
// 执行函数调用
if funcResult, err := s.executeFunction(fieldName, dataMap); err == nil {
result[outputName] = funcResult
} else {
logger.Error("Function execution error %s: %v", fieldName, err)
result[outputName] = nil
}
} else {
// 普通字段 - 支持嵌套字段
var value interface{}
var exists bool
if fieldpath.IsNestedField(fieldName) {
value, exists = fieldpath.GetNestedField(data, fieldName)
} else {
value, exists = dataMap[fieldName]
}
if exists {
result[outputName] = value
} else {
result[outputName] = nil
}
}
}
// executeFunction 执行函数调用
func (s *Stream) executeFunction(funcExpr string, data map[string]interface{}) (interface{}, error) {
// 检查是否是自定义函数
funcName := extractFunctionName(funcExpr)
if funcName != "" {
// 直接使用函数系统
fn, exists := functions.Get(funcName)
if exists {
// 解析参数
args, err := s.parseFunctionArgs(funcExpr, data)
if err != nil {
return nil, err
}
// 创建函数上下文
ctx := &functions.FunctionContext{Data: data}
// 执行函数
return fn.Execute(ctx, args)
}
}
// 对于复杂的嵌套函数调用直接使用ExprBridge
// 这样可以避免Expression.Evaluate的float64类型限制
bridge := functions.GetExprBridge()
result, err := bridge.EvaluateExpression(funcExpr, data)
if err != nil {
return nil, fmt.Errorf("evaluate function expression failed: %w", err)
}
return result, nil
}
// extractFunctionName 从表达式中提取函数名
func extractFunctionName(expr string) string {
parenIndex := strings.Index(expr, "(")
if parenIndex == -1 {
return ""
}
funcName := strings.TrimSpace(expr[:parenIndex])
if strings.ContainsAny(funcName, " +-*/=<>!&|") {
return ""
}
return funcName
}
// parseFunctionArgs 解析函数参数,支持嵌套函数调用
func (s *Stream) parseFunctionArgs(funcExpr string, data map[string]interface{}) ([]interface{}, error) {
// 提取括号内的参数
start := strings.Index(funcExpr, "(")
end := strings.LastIndex(funcExpr, ")")
if start == -1 || end == -1 || end <= start {
return nil, fmt.Errorf("invalid function expression: %s", funcExpr)
}
argsStr := strings.TrimSpace(funcExpr[start+1 : end])
if argsStr == "" {
return []interface{}{}, nil
}
// 智能分割参数,处理嵌套函数和引号
argParts, err := s.smartSplitArgs(argsStr)
if err != nil {
return nil, err
}
args := make([]interface{}, len(argParts))
for i, arg := range argParts {
arg = strings.TrimSpace(arg)
// 如果参数是字符串常量(用引号包围)
if strings.HasPrefix(arg, "'") && strings.HasSuffix(arg, "'") {
args[i] = strings.Trim(arg, "'")
} else if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") {
args[i] = strings.Trim(arg, "\"")
} else if strings.Contains(arg, "(") {
// 如果参数包含函数调用,递归执行
result, err := s.executeFunction(arg, data)
if err != nil {
return nil, fmt.Errorf("failed to execute nested function '%s': %v", arg, err)
}
args[i] = result
} else if value, exists := data[arg]; exists {
// 如果是数据字段
args[i] = value
} else {
// 尝试解析为数字
if val, err := strconv.ParseFloat(arg, 64); err == nil {
args[i] = val
} else {
args[i] = arg
}
}
}
return args, nil
}
// smartSplitArgs 智能分割参数,考虑括号嵌套和引号
func (s *Stream) smartSplitArgs(argsStr string) ([]string, error) {
var args []string
var current strings.Builder
parenDepth := 0
inQuotes := false
quoteChar := byte(0)
for i := 0; i < len(argsStr); i++ {
ch := argsStr[i]
switch ch {
case '\'':
if !inQuotes {
inQuotes = true
quoteChar = ch
} else if quoteChar == ch {
inQuotes = false
quoteChar = 0
}
current.WriteByte(ch)
case '"':
if !inQuotes {
inQuotes = true
quoteChar = ch
} else if quoteChar == ch {
inQuotes = false
quoteChar = 0
}
current.WriteByte(ch)
case '(':
if !inQuotes {
parenDepth++
}
current.WriteByte(ch)
case ')':
if !inQuotes {
parenDepth--
}
current.WriteByte(ch)
case ',':
if !inQuotes && parenDepth == 0 {
// 找到参数分隔符
args = append(args, strings.TrimSpace(current.String()))
current.Reset()
} else {
current.WriteByte(ch)
}
default:
current.WriteByte(ch)
}
}
// 添加最后一个参数
if current.Len() > 0 {
args = append(args, strings.TrimSpace(current.String()))
}
return args, nil
}