diff options
Diffstat (limited to 'weed/query/engine/alias_timestamp_integration_test.go')
| -rw-r--r-- | weed/query/engine/alias_timestamp_integration_test.go | 252 |
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") + }) +} |
