You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							217 lines
						
					
					
						
							5.7 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							217 lines
						
					
					
						
							5.7 KiB
						
					
					
				| package engine | |
| 
 | |
| import ( | |
| 	"fmt" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb" | |
| 	"github.com/seaweedfs/seaweedfs/weed/query/sqltypes" | |
| ) | |
| 
 | |
| // formatAggregationResult formats an aggregation result into a SQL value | |
| func (e *SQLEngine) formatAggregationResult(spec AggregationSpec, result AggregationResult) sqltypes.Value { | |
| 	switch spec.Function { | |
| 	case "COUNT": | |
| 		return sqltypes.NewInt64(result.Count) | |
| 	case "SUM": | |
| 		return sqltypes.NewFloat64(result.Sum) | |
| 	case "AVG": | |
| 		return sqltypes.NewFloat64(result.Sum) // Sum contains the average for AVG | |
| 	case "MIN": | |
| 		if result.Min != nil { | |
| 			return e.convertRawValueToSQL(result.Min) | |
| 		} | |
| 		return sqltypes.NULL | |
| 	case "MAX": | |
| 		if result.Max != nil { | |
| 			return e.convertRawValueToSQL(result.Max) | |
| 		} | |
| 		return sqltypes.NULL | |
| 	} | |
| 	return sqltypes.NULL | |
| } | |
| 
 | |
| // convertRawValueToSQL converts a raw Go value to a SQL value | |
| func (e *SQLEngine) convertRawValueToSQL(value interface{}) sqltypes.Value { | |
| 	switch v := value.(type) { | |
| 	case int32: | |
| 		return sqltypes.NewInt32(v) | |
| 	case int64: | |
| 		return sqltypes.NewInt64(v) | |
| 	case float32: | |
| 		return sqltypes.NewFloat32(v) | |
| 	case float64: | |
| 		return sqltypes.NewFloat64(v) | |
| 	case string: | |
| 		return sqltypes.NewVarChar(v) | |
| 	case bool: | |
| 		if v { | |
| 			return sqltypes.NewVarChar("1") | |
| 		} | |
| 		return sqltypes.NewVarChar("0") | |
| 	} | |
| 	return sqltypes.NULL | |
| } | |
| 
 | |
| // extractRawValue extracts the raw Go value from a schema_pb.Value | |
| func (e *SQLEngine) extractRawValue(value *schema_pb.Value) interface{} { | |
| 	switch v := value.Kind.(type) { | |
| 	case *schema_pb.Value_Int32Value: | |
| 		return v.Int32Value | |
| 	case *schema_pb.Value_Int64Value: | |
| 		return v.Int64Value | |
| 	case *schema_pb.Value_FloatValue: | |
| 		return v.FloatValue | |
| 	case *schema_pb.Value_DoubleValue: | |
| 		return v.DoubleValue | |
| 	case *schema_pb.Value_StringValue: | |
| 		return v.StringValue | |
| 	case *schema_pb.Value_BoolValue: | |
| 		return v.BoolValue | |
| 	case *schema_pb.Value_BytesValue: | |
| 		return string(v.BytesValue) // Convert bytes to string for comparison | |
| 	} | |
| 	return nil | |
| } | |
| 
 | |
| // compareValues compares two schema_pb.Value objects | |
| func (e *SQLEngine) compareValues(value1 *schema_pb.Value, value2 *schema_pb.Value) int { | |
| 	if value2 == nil { | |
| 		return 1 // value1 > nil | |
| 	} | |
| 	raw1 := e.extractRawValue(value1) | |
| 	raw2 := e.extractRawValue(value2) | |
| 	if raw1 == nil { | |
| 		return -1 | |
| 	} | |
| 	if raw2 == nil { | |
| 		return 1 | |
| 	} | |
| 
 | |
| 	// Simple comparison - in a full implementation this would handle type coercion | |
| 	switch v1 := raw1.(type) { | |
| 	case int32: | |
| 		if v2, ok := raw2.(int32); ok { | |
| 			if v1 < v2 { | |
| 				return -1 | |
| 			} else if v1 > v2 { | |
| 				return 1 | |
| 			} | |
| 			return 0 | |
| 		} | |
| 	case int64: | |
| 		if v2, ok := raw2.(int64); ok { | |
| 			if v1 < v2 { | |
| 				return -1 | |
| 			} else if v1 > v2 { | |
| 				return 1 | |
| 			} | |
| 			return 0 | |
| 		} | |
| 	case float32: | |
| 		if v2, ok := raw2.(float32); ok { | |
| 			if v1 < v2 { | |
| 				return -1 | |
| 			} else if v1 > v2 { | |
| 				return 1 | |
| 			} | |
| 			return 0 | |
| 		} | |
| 	case float64: | |
| 		if v2, ok := raw2.(float64); ok { | |
| 			if v1 < v2 { | |
| 				return -1 | |
| 			} else if v1 > v2 { | |
| 				return 1 | |
| 			} | |
| 			return 0 | |
| 		} | |
| 	case string: | |
| 		if v2, ok := raw2.(string); ok { | |
| 			if v1 < v2 { | |
| 				return -1 | |
| 			} else if v1 > v2 { | |
| 				return 1 | |
| 			} | |
| 			return 0 | |
| 		} | |
| 	case bool: | |
| 		if v2, ok := raw2.(bool); ok { | |
| 			if v1 == v2 { | |
| 				return 0 | |
| 			} else if v1 && !v2 { | |
| 				return 1 | |
| 			} | |
| 			return -1 | |
| 		} | |
| 	} | |
| 	return 0 | |
| } | |
| 
 | |
| // convertRawValueToSchemaValue converts raw Go values back to schema_pb.Value for comparison | |
| func (e *SQLEngine) convertRawValueToSchemaValue(rawValue interface{}) *schema_pb.Value { | |
| 	switch v := rawValue.(type) { | |
| 	case int32: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_Int32Value{Int32Value: v}} | |
| 	case int64: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: v}} | |
| 	case float32: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_FloatValue{FloatValue: v}} | |
| 	case float64: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: v}} | |
| 	case string: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_StringValue{StringValue: v}} | |
| 	case bool: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_BoolValue{BoolValue: v}} | |
| 	case []byte: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_BytesValue{BytesValue: v}} | |
| 	default: | |
| 		// Convert other types to string as fallback | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_StringValue{StringValue: fmt.Sprintf("%v", v)}} | |
| 	} | |
| } | |
| 
 | |
| // convertJSONValueToSchemaValue converts JSON values to schema_pb.Value | |
| func (e *SQLEngine) convertJSONValueToSchemaValue(jsonValue interface{}) *schema_pb.Value { | |
| 	switch v := jsonValue.(type) { | |
| 	case string: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_StringValue{StringValue: v}} | |
| 	case float64: | |
| 		// JSON numbers are always float64, try to detect if it's actually an integer | |
| 		if v == float64(int64(v)) { | |
| 			return &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: int64(v)}} | |
| 		} | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: v}} | |
| 	case bool: | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_BoolValue{BoolValue: v}} | |
| 	case nil: | |
| 		return nil | |
| 	default: | |
| 		// Convert other types to string | |
| 		return &schema_pb.Value{Kind: &schema_pb.Value_StringValue{StringValue: fmt.Sprintf("%v", v)}} | |
| 	} | |
| } | |
| 
 | |
| // Helper functions for aggregation processing | |
|  | |
| // isNullValue checks if a schema_pb.Value is null or empty | |
| func (e *SQLEngine) isNullValue(value *schema_pb.Value) bool { | |
| 	return value == nil || value.Kind == nil | |
| } | |
| 
 | |
| // convertToNumber converts a schema_pb.Value to a float64 for numeric operations | |
| func (e *SQLEngine) convertToNumber(value *schema_pb.Value) *float64 { | |
| 	switch v := value.Kind.(type) { | |
| 	case *schema_pb.Value_Int32Value: | |
| 		result := float64(v.Int32Value) | |
| 		return &result | |
| 	case *schema_pb.Value_Int64Value: | |
| 		result := float64(v.Int64Value) | |
| 		return &result | |
| 	case *schema_pb.Value_FloatValue: | |
| 		result := float64(v.FloatValue) | |
| 		return &result | |
| 	case *schema_pb.Value_DoubleValue: | |
| 		return &v.DoubleValue | |
| 	} | |
| 	return nil | |
| }
 |