2
0

window.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package executor
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. "github.com/danfragoso/pizzasql-next/pkg/parser"
  7. "github.com/danfragoso/pizzasql-next/pkg/storage"
  8. )
  9. // computeWindowValues evaluates each window function in a projection over the
  10. // given rows, returning one value per row for each window expression.
  11. func (e *Executor) computeWindowValues(stmt *parser.SelectStmt, rows []storage.Row) (map[*parser.WindowExpr][]interface{}, error) {
  12. var windows []*parser.WindowExpr
  13. for _, col := range stmt.Columns {
  14. if we, ok := col.Expr.(*parser.WindowExpr); ok {
  15. windows = append(windows, we)
  16. }
  17. }
  18. if len(windows) == 0 {
  19. return nil, nil
  20. }
  21. out := make(map[*parser.WindowExpr][]interface{}, len(windows))
  22. for _, we := range windows {
  23. values, err := e.evalWindowExpr(we, rows)
  24. if err != nil {
  25. return nil, err
  26. }
  27. out[we] = values
  28. }
  29. return out, nil
  30. }
  31. type windowRow struct {
  32. idx int
  33. key []interface{}
  34. }
  35. // evalWindowExpr computes ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...).
  36. // Other window functions are rejected rather than approximated.
  37. func (e *Executor) evalWindowExpr(we *parser.WindowExpr, rows []storage.Row) ([]interface{}, error) {
  38. name := ""
  39. if we.Func != nil {
  40. name = strings.ToUpper(we.Func.Name)
  41. }
  42. if name != "ROW_NUMBER" {
  43. return nil, fmt.Errorf("unsupported window function: %s", name)
  44. }
  45. partitions := map[string][]int{}
  46. var order []string
  47. for i, row := range rows {
  48. key, err := e.windowPartitionKey(we, row)
  49. if err != nil {
  50. return nil, err
  51. }
  52. if _, ok := partitions[key]; !ok {
  53. order = append(order, key)
  54. }
  55. partitions[key] = append(partitions[key], i)
  56. }
  57. values := make([]interface{}, len(rows))
  58. for _, key := range order {
  59. partition := make([]windowRow, 0, len(partitions[key]))
  60. for _, idx := range partitions[key] {
  61. wr := windowRow{idx: idx}
  62. if len(we.OrderBy) > 0 {
  63. wr.key = make([]interface{}, len(we.OrderBy))
  64. for k, item := range we.OrderBy {
  65. wr.key[k], _ = e.evalExpr(item.Expr, rows[idx])
  66. }
  67. }
  68. partition = append(partition, wr)
  69. }
  70. if len(we.OrderBy) > 0 {
  71. sort.SliceStable(partition, func(a, b int) bool {
  72. return orderByLess(partition[a].key, partition[b].key, we.OrderBy)
  73. })
  74. }
  75. for rank, wr := range partition {
  76. values[wr.idx] = int64(rank + 1)
  77. }
  78. }
  79. return values, nil
  80. }
  81. func (e *Executor) windowPartitionKey(we *parser.WindowExpr, row storage.Row) (string, error) {
  82. if len(we.PartitionBy) == 0 {
  83. return "", nil
  84. }
  85. var b strings.Builder
  86. for _, p := range we.PartitionBy {
  87. v, err := e.evalExpr(p, row)
  88. if err != nil {
  89. return "", err
  90. }
  91. fmt.Fprintf(&b, "%v\x00", v)
  92. }
  93. return b.String(), nil
  94. }