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.
		
		
		
		
		
			
		
			
				
					
					
						
							252 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							252 lines
						
					
					
						
							10 KiB
						
					
					
				
								package engine
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"strconv"
							 | 
						|
									"testing"
							 | 
						|
								
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
							 | 
						|
									"github.com/stretchr/testify/assert"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// TestAliasTimestampIntegration tests that SQL aliases work correctly with timestamp query fixes
							 | 
						|
								func TestAliasTimestampIntegration(t *testing.T) {
							 | 
						|
									engine := NewTestSQLEngine()
							 | 
						|
								
							 | 
						|
									// Use the exact timestamps from the original failing production queries
							 | 
						|
									originalFailingTimestamps := []int64{
							 | 
						|
										1756947416566456262, // Original failing query 1
							 | 
						|
										1756947416566439304, // Original failing query 2
							 | 
						|
										1756913789829292386, // Current data timestamp
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									t.Run("AliasWithLargeTimestamps", func(t *testing.T) {
							 | 
						|
										for i, timestamp := range originalFailingTimestamps {
							 | 
						|
											t.Run("Timestamp_"+strconv.Itoa(i+1), func(t *testing.T) {
							 | 
						|
												// Create test record
							 | 
						|
												testRecord := &schema_pb.RecordValue{
							 | 
						|
													Fields: map[string]*schema_pb.Value{
							 | 
						|
														"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: timestamp}},
							 | 
						|
														"id":            {Kind: &schema_pb.Value_Int64Value{Int64Value: int64(1000 + i)}},
							 | 
						|
													},
							 | 
						|
												}
							 | 
						|
								
							 | 
						|
												// Test equality with alias (this was the originally failing pattern)
							 | 
						|
												sql := "SELECT _timestamp_ns AS ts, id FROM test WHERE ts = " + strconv.FormatInt(timestamp, 10)
							 | 
						|
												stmt, err := ParseSQL(sql)
							 | 
						|
												assert.NoError(t, err, "Should parse alias equality query for timestamp %d", timestamp)
							 | 
						|
								
							 | 
						|
												selectStmt := stmt.(*SelectStatement)
							 | 
						|
												predicate, err := engine.buildPredicateWithContext(selectStmt.Where.Expr, selectStmt.SelectExprs)
							 | 
						|
												assert.NoError(t, err, "Should build predicate for large timestamp with alias")
							 | 
						|
								
							 | 
						|
												result := predicate(testRecord)
							 | 
						|
												assert.True(t, result, "Should match exact large timestamp using alias")
							 | 
						|
								
							 | 
						|
												// Test precision - off by 1 nanosecond should not match
							 | 
						|
												sqlOffBy1 := "SELECT _timestamp_ns AS ts, id FROM test WHERE ts = " + strconv.FormatInt(timestamp+1, 10)
							 | 
						|
												stmt2, err := ParseSQL(sqlOffBy1)
							 | 
						|
												assert.NoError(t, err)
							 | 
						|
												selectStmt2 := stmt2.(*SelectStatement)
							 | 
						|
												predicate2, err := engine.buildPredicateWithContext(selectStmt2.Where.Expr, selectStmt2.SelectExprs)
							 | 
						|
												assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
												result2 := predicate2(testRecord)
							 | 
						|
												assert.False(t, result2, "Should not match timestamp off by 1 nanosecond with alias")
							 | 
						|
											})
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("AliasWithTimestampRangeQueries", func(t *testing.T) {
							 | 
						|
										timestamp := int64(1756947416566456262)
							 | 
						|
								
							 | 
						|
										testRecords := []*schema_pb.RecordValue{
							 | 
						|
											{
							 | 
						|
												Fields: map[string]*schema_pb.Value{
							 | 
						|
													"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: timestamp - 2}}, // Before range
							 | 
						|
												},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Fields: map[string]*schema_pb.Value{
							 | 
						|
													"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: timestamp}}, // In range
							 | 
						|
												},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Fields: map[string]*schema_pb.Value{
							 | 
						|
													"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: timestamp + 2}}, // After range
							 | 
						|
												},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Test range query with alias
							 | 
						|
										sql := "SELECT _timestamp_ns AS ts FROM test WHERE ts >= " +
							 | 
						|
											strconv.FormatInt(timestamp-1, 10) + " AND ts <= " +
							 | 
						|
											strconv.FormatInt(timestamp+1, 10)
							 | 
						|
										stmt, err := ParseSQL(sql)
							 | 
						|
										assert.NoError(t, err, "Should parse range query with alias")
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										predicate, err := engine.buildPredicateWithContext(selectStmt.Where.Expr, selectStmt.SelectExprs)
							 | 
						|
										assert.NoError(t, err, "Should build range predicate with alias")
							 | 
						|
								
							 | 
						|
										// Test each record
							 | 
						|
										assert.False(t, predicate(testRecords[0]), "Should not match record before range")
							 | 
						|
										assert.True(t, predicate(testRecords[1]), "Should match record in range")
							 | 
						|
										assert.False(t, predicate(testRecords[2]), "Should not match record after range")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("AliasWithTimestampPrecisionEdgeCases", func(t *testing.T) {
							 | 
						|
										// Test maximum int64 value
							 | 
						|
										maxInt64 := int64(9223372036854775807)
							 | 
						|
										testRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: maxInt64}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Test with alias
							 | 
						|
										sql := "SELECT _timestamp_ns AS ts FROM test WHERE ts = " + strconv.FormatInt(maxInt64, 10)
							 | 
						|
										stmt, err := ParseSQL(sql)
							 | 
						|
										assert.NoError(t, err, "Should parse max int64 with alias")
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										predicate, err := engine.buildPredicateWithContext(selectStmt.Where.Expr, selectStmt.SelectExprs)
							 | 
						|
										assert.NoError(t, err, "Should build predicate for max int64 with alias")
							 | 
						|
								
							 | 
						|
										result := predicate(testRecord)
							 | 
						|
										assert.True(t, result, "Should handle max int64 value correctly with alias")
							 | 
						|
								
							 | 
						|
										// Test minimum value
							 | 
						|
										minInt64 := int64(-9223372036854775808)
							 | 
						|
										testRecord2 := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: minInt64}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										sql2 := "SELECT _timestamp_ns AS ts FROM test WHERE ts = " + strconv.FormatInt(minInt64, 10)
							 | 
						|
										stmt2, err := ParseSQL(sql2)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
										selectStmt2 := stmt2.(*SelectStatement)
							 | 
						|
										predicate2, err := engine.buildPredicateWithContext(selectStmt2.Where.Expr, selectStmt2.SelectExprs)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										result2 := predicate2(testRecord2)
							 | 
						|
										assert.True(t, result2, "Should handle min int64 value correctly with alias")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("MultipleAliasesWithTimestamps", func(t *testing.T) {
							 | 
						|
										// Test multiple aliases including timestamps
							 | 
						|
										timestamp1 := int64(1756947416566456262)
							 | 
						|
										timestamp2 := int64(1756913789829292386)
							 | 
						|
								
							 | 
						|
										testRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: timestamp1}},
							 | 
						|
												"created_at":    {Kind: &schema_pb.Value_Int64Value{Int64Value: timestamp2}},
							 | 
						|
												"id":            {Kind: &schema_pb.Value_Int64Value{Int64Value: 12345}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// Use multiple timestamp aliases in WHERE
							 | 
						|
										sql := "SELECT _timestamp_ns AS event_time, created_at AS created_time, id AS record_id FROM test " +
							 | 
						|
											"WHERE event_time = " + strconv.FormatInt(timestamp1, 10) +
							 | 
						|
											" AND created_time = " + strconv.FormatInt(timestamp2, 10) +
							 | 
						|
											" AND record_id = 12345"
							 | 
						|
								
							 | 
						|
										stmt, err := ParseSQL(sql)
							 | 
						|
										assert.NoError(t, err, "Should parse complex query with multiple timestamp aliases")
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										predicate, err := engine.buildPredicateWithContext(selectStmt.Where.Expr, selectStmt.SelectExprs)
							 | 
						|
										assert.NoError(t, err, "Should build predicate for multiple timestamp aliases")
							 | 
						|
								
							 | 
						|
										result := predicate(testRecord)
							 | 
						|
										assert.True(t, result, "Should match complex query with multiple timestamp aliases")
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("CompatibilityWithExistingTimestampFixes", func(t *testing.T) {
							 | 
						|
										// Verify that all the timestamp fixes (precision, scan boundaries, etc.) still work with aliases
							 | 
						|
										largeTimestamp := int64(1756947416566456262)
							 | 
						|
								
							 | 
						|
										// Test all comparison operators with aliases
							 | 
						|
										operators := []struct {
							 | 
						|
											sql      string
							 | 
						|
											value    int64
							 | 
						|
											expected bool
							 | 
						|
										}{
							 | 
						|
											{"ts = " + strconv.FormatInt(largeTimestamp, 10), largeTimestamp, true},
							 | 
						|
											{"ts = " + strconv.FormatInt(largeTimestamp+1, 10), largeTimestamp, false},
							 | 
						|
											{"ts > " + strconv.FormatInt(largeTimestamp-1, 10), largeTimestamp, true},
							 | 
						|
											{"ts > " + strconv.FormatInt(largeTimestamp, 10), largeTimestamp, false},
							 | 
						|
											{"ts >= " + strconv.FormatInt(largeTimestamp, 10), largeTimestamp, true},
							 | 
						|
											{"ts >= " + strconv.FormatInt(largeTimestamp+1, 10), largeTimestamp, false},
							 | 
						|
											{"ts < " + strconv.FormatInt(largeTimestamp+1, 10), largeTimestamp, true},
							 | 
						|
											{"ts < " + strconv.FormatInt(largeTimestamp, 10), largeTimestamp, false},
							 | 
						|
											{"ts <= " + strconv.FormatInt(largeTimestamp, 10), largeTimestamp, true},
							 | 
						|
											{"ts <= " + strconv.FormatInt(largeTimestamp-1, 10), largeTimestamp, false},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										for _, op := range operators {
							 | 
						|
											t.Run(op.sql, func(t *testing.T) {
							 | 
						|
												testRecord := &schema_pb.RecordValue{
							 | 
						|
													Fields: map[string]*schema_pb.Value{
							 | 
						|
														"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: op.value}},
							 | 
						|
													},
							 | 
						|
												}
							 | 
						|
								
							 | 
						|
												sql := "SELECT _timestamp_ns AS ts FROM test WHERE " + op.sql
							 | 
						|
												stmt, err := ParseSQL(sql)
							 | 
						|
												assert.NoError(t, err, "Should parse: %s", op.sql)
							 | 
						|
								
							 | 
						|
												selectStmt := stmt.(*SelectStatement)
							 | 
						|
												predicate, err := engine.buildPredicateWithContext(selectStmt.Where.Expr, selectStmt.SelectExprs)
							 | 
						|
												assert.NoError(t, err, "Should build predicate for: %s", op.sql)
							 | 
						|
								
							 | 
						|
												result := predicate(testRecord)
							 | 
						|
												assert.Equal(t, op.expected, result, "Alias operator test failed for: %s", op.sql)
							 | 
						|
											})
							 | 
						|
										}
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									t.Run("ProductionScenarioReproduction", func(t *testing.T) {
							 | 
						|
										// Reproduce the exact production scenario that was originally failing
							 | 
						|
								
							 | 
						|
										// This was the original failing pattern from the user
							 | 
						|
										originalFailingSQL := "select id, _timestamp_ns as ts from ecommerce.user_events where ts = 1756913789829292386"
							 | 
						|
								
							 | 
						|
										testRecord := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: 1756913789829292386}},
							 | 
						|
												"id":            {Kind: &schema_pb.Value_Int64Value{Int64Value: 82460}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										stmt, err := ParseSQL(originalFailingSQL)
							 | 
						|
										assert.NoError(t, err, "Should parse the exact originally failing production query")
							 | 
						|
								
							 | 
						|
										selectStmt := stmt.(*SelectStatement)
							 | 
						|
										predicate, err := engine.buildPredicateWithContext(selectStmt.Where.Expr, selectStmt.SelectExprs)
							 | 
						|
										assert.NoError(t, err, "Should build predicate for original failing query")
							 | 
						|
								
							 | 
						|
										result := predicate(testRecord)
							 | 
						|
										assert.True(t, result, "The originally failing production query should now work perfectly")
							 | 
						|
								
							 | 
						|
										// Also test the other originally failing timestamp
							 | 
						|
										originalFailingSQL2 := "select id, _timestamp_ns as ts from ecommerce.user_events where ts = 1756947416566456262"
							 | 
						|
										testRecord2 := &schema_pb.RecordValue{
							 | 
						|
											Fields: map[string]*schema_pb.Value{
							 | 
						|
												"_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: 1756947416566456262}},
							 | 
						|
												"id":            {Kind: &schema_pb.Value_Int64Value{Int64Value: 897795}},
							 | 
						|
											},
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										stmt2, err := ParseSQL(originalFailingSQL2)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
										selectStmt2 := stmt2.(*SelectStatement)
							 | 
						|
										predicate2, err := engine.buildPredicateWithContext(selectStmt2.Where.Expr, selectStmt2.SelectExprs)
							 | 
						|
										assert.NoError(t, err)
							 | 
						|
								
							 | 
						|
										result2 := predicate2(testRecord2)
							 | 
						|
										assert.True(t, result2, "The second originally failing production query should now work perfectly")
							 | 
						|
									})
							 | 
						|
								}
							 |