aboutsummaryrefslogtreecommitdiff
path: root/weed/query/engine/alias_timestamp_integration_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/query/engine/alias_timestamp_integration_test.go')
-rw-r--r--weed/query/engine/alias_timestamp_integration_test.go252
1 files changed, 252 insertions, 0 deletions
diff --git a/weed/query/engine/alias_timestamp_integration_test.go b/weed/query/engine/alias_timestamp_integration_test.go
new file mode 100644
index 000000000..eca8161db
--- /dev/null
+++ b/weed/query/engine/alias_timestamp_integration_test.go
@@ -0,0 +1,252 @@
+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")
+ })
+}