aboutsummaryrefslogtreecommitdiff
path: root/weed/query/engine/timestamp_query_fixes_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/query/engine/timestamp_query_fixes_test.go')
-rw-r--r--weed/query/engine/timestamp_query_fixes_test.go245
1 files changed, 245 insertions, 0 deletions
diff --git a/weed/query/engine/timestamp_query_fixes_test.go b/weed/query/engine/timestamp_query_fixes_test.go
new file mode 100644
index 000000000..633738a00
--- /dev/null
+++ b/weed/query/engine/timestamp_query_fixes_test.go
@@ -0,0 +1,245 @@
+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{
+ "_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: largeTimestamp1}},
+ "id": {Kind: &schema_pb.Value_Int64Value{Int64Value: 12345}},
+ },
+ }
+
+ // Test equality comparison
+ result := engine.valuesEqual(testRecord.Fields["_timestamp_ns"], largeTimestamp1)
+ assert.True(t, result, "Large timestamp equality should work without precision loss")
+
+ // Test inequality comparison
+ result = engine.valuesEqual(testRecord.Fields["_timestamp_ns"], largeTimestamp1+1)
+ assert.False(t, result, "Large timestamp inequality should be detected accurately")
+
+ // Test less than comparison
+ result = engine.valueLessThan(testRecord.Fields["_timestamp_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["_timestamp_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 _timestamp_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 _timestamp_ns >= " + strconv.FormatInt(largeTimestamp3, 10) +
+ " AND _timestamp_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 _timestamp_ns >= " + strconv.FormatInt(largeTimestamp1, 10) +
+ " AND _timestamp_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 _timestamp_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{
+ "_timestamp_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{
+ "_timestamp_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{
+ "_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: largeTimestamp2}},
+ },
+ }
+
+ operators := []struct {
+ sql string
+ expected bool
+ }{
+ {"_timestamp_ns = " + strconv.FormatInt(largeTimestamp2, 10), true},
+ {"_timestamp_ns = " + strconv.FormatInt(largeTimestamp2+1, 10), false},
+ {"_timestamp_ns > " + strconv.FormatInt(largeTimestamp2-1, 10), true},
+ {"_timestamp_ns > " + strconv.FormatInt(largeTimestamp2, 10), false},
+ {"_timestamp_ns >= " + strconv.FormatInt(largeTimestamp2, 10), true},
+ {"_timestamp_ns >= " + strconv.FormatInt(largeTimestamp2+1, 10), false},
+ {"_timestamp_ns < " + strconv.FormatInt(largeTimestamp2+1, 10), true},
+ {"_timestamp_ns < " + strconv.FormatInt(largeTimestamp2, 10), false},
+ {"_timestamp_ns <= " + strconv.FormatInt(largeTimestamp2, 10), true},
+ {"_timestamp_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{
+ "_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: maxInt64}},
+ },
+ }
+
+ // Test equality with maximum int64
+ result := engine.valuesEqual(testRecord.Fields["_timestamp_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{
+ "_timestamp_ns": {Kind: &schema_pb.Value_Int64Value{Int64Value: 0}},
+ },
+ }
+
+ result = engine.valuesEqual(zeroRecord.Fields["_timestamp_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, _timestamp_ns from ecommerce.user_events where _timestamp_ns = 1756947416566456262",
+ timestamp: 1756947416566456262,
+ id: 897795,
+ },
+ {
+ name: "OriginalQuery2",
+ sql: "select id, _timestamp_ns from ecommerce.user_events where _timestamp_ns = 1756947416566439304",
+ timestamp: 1756947416566439304,
+ id: 715356,
+ },
+ {
+ name: "CurrentDataQuery",
+ sql: "select id, _timestamp_ns from ecommerce.user_events where _timestamp_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{
+ "_timestamp_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)
+ })
+ }
+}