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.
		
		
		
		
		
			
		
			
				
					
					
						
							245 lines
						
					
					
						
							9.1 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							245 lines
						
					
					
						
							9.1 KiB
						
					
					
				
								package engine
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"strconv"
							 | 
						|
									"testing"
							 | 
						|
								
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
							 | 
						|
									"github.com/stretchr/testify/assert"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// TestTimestampQueryFixes tests all the timestamp query fixes comprehensively
							 | 
						|
								func TestTimestampQueryFixes(t *testing.T) {
							 | 
						|
									engine := NewTestSQLEngine()
							 | 
						|
								
							 | 
						|
									// Test timestamps from the actual failing cases
							 | 
						|
									largeTimestamp1 := int64(1756947416566456262) // Original failing query
							 | 
						|
									largeTimestamp2 := int64(1756947416566439304) // Second failing query
							 | 
						|
									largeTimestamp3 := int64(1756913789829292386) // Current data timestamp
							 | 
						|
								
							 | 
						|
									t.Run("Fix1_PrecisionLoss", func(t *testing.T) {
							 | 
						|
										// Test that large int64 timestamps don't lose precision in comparisons
							 | 
						|
										testRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: largeTimestamp1}},
							 | 
						|
												"id":     {Kind: &schema_pb.Value_Int64Value{Int64Value: 12345}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Test equality comparison
							 | 
						|
										result := engine.valuesEqual(testRecord.Fields["_ts_ns"], largeTimestamp1)
							 | 
						|
										assert.True(t, result, "Large timestamp equality should work without precision loss")
							 | 
						|
								
							 | 
						|
										// Test inequality comparison
							 | 
						|
										result = engine.valuesEqual(testRecord.Fields["_ts_ns"], largeTimestamp1+1)
							 | 
						|
										assert.False(t, result, "Large timestamp inequality should be detected accurately")
							 | 
						|
								
							 | 
						|
										// Test less than comparison
							 | 
						|
										result = engine.valueLessThan(testRecord.Fields["_ts_ns"], largeTimestamp1+1)
							 | 
						|
										assert.True(t, result, "Large timestamp less-than should work without precision loss")
							 | 
						|
								
							 | 
						|
										// Test greater than comparison
							 | 
						|
										result = engine.valueGreaterThan(testRecord.Fields["_ts_ns"], largeTimestamp1-1)
							 | 
						|
										assert.True(t, result, "Large timestamp greater-than should work without precision loss")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Fix2_TimeFilterExtraction", func(t *testing.T) {
							 | 
						|
										// Test that equality queries don't set stopTimeNs (which causes premature termination)
							 | 
						|
										equalitySQL := "SELECT * FROM test WHERE _ts_ns = " + strconv.FormatInt(largeTimestamp2, 10)
							 | 
						|
										stmt, err := ParseSQL(equalitySQL)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										startTimeNs, stopTimeNs := engine.extractTimeFilters(selectStmt.Where.Expr)
							 | 
						|
								
							 | 
						|
										assert.Equal(t, largeTimestamp2-1, startTimeNs, "Equality query should set startTimeNs to target-1")
							 | 
						|
										assert.Equal(t, int64(0), stopTimeNs, "Equality query should NOT set stopTimeNs to avoid early termination")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Fix3_RangeBoundaryFix", func(t *testing.T) {
							 | 
						|
										// Test that range queries with equal boundaries don't cause premature termination
							 | 
						|
										rangeSQL := "SELECT * FROM test WHERE _ts_ns >= " + strconv.FormatInt(largeTimestamp3, 10) +
							 | 
						|
											" AND _ts_ns <= " + strconv.FormatInt(largeTimestamp3, 10)
							 | 
						|
										stmt, err := ParseSQL(rangeSQL)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										startTimeNs, stopTimeNs := engine.extractTimeFilters(selectStmt.Where.Expr)
							 | 
						|
								
							 | 
						|
										// Should be treated like an equality query to avoid premature termination
							 | 
						|
										assert.NotEqual(t, int64(0), startTimeNs, "Range with equal boundaries should set startTimeNs")
							 | 
						|
										assert.Equal(t, int64(0), stopTimeNs, "Range with equal boundaries should NOT set stopTimeNs")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Fix4_DifferentRangeBoundaries", func(t *testing.T) {
							 | 
						|
										// Test that normal range queries still work correctly
							 | 
						|
										rangeSQL := "SELECT * FROM test WHERE _ts_ns >= " + strconv.FormatInt(largeTimestamp1, 10) +
							 | 
						|
											" AND _ts_ns <= " + strconv.FormatInt(largeTimestamp2, 10)
							 | 
						|
										stmt, err := ParseSQL(rangeSQL)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										startTimeNs, stopTimeNs := engine.extractTimeFilters(selectStmt.Where.Expr)
							 | 
						|
								
							 | 
						|
										assert.Equal(t, largeTimestamp1, startTimeNs, "Range query should set correct startTimeNs")
							 | 
						|
										assert.Equal(t, largeTimestamp2, stopTimeNs, "Range query should set correct stopTimeNs")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Fix5_PredicateAccuracy", func(t *testing.T) {
							 | 
						|
										// Test that predicates correctly evaluate large timestamp equality
							 | 
						|
										equalitySQL := "SELECT * FROM test WHERE _ts_ns = " + strconv.FormatInt(largeTimestamp1, 10)
							 | 
						|
										stmt, err := ParseSQL(equalitySQL)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										predicate, err := engine.buildPredicate(selectStmt.Where.Expr)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										// Test with matching record
							 | 
						|
										matchingRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: largeTimestamp1}},
							 | 
						|
												"id":     {Kind: &schema_pb.Value_Int64Value{Int64Value: 897795}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										result := predicate(matchingRecord)
							 | 
						|
										assert.True(t, result, "Predicate should match record with exact timestamp")
							 | 
						|
								
							 | 
						|
										// Test with non-matching record
							 | 
						|
										nonMatchingRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: largeTimestamp1 + 1}},
							 | 
						|
												"id":     {Kind: &schema_pb.Value_Int64Value{Int64Value: 12345}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										result = predicate(nonMatchingRecord)
							 | 
						|
										assert.False(t, result, "Predicate should NOT match record with different timestamp")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Fix6_ComparisonOperators", func(t *testing.T) {
							 | 
						|
										// Test all comparison operators work correctly with large timestamps
							 | 
						|
										testRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: largeTimestamp2}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										operators := []struct {
							 | 
						|
											sql      string
							 | 
						|
											expected bool
							 | 
						|
										}{
							 | 
						|
											{"_ts_ns = " + strconv.FormatInt(largeTimestamp2, 10), true},
							 | 
						|
											{"_ts_ns = " + strconv.FormatInt(largeTimestamp2+1, 10), false},
							 | 
						|
											{"_ts_ns > " + strconv.FormatInt(largeTimestamp2-1, 10), true},
							 | 
						|
											{"_ts_ns > " + strconv.FormatInt(largeTimestamp2, 10), false},
							 | 
						|
											{"_ts_ns >= " + strconv.FormatInt(largeTimestamp2, 10), true},
							 | 
						|
											{"_ts_ns >= " + strconv.FormatInt(largeTimestamp2+1, 10), false},
							 | 
						|
											{"_ts_ns < " + strconv.FormatInt(largeTimestamp2+1, 10), true},
							 | 
						|
											{"_ts_ns < " + strconv.FormatInt(largeTimestamp2, 10), false},
							 | 
						|
											{"_ts_ns <= " + strconv.FormatInt(largeTimestamp2, 10), true},
							 | 
						|
											{"_ts_ns <= " + strconv.FormatInt(largeTimestamp2-1, 10), false},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										for _, op := range operators {
							 | 
						|
											sql := "SELECT * FROM test WHERE " + op.sql
							 | 
						|
											stmt, err := ParseSQL(sql)
							 | 
						|
											assert.NoError(t, err, "Should parse SQL: %s", op.sql)
							 | 
						|
								
							 | 
						|
											selectStmt := stmt.(*SelectStatement)
							 | 
						|
											predicate, err := engine.buildPredicate(selectStmt.Where.Expr)
							 | 
						|
											assert.NoError(t, err, "Should build predicate for: %s", op.sql)
							 | 
						|
								
							 | 
						|
											result := predicate(testRecord)
							 | 
						|
											assert.Equal(t, op.expected, result, "Operator test failed for: %s", op.sql)
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("Fix7_EdgeCases", func(t *testing.T) {
							 | 
						|
										// Test edge cases and boundary conditions
							 | 
						|
								
							 | 
						|
										// Maximum int64 value
							 | 
						|
										maxInt64 := int64(9223372036854775807)
							 | 
						|
										testRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: maxInt64}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Test equality with maximum int64
							 | 
						|
										result := engine.valuesEqual(testRecord.Fields["_ts_ns"], maxInt64)
							 | 
						|
										assert.True(t, result, "Should handle maximum int64 value correctly")
							 | 
						|
								
							 | 
						|
										// Test with zero timestamp
							 | 
						|
										zeroRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: 0}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										result = engine.valuesEqual(zeroRecord.Fields["_ts_ns"], int64(0))
							 | 
						|
										assert.True(t, result, "Should handle zero timestamp correctly")
							 | 
						|
									})
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// TestOriginalFailingQueries tests the specific queries that were failing before the fixes
							 | 
						|
								func TestOriginalFailingQueries(t *testing.T) {
							 | 
						|
									engine := NewTestSQLEngine()
							 | 
						|
								
							 | 
						|
									failingQueries := []struct {
							 | 
						|
										name      string
							 | 
						|
										sql       string
							 | 
						|
										timestamp int64
							 | 
						|
										id        int64
							 | 
						|
									}{
							 | 
						|
										{
							 | 
						|
											name:      "OriginalQuery1",
							 | 
						|
											sql:       "select id, _ts_ns from ecommerce.user_events where _ts_ns = 1756947416566456262",
							 | 
						|
											timestamp: 1756947416566456262,
							 | 
						|
											id:        897795,
							 | 
						|
										},
							 | 
						|
										{
							 | 
						|
											name:      "OriginalQuery2",
							 | 
						|
											sql:       "select id, _ts_ns from ecommerce.user_events where _ts_ns = 1756947416566439304",
							 | 
						|
											timestamp: 1756947416566439304,
							 | 
						|
											id:        715356,
							 | 
						|
										},
							 | 
						|
										{
							 | 
						|
											name:      "CurrentDataQuery",
							 | 
						|
											sql:       "select id, _ts_ns from ecommerce.user_events where _ts_ns = 1756913789829292386",
							 | 
						|
											timestamp: 1756913789829292386,
							 | 
						|
											id:        82460,
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									for _, query := range failingQueries {
							 | 
						|
										t.Run(query.name, func(t *testing.T) {
							 | 
						|
											// Parse the SQL
							 | 
						|
											stmt, err := ParseSQL(query.sql)
							 | 
						|
											assert.NoError(t, err, "Should parse the failing query")
							 | 
						|
								
							 | 
						|
											selectStmt := stmt.(*SelectStatement)
							 | 
						|
								
							 | 
						|
											// Test time filter extraction
							 | 
						|
											startTimeNs, stopTimeNs := engine.extractTimeFilters(selectStmt.Where.Expr)
							 | 
						|
											assert.Equal(t, query.timestamp-1, startTimeNs, "Should set startTimeNs to timestamp-1")
							 | 
						|
											assert.Equal(t, int64(0), stopTimeNs, "Should not set stopTimeNs for equality")
							 | 
						|
								
							 | 
						|
											// Test predicate building and evaluation
							 | 
						|
											predicate, err := engine.buildPredicate(selectStmt.Where.Expr)
							 | 
						|
											assert.NoError(t, err, "Should build predicate")
							 | 
						|
								
							 | 
						|
											// Test with matching record
							 | 
						|
											matchingRecord := &schema_pb.RecordValue{
							 | 
						|
												Fields: map[string]*schema_pb.Value{
							 | 
						|
													"_ts_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: query.timestamp}},
							 | 
						|
													"id":     {Kind: &schema_pb.Value_Int64Value{Int64Value: query.id}},
							 | 
						|
												},
							 | 
						|
											}
							 | 
						|
								
							 | 
						|
											result := predicate(matchingRecord)
							 | 
						|
											assert.True(t, result, "Predicate should match the target record for query: %s", query.name)
							 | 
						|
										})
							 | 
						|
									}
							 | 
						|
								}
							 |