arithmetic_only_execution_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package engine
  2. import (
  3. "context"
  4. "testing"
  5. )
  6. // TestSQLEngine_ArithmeticOnlyQueryExecution tests the specific fix for queries
  7. // that contain ONLY arithmetic expressions (no base columns) in the SELECT clause.
  8. // This was the root issue reported where such queries returned empty values.
  9. func TestSQLEngine_ArithmeticOnlyQueryExecution(t *testing.T) {
  10. engine := NewTestSQLEngine()
  11. // Test the core functionality: arithmetic-only queries should return data
  12. tests := []struct {
  13. name string
  14. query string
  15. expectedCols []string
  16. mustNotBeEmpty bool
  17. }{
  18. {
  19. name: "Basic arithmetic only query",
  20. query: "SELECT id+user_id, id*2 FROM user_events LIMIT 3",
  21. expectedCols: []string{"id+user_id", "id*2"},
  22. mustNotBeEmpty: true,
  23. },
  24. {
  25. name: "With LIMIT and OFFSET - original user issue",
  26. query: "SELECT id+user_id, id*2 FROM user_events LIMIT 2 OFFSET 1",
  27. expectedCols: []string{"id+user_id", "id*2"},
  28. mustNotBeEmpty: true,
  29. },
  30. {
  31. name: "Multiple arithmetic expressions",
  32. query: "SELECT user_id+100, id-1000 FROM user_events LIMIT 1",
  33. expectedCols: []string{"user_id+100", "id-1000"},
  34. mustNotBeEmpty: true,
  35. },
  36. }
  37. for _, tt := range tests {
  38. t.Run(tt.name, func(t *testing.T) {
  39. result, err := engine.ExecuteSQL(context.Background(), tt.query)
  40. if err != nil {
  41. t.Fatalf("Query failed: %v", err)
  42. }
  43. if result.Error != nil {
  44. t.Fatalf("Query returned error: %v", result.Error)
  45. }
  46. // CRITICAL: Verify we got results (the original bug would return empty)
  47. if tt.mustNotBeEmpty && len(result.Rows) == 0 {
  48. t.Fatal("CRITICAL BUG: Query returned no rows - arithmetic-only query fix failed!")
  49. }
  50. // Verify column count and names
  51. if len(result.Columns) != len(tt.expectedCols) {
  52. t.Errorf("Expected %d columns, got %d", len(tt.expectedCols), len(result.Columns))
  53. }
  54. // CRITICAL: Verify no empty/null values (the original bug symptom)
  55. if len(result.Rows) > 0 {
  56. firstRow := result.Rows[0]
  57. for i, val := range firstRow {
  58. if val.IsNull() {
  59. t.Errorf("CRITICAL BUG: Column %d (%s) returned NULL", i, result.Columns[i])
  60. }
  61. if val.ToString() == "" {
  62. t.Errorf("CRITICAL BUG: Column %d (%s) returned empty string", i, result.Columns[i])
  63. }
  64. }
  65. }
  66. // Log success
  67. t.Logf("SUCCESS: %s returned %d rows with calculated values", tt.query, len(result.Rows))
  68. })
  69. }
  70. }
  71. // TestSQLEngine_ArithmeticOnlyQueryBugReproduction tests that the original bug
  72. // (returning empty values) would have failed before our fix
  73. func TestSQLEngine_ArithmeticOnlyQueryBugReproduction(t *testing.T) {
  74. engine := NewTestSQLEngine()
  75. // This is the EXACT query from the user's bug report
  76. query := "SELECT id+user_id, id*amount, id*2 FROM user_events LIMIT 10 OFFSET 5"
  77. result, err := engine.ExecuteSQL(context.Background(), query)
  78. if err != nil {
  79. t.Fatalf("Query failed: %v", err)
  80. }
  81. if result.Error != nil {
  82. t.Fatalf("Query returned error: %v", result.Error)
  83. }
  84. // Key assertions that would fail with the original bug:
  85. // 1. Must return rows (bug would return 0 rows or empty results)
  86. if len(result.Rows) == 0 {
  87. t.Fatal("CRITICAL: Query returned no rows - the original bug is NOT fixed!")
  88. }
  89. // 2. Must have expected columns
  90. expectedColumns := []string{"id+user_id", "id*amount", "id*2"}
  91. if len(result.Columns) != len(expectedColumns) {
  92. t.Errorf("Expected %d columns, got %d", len(expectedColumns), len(result.Columns))
  93. }
  94. // 3. Must have calculated values, not empty/null
  95. for i, row := range result.Rows {
  96. for j, val := range row {
  97. if val.IsNull() {
  98. t.Errorf("Row %d, Column %d (%s) is NULL - original bug not fixed!",
  99. i, j, result.Columns[j])
  100. }
  101. if val.ToString() == "" {
  102. t.Errorf("Row %d, Column %d (%s) is empty - original bug not fixed!",
  103. i, j, result.Columns[j])
  104. }
  105. }
  106. }
  107. // 4. Verify specific calculations for the OFFSET 5 data
  108. if len(result.Rows) > 0 {
  109. firstRow := result.Rows[0]
  110. // With OFFSET 5, first returned row should be 6th row: id=417224, user_id=7810
  111. expectedSum := "425034" // 417224 + 7810
  112. if firstRow[0].ToString() != expectedSum {
  113. t.Errorf("OFFSET 5 calculation wrong: expected id+user_id=%s, got %s",
  114. expectedSum, firstRow[0].ToString())
  115. }
  116. expectedDouble := "834448" // 417224 * 2
  117. if firstRow[2].ToString() != expectedDouble {
  118. t.Errorf("OFFSET 5 calculation wrong: expected id*2=%s, got %s",
  119. expectedDouble, firstRow[2].ToString())
  120. }
  121. }
  122. t.Logf("SUCCESS: Arithmetic-only query with OFFSET works correctly!")
  123. t.Logf("Query: %s", query)
  124. t.Logf("Returned %d rows with correct calculations", len(result.Rows))
  125. }