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
							 | 
						|
								}
							 |