diff --git a/embedded/document/engine.go b/embedded/document/engine.go index 553a5b9b4b..2f752353ed 100644 --- a/embedded/document/engine.go +++ b/embedded/document/engine.go @@ -1408,9 +1408,9 @@ func (e *Engine) CopyCatalogToTx(ctx context.Context, tx *store.OngoingTx) error return e.sqlEngine.CopyCatalogToTx(ctx, tx) } -func generateSQLOrderByClauses(table *sql.Table, orderBy []*protomodel.OrderByClause) (ordCols []*sql.OrdCol) { +func generateSQLOrderByClauses(table *sql.Table, orderBy []*protomodel.OrderByClause) (ordExps []*sql.OrdExp) { for _, col := range orderBy { - ordCols = append(ordCols, sql.NewOrdCol(table.Name(), col.Field, col.Desc)) + ordExps = append(ordExps, sql.NewOrdCol(table.Name(), col.Field, col.Desc)) } - return ordCols + return ordExps } diff --git a/embedded/sql/catalog.go b/embedded/sql/catalog.go index f9c3d91210..e936ced650 100644 --- a/embedded/sql/catalog.go +++ b/embedded/sql/catalog.go @@ -266,34 +266,39 @@ func (i *Index) enginePrefix() []byte { return i.table.catalog.enginePrefix } -func (i *Index) coversOrdCols(ordCols []*OrdCol, rangesByColID map[uint32]*typedValueRange) bool { - if !ordColumnsHaveSameDirection(ordCols) { +func (i *Index) coversOrdCols(ordExps []*OrdExp, rangesByColID map[uint32]*typedValueRange) bool { + if !ordExpsHaveSameDirection(ordExps) { return false } - return i.hasPrefix(i.cols, ordCols) || i.sortableUsing(ordCols, rangesByColID) + return i.hasPrefix(i.cols, ordExps) || i.sortableUsing(ordExps, rangesByColID) } -func ordColumnsHaveSameDirection(cols []*OrdCol) bool { - if len(cols) == 0 { +func ordExpsHaveSameDirection(exps []*OrdExp) bool { + if len(exps) == 0 { return true } - desc := cols[0].descOrder - for _, ordCol := range cols[1:] { - if ordCol.descOrder != desc { + desc := exps[0].descOrder + for _, e := range exps[1:] { + if e.descOrder != desc { return false } } return true } -func (i *Index) hasPrefix(columns []*Column, ordCols []*OrdCol) bool { - if len(ordCols) > len(columns) { +func (i *Index) hasPrefix(columns []*Column, ordExps []*OrdExp) bool { + if len(ordExps) > len(columns) { return false } - for j, ordCol := range ordCols { - aggFn, _, colName := ordCol.sel.resolve(i.table.Name()) + for j, ordCol := range ordExps { + sel := ordCol.AsSelector() + if sel == nil { + return false + } + + aggFn, _, colName := sel.resolve(i.table.Name()) if len(aggFn) > 0 { return false } @@ -306,9 +311,14 @@ func (i *Index) hasPrefix(columns []*Column, ordCols []*OrdCol) bool { return true } -func (i *Index) sortableUsing(columns []*OrdCol, rangesByColID map[uint32]*typedValueRange) bool { +func (i *Index) sortableUsing(columns []*OrdExp, rangesByColID map[uint32]*typedValueRange) bool { // all columns before colID must be fixedValues otherwise the index can not be used - aggFn, _, colName := columns[0].sel.resolve(i.table.Name()) + sel := columns[0].AsSelector() + if sel == nil { + return false + } + + aggFn, _, colName := sel.resolve(i.table.Name()) if len(aggFn) > 0 { return false } @@ -327,7 +337,6 @@ func (i *Index) sortableUsing(columns []*OrdCol, rangesByColID map[uint32]*typed if ok && colRange.unitary() { continue } - return false } return false diff --git a/embedded/sql/engine_test.go b/embedded/sql/engine_test.go index 4706150262..cfd351c853 100644 --- a/embedded/sql/engine_test.go +++ b/embedded/sql/engine_test.go @@ -3822,19 +3822,19 @@ func TestIndexSelection(t *testing.T) { require.NotNil(t, specs.Index) require.Len(t, specs.Index.cols, len(testCase.expectedIndex)) require.Equal(t, specs.DescOrder, testCase.desc) - require.Len(t, specs.groupBySortColumns, len(testCase.expectedGroupBySortCols)) - require.Len(t, specs.orderBySortCols, len(testCase.expectedOrderBySortCols)) + require.Len(t, specs.groupBySortExps, len(testCase.expectedGroupBySortCols)) + require.Len(t, specs.orderBySortExps, len(testCase.expectedOrderBySortCols)) for i, col := range testCase.expectedIndex { require.Equal(t, col, specs.Index.cols[i].Name()) } for i, col := range testCase.expectedGroupBySortCols { - require.Equal(t, col, EncodeSelector(specs.groupBySortColumns[i].sel.resolve("table1"))) + require.Equal(t, col, EncodeSelector(specs.groupBySortExps[i].AsSelector().resolve("table1"))) } for i, col := range testCase.expectedOrderBySortCols { - require.Equal(t, col, EncodeSelector(specs.orderBySortCols[i].sel.resolve("table1"))) + require.Equal(t, col, EncodeSelector(specs.orderBySortExps[i].AsSelector().resolve("table1"))) } }) } @@ -4435,6 +4435,7 @@ func TestOrderBy(t *testing.T) { title VARCHAR[100], age INTEGER, height FLOAT, + weight FLOAT, created_at TIMESTAMP, PRIMARY KEY id @@ -4458,14 +4459,15 @@ func TestOrderBy(t *testing.T) { "id": id, "title": fmt.Sprintf("title%d", rand.Intn(100)), "age": rand.Intn(100), + "weight": 50 + rand.Float64()*50, "height": rand.Float64() * 200, "created": time.Unix(rand.Int63n(100000), 0).UTC(), } - _, _, err = engine.Exec(context.Background(), nil, "INSERT INTO table1 (id, title, age, height, created_at) VALUES (@id, @title, @age, @height, @created)", params) + _, _, err = engine.Exec(context.Background(), nil, "INSERT INTO table1 (id, title, age, height, weight, created_at) VALUES (@id, @title, @age, @height, @weight, @created)", params) require.NoError(t, err) } - checkDataItegrity := func(t *testing.T, rows []*Row, table string) { + checkDataIntegrity := func(t *testing.T, rows []*Row, table string) { require.Len(t, rows, rowCount) ids := make(map[int64]struct{}) @@ -4476,10 +4478,12 @@ func TestOrderBy(t *testing.T) { title := row.ValuesBySelector[EncodeSelector("", table, "title")].RawValue().(string) age := row.ValuesBySelector[EncodeSelector("", table, "age")].RawValue().(int64) height := row.ValuesBySelector[EncodeSelector("", table, "height")].RawValue().(float64) + weight := row.ValuesBySelector[EncodeSelector("", table, "weight")].RawValue().(float64) created := row.ValuesBySelector[EncodeSelector("", table, "created_at")].RawValue().(time.Time).UTC() require.Equal(t, fmt.Sprintf("title%d", rand.Intn(100)), title) require.Equal(t, int64(rand.Intn(100)), age) + require.Equal(t, 50+rand.Float64()*50, weight) require.Equal(t, rand.Float64()*200, height) require.Equal(t, time.Unix(rand.Int63n(100000), 0).UTC(), created) @@ -4496,33 +4500,47 @@ func TestOrderBy(t *testing.T) { } type test struct { - columns []string - directions []int - expectedIndex []string + exps []string + directions []int + expectedIndex []string + positionalRefs []int } testCases := []test{ { - columns: []string{"age"}, - directions: []int{1}, + exps: []string{"age"}, + directions: []int{1}, + positionalRefs: []int{3}, + }, + { + exps: []string{"created_at"}, + directions: []int{-1}, + positionalRefs: []int{6}, }, { - columns: []string{"created_at"}, - directions: []int{-1}, + exps: []string{"title", "age"}, + directions: []int{-1, 1}, + positionalRefs: []int{2, 3}, }, { - columns: []string{"title", "age"}, - directions: []int{-1, 1}, + exps: []string{"age", "title", "height"}, + directions: []int{1, -1, 1}, + positionalRefs: []int{3, 2, 4}, + }, + { + exps: []string{"weight/(height*height)"}, + directions: []int{1}, }, { - columns: []string{"age", "title", "height"}, - directions: []int{1, -1, 1}, + exps: []string{"height", "weight"}, + directions: []int{1, -1}, + positionalRefs: []int{4, 5}, }, } runTest := func(t *testing.T, test *test, expectedTempFiles int) []*Row { - orderByCols := make([]string, len(test.columns)) - for i, col := range test.columns { + orderByCols := make([]string, len(test.exps)) + for i, col := range test.exps { orderByCols[i] = col + " " + directionToSql(test.directions[i]) } @@ -4534,11 +4552,6 @@ func TestOrderBy(t *testing.T) { require.NoError(t, err) require.Len(t, rows, rowCount) - selectors := make([]string, len(test.columns)) - for i, col := range test.columns { - selectors[i] = EncodeSelector("", "table1", col) - } - specs := reader.ScanSpecs() if test.expectedIndex != nil { @@ -4549,14 +4562,32 @@ func TestOrderBy(t *testing.T) { require.Equal(t, col, specs.Index.cols[i].Name()) } } else { - require.Len(t, specs.orderBySortCols, len(orderByCols)) - for i, col := range specs.orderBySortCols { - require.Equal(t, selectors[i], EncodeSelector(col.sel.resolve("table1"))) + require.Len(t, specs.orderBySortExps, len(orderByCols)) + for i, col := range specs.orderBySortExps { + e, err := ParseExpFromString(test.exps[i]) + require.NoError(t, err) + require.Equal(t, e, col.exp) } } - checkRowsAreSorted(t, rows, selectors, test.directions) - checkDataItegrity(t, rows, "table1") + checkRowsAreSorted(t, rows, test.exps, test.directions, "table1") + checkDataIntegrity(t, rows, "table1") + + if test.positionalRefs != nil { + orderByColPositions := make([]string, len(test.exps)) + for i, ref := range test.positionalRefs { + orderByColPositions[i] = strconv.Itoa(ref) + " " + directionToSql(test.directions[i]) + } + + rows1, err := engine.queryAll( + context.Background(), + nil, + fmt.Sprintf("SELECT * FROM table1 ORDER BY %s", strings.Join(orderByColPositions, ",")), + nil, + ) + require.NoError(t, err) + require.Equal(t, rows, rows1) + } tx := reader.Tx() require.Len(t, tx.tempFiles, expectedTempFiles) @@ -4565,7 +4596,7 @@ func TestOrderBy(t *testing.T) { } for _, test := range testCases { - t.Run(fmt.Sprintf("order by on %s should be executed using in memory sort", strings.Join(test.columns, ",")), func(t *testing.T) { + t.Run(fmt.Sprintf("order by on %s should be executed using in memory sort", strings.Join(test.exps, ",")), func(t *testing.T) { runTest(t, &test, 0) }) } @@ -4573,7 +4604,7 @@ func TestOrderBy(t *testing.T) { engine.sortBufferSize = 4 + rand.Intn(13) // [4, 16] for _, test := range testCases { - t.Run(fmt.Sprintf("order by on %s should be executed using file sort", strings.Join(test.columns, ",")), func(t *testing.T) { + t.Run(fmt.Sprintf("order by on %s should be executed using file sort", strings.Join(test.exps, ",")), func(t *testing.T) { runTest(t, &test, 2) }) } @@ -4587,7 +4618,7 @@ func TestOrderBy(t *testing.T) { require.NoError(t, err) require.Len(t, rows, rowCount) - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "t1", "age")}, []int{-1}) + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "t1", "age")}, []int{-1}, "t1") }) _, _, err = engine.Exec(context.Background(), nil, "CREATE INDEX ON table1(age)", nil) @@ -4601,29 +4632,29 @@ func TestOrderBy(t *testing.T) { testCases = []test{ { - columns: []string{"age"}, + exps: []string{"age"}, directions: []int{1}, expectedIndex: []string{"age"}, }, { - columns: []string{"title"}, + exps: []string{"title"}, directions: []int{-1}, expectedIndex: []string{"title", "age"}, }, { - columns: []string{"title", "age"}, + exps: []string{"title", "age"}, directions: []int{1, 1}, expectedIndex: []string{"title", "age"}, }, { - columns: []string{"age", "title"}, + exps: []string{"age", "title"}, directions: []int{-1, -1, -1}, expectedIndex: []string{"age", "title", "height"}, }, } for _, test := range testCases { - t.Run(fmt.Sprintf("order by on %s should be executed using index", strings.Join(test.columns, ",")), func(t *testing.T) { + t.Run(fmt.Sprintf("order by on %s should be executed using index", strings.Join(test.exps, ",")), func(t *testing.T) { runTest(t, &test, 0) }) } @@ -4640,12 +4671,12 @@ func TestOrderBy(t *testing.T) { require.NoError(t, err) require.Len(t, rows, rowCount) - require.Len(t, specs.orderBySortCols, 2) - require.Equal(t, EncodeSelector(specs.orderBySortCols[0].sel.resolve("table1")), EncodeSelector("", "table1", "title")) - require.Equal(t, EncodeSelector(specs.orderBySortCols[1].sel.resolve("table1")), EncodeSelector("", "table1", "age")) + require.Len(t, specs.orderBySortExps, 2) + require.Equal(t, EncodeSelector(specs.orderBySortExps[0].AsSelector().resolve("table1")), EncodeSelector("", "table1", "title")) + require.Equal(t, EncodeSelector(specs.orderBySortExps[1].AsSelector().resolve("table1")), EncodeSelector("", "table1", "age")) - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "age")}, []int{1, -1}) - checkDataItegrity(t, rows, "table1") + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "age")}, []int{1, -1}, "table1") + checkDataIntegrity(t, rows, "table1") }) t.Run("sorting not required", func(t *testing.T) { @@ -4658,7 +4689,7 @@ func TestOrderBy(t *testing.T) { rows, err := ReadAllRows(context.Background(), reader) require.NoError(t, err) require.Len(t, rows, rowCount) - require.Len(t, specs.orderBySortCols, 0) + require.Len(t, specs.orderBySortExps, 0) require.NotNil(t, specs.Index) require.Len(t, specs.Index.cols, 2) @@ -4666,8 +4697,8 @@ func TestOrderBy(t *testing.T) { require.Equal(t, "title", specs.Index.cols[0].Name()) require.Equal(t, "age", specs.Index.cols[1].Name()) - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "age")}, []int{-1, -1}) - checkDataItegrity(t, rows, "table1") + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "age")}, []int{-1, -1}, "table1") + checkDataIntegrity(t, rows, "table1") }) }) @@ -4685,7 +4716,7 @@ func TestOrderBy(t *testing.T) { } t.Run("order by with null values", func(t *testing.T) { - reader, err := engine.Query(context.Background(), nil, "SELECT id, title, age, height, created_at FROM table1 ORDER BY title, id", nil) + reader, err := engine.Query(context.Background(), nil, "SELECT id, title, age, height, weight, created_at FROM table1 ORDER BY title, id", nil) require.NoError(t, err) defer reader.Close() @@ -4705,8 +4736,8 @@ func TestOrderBy(t *testing.T) { tx := reader.Tx() require.Len(t, tx.tempFiles, 2) - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "id")}, []int{1, 1}) - checkDataItegrity(t, rows[nullValues:], "table1") + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "id")}, []int{1, 1}, "table1") + checkDataIntegrity(t, rows[nullValues:], "table1") }) } @@ -4717,14 +4748,27 @@ func directionToSql(direction int) string { return "DESC" } -func checkRowsAreSorted(t *testing.T, rows []*Row, selectors []string, directions []int) { - k1 := make(Tuple, len(selectors)) - k2 := make(Tuple, len(selectors)) +func checkRowsAreSorted(t *testing.T, rows []*Row, expStrings []string, directions []int, table string) { + exps := make([]ValueExp, len(expStrings)) + for i, s := range expStrings { + e, err := ParseExpFromString(s) + require.NoError(t, err) + exps[i] = e + } + + k1 := make(Tuple, len(exps)) + k2 := make(Tuple, len(exps)) isSorted := sort.SliceIsSorted(rows, func(i, j int) bool { - for idx, sel := range selectors { - k1[idx] = rows[i].ValuesBySelector[sel] - k2[idx] = rows[j].ValuesBySelector[sel] + for idx, e := range exps { + v1, err := e.reduce(nil, rows[i], table) + require.NoError(t, err) + + v2, err := e.reduce(nil, rows[j], table) + require.NoError(t, err) + + k1[idx] = v1 + k2[idx] = v2 } res, idx, err := Tuple(k1).Compare(k2) @@ -5410,7 +5454,7 @@ func TestGroupBy(t *testing.T) { for _, row := range rows { require.Equal(t, row.ValuesByPosition[0].RawValue().(int64), int64(1)) } - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "age"), EncodeSelector("", "table1", "id")}, []int{-1, 1, 1}) + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "title"), EncodeSelector("", "table1", "age"), EncodeSelector("", "table1", "id")}, []int{-1, 1, 1}, "table1") }) t.Run("index covers group by but not order by", func(t *testing.T) { @@ -5432,7 +5476,7 @@ func TestGroupBy(t *testing.T) { for _, row := range rows { require.Equal(t, row.ValuesByPosition[0].RawValue().(int64), int64(1)) } - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "age")}, []int{-1}) + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "age")}, []int{-1}, "table1") }) t.Run("preferred index doesn't cover group by and order by", func(t *testing.T) { @@ -5442,8 +5486,8 @@ func TestGroupBy(t *testing.T) { specs := reader.ScanSpecs() require.NotNil(t, specs.Index) - require.Len(t, specs.groupBySortColumns, 2) - require.Len(t, specs.orderBySortCols, 1) + require.Len(t, specs.groupBySortExps, 2) + require.Len(t, specs.orderBySortExps, 1) require.Len(t, specs.Index.cols, 1) require.Equal(t, specs.Index.cols[0].Name(), "age") @@ -5454,7 +5498,7 @@ func TestGroupBy(t *testing.T) { for _, row := range rows { require.Equal(t, row.ValuesByPosition[0].RawValue().(int64), int64(1)) } - checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "age")}, []int{-1}) + checkRowsAreSorted(t, rows, []string{EncodeSelector("", "table1", "age")}, []int{-1}, "table1") }) t.Run("index covers group by and order by because of unitary filter", func(t *testing.T) { @@ -5464,8 +5508,8 @@ func TestGroupBy(t *testing.T) { specs := reader.ScanSpecs() require.NotNil(t, specs.Index) - require.Len(t, specs.groupBySortColumns, 0) - require.Len(t, specs.orderBySortCols, 0) + require.Len(t, specs.groupBySortExps, 0) + require.Len(t, specs.orderBySortExps, 0) require.Len(t, specs.Index.cols, 2) require.Equal(t, specs.Index.cols[0].Name(), "title") diff --git a/embedded/sql/parser_test.go b/embedded/sql/parser_test.go index 953b0c0e2c..56c3ca0d9a 100644 --- a/embedded/sql/parser_test.go +++ b/embedded/sql/parser_test.go @@ -1049,9 +1049,9 @@ func TestSelectStmt(t *testing.T) { {Exp: &ColSelector{col: "year"}}, }, ds: &tableRef{table: "table1"}, - orderBy: []*OrdCol{ - {sel: &ColSelector{col: "title"}}, - {sel: &ColSelector{col: "year"}, descOrder: true}, + orderBy: []*OrdExp{ + {exp: &ColSelector{col: "title"}}, + {exp: &ColSelector{col: "year"}, descOrder: true}, }, }}, expectedError: nil, @@ -1089,8 +1089,8 @@ func TestSelectStmt(t *testing.T) { left: &ColSelector{col: "name"}, right: &Varchar{val: "John"}, }, - orderBy: []*OrdCol{ - {sel: &ColSelector{col: "name"}, descOrder: true}, + orderBy: []*OrdExp{ + {exp: &ColSelector{col: "name"}, descOrder: true}, }, }}, expectedError: nil, @@ -1128,8 +1128,8 @@ func TestSelectStmt(t *testing.T) { left: &ColSelector{col: "name"}, right: &Varchar{val: "John"}, }, - orderBy: []*OrdCol{ - {sel: &ColSelector{col: "name"}, descOrder: true}, + orderBy: []*OrdExp{ + {exp: &ColSelector{col: "name"}, descOrder: true}, }, }}, expectedError: nil, @@ -1167,8 +1167,8 @@ func TestSelectStmt(t *testing.T) { left: &ColSelector{col: "name"}, right: &Varchar{val: "John"}, }, - orderBy: []*OrdCol{ - {sel: &ColSelector{col: "name"}, descOrder: true}, + orderBy: []*OrdExp{ + {exp: &ColSelector{col: "name"}, descOrder: true}, }, }}, expectedError: nil, diff --git a/embedded/sql/row_reader.go b/embedded/sql/row_reader.go index 46e122481c..25f7dea0b0 100644 --- a/embedded/sql/row_reader.go +++ b/embedded/sql/row_reader.go @@ -42,13 +42,13 @@ type RowReader interface { } type ScanSpecs struct { - Index *Index - rangesByColID map[uint32]*typedValueRange - IncludeHistory bool - IncludeTxMetadata bool - DescOrder bool - groupBySortColumns []*OrdCol - orderBySortCols []*OrdCol + Index *Index + rangesByColID map[uint32]*typedValueRange + IncludeHistory bool + IncludeTxMetadata bool + DescOrder bool + groupBySortExps []*OrdExp + orderBySortExps []*OrdExp } func (s *ScanSpecs) extraCols() int { diff --git a/embedded/sql/sort_reader.go b/embedded/sql/sort_reader.go index 23ea509128..3957bb13c8 100644 --- a/embedded/sql/sort_reader.go +++ b/embedded/sql/sort_reader.go @@ -18,6 +18,7 @@ package sql import ( "context" + "fmt" ) type sortDirection int8 @@ -29,15 +30,15 @@ const ( type sortRowReader struct { rowReader RowReader - ordCols []*OrdCol + ordExps []*OrdExp orderByDescriptors []ColDescriptor sorter fileSorter resultReader resultReader } -func newSortRowReader(rowReader RowReader, ordCols []*OrdCol) (*sortRowReader, error) { - if rowReader == nil || len(ordCols) == 0 { +func newSortRowReader(rowReader RowReader, ordExps []*OrdExp) (*sortRowReader, error) { + if rowReader == nil || len(ordExps) == 0 { return nil, ErrIllegalArguments } @@ -46,6 +47,13 @@ func newSortRowReader(rowReader RowReader, ordCols []*OrdCol) (*sortRowReader, e return nil, err } + for _, col := range ordExps { + colPos, isColRef := col.exp.(*Integer) + if isColRef && (colPos.val <= 0 || colPos.val > int64(len(descriptors))) { + return nil, fmt.Errorf("position %d is not in select list", colPos.val) + } + } + colPosBySelector, err := getColPositionsBySelector(descriptors) if err != nil { return nil, err @@ -56,7 +64,7 @@ func newSortRowReader(rowReader RowReader, ordCols []*OrdCol) (*sortRowReader, e return nil, err } - orderByDescriptors, err := getOrderByDescriptors(ordCols, rowReader) + orderByDescriptors, err := getOrderByDescriptors(ordExps, rowReader) if err != nil { return nil, err } @@ -64,7 +72,7 @@ func newSortRowReader(rowReader RowReader, ordCols []*OrdCol) (*sortRowReader, e tx := rowReader.Tx() sr := &sortRowReader{ rowReader: rowReader, - ordCols: ordCols, + ordExps: ordExps, orderByDescriptors: orderByDescriptors, sorter: fileSorter{ colPosBySelector: colPosBySelector, @@ -75,23 +83,23 @@ func newSortRowReader(rowReader RowReader, ordCols []*OrdCol) (*sortRowReader, e }, } - directions := make([]sortDirection, len(ordCols)) - for i, col := range ordCols { + directions := make([]sortDirection, len(ordExps)) + for i, col := range ordExps { directions[i] = sortDirectionAsc if col.descOrder { directions[i] = sortDirectionDesc } } - t1 := make(Tuple, len(ordCols)) - t2 := make(Tuple, len(ordCols)) + t1 := make(Tuple, len(ordExps)) + t2 := make(Tuple, len(ordExps)) sr.sorter.cmp = func(r1, r2 *Row) (int, error) { - if err := sr.evalSortSelectors(r1, t1); err != nil { + if err := sr.evalSortExps(r1, t1); err != nil { return 0, err } - if err := sr.evalSortSelectors(r2, t2); err != nil { + if err := sr.evalSortExps(r2, t2); err != nil { return 0, err } @@ -108,37 +116,52 @@ func newSortRowReader(rowReader RowReader, ordCols []*OrdCol) (*sortRowReader, e return sr, nil } -func (s *sortRowReader) evalSortSelectors(inRow *Row, out Tuple) error { - for i, col := range s.ordCols { - val, err := col.sel.reduce(s.Tx(), inRow, s.TableAlias()) - if err != nil { - return err +func (s *sortRowReader) evalSortExps(inRow *Row, out Tuple) error { + for i, col := range s.ordExps { + colPos, isColRef := col.exp.(*Integer) + if isColRef { + if colPos.val < 1 || colPos.val > int64(len(inRow.ValuesByPosition)) { + return fmt.Errorf("position %d is not in select list", colPos.val) + } + out[i] = inRow.ValuesByPosition[colPos.val-1] + } else { + val, err := col.exp.reduce(s.Tx(), inRow, s.TableAlias()) + if err != nil { + return err + } + out[i] = val } - out[i] = val } return nil } -func getOrderByDescriptors(ordCols []*OrdCol, rowReader RowReader) ([]ColDescriptor, error) { +func getOrderByDescriptors(ordExps []*OrdExp, rowReader RowReader) ([]ColDescriptor, error) { colsBySel, err := rowReader.colsBySelector(context.Background()) if err != nil { return nil, err } params := make(map[string]string) - orderByDescriptors := make([]ColDescriptor, len(ordCols)) - for i, col := range ordCols { - sqlType, err := col.sel.inferType(colsBySel, params, rowReader.TableAlias()) + orderByDescriptors := make([]ColDescriptor, len(ordExps)) + for i, col := range ordExps { + sqlType, err := col.exp.inferType(colsBySel, params, rowReader.TableAlias()) if err != nil { return nil, err } - aggFn, table, col := col.sel.resolve(rowReader.TableAlias()) - orderByDescriptors[i] = ColDescriptor{ - AggFn: aggFn, - Table: table, - Column: col, - Type: sqlType, + if sel := col.AsSelector(); sel != nil { + aggFn, table, col := sel.resolve(rowReader.TableAlias()) + orderByDescriptors[i] = ColDescriptor{ + AggFn: aggFn, + Table: table, + Column: col, + Type: sqlType, + } + } else { + orderByDescriptors[i] = ColDescriptor{ + Column: col.exp.String(), + Type: sqlType, + } } } return orderByDescriptors, nil diff --git a/embedded/sql/sort_reader_test.go b/embedded/sql/sort_reader_test.go index 0f2c26ae18..173ba95899 100644 --- a/embedded/sql/sort_reader_test.go +++ b/embedded/sql/sort_reader_test.go @@ -50,7 +50,7 @@ func TestSortRowReader(t *testing.T) { r, err := newRawRowReader(tx, nil, table, period{}, "", &ScanSpecs{Index: table.primaryIndex}) require.NoError(t, err) - sr, err := newSortRowReader(r, []*OrdCol{{sel: &ColSelector{col: "number"}}}) + sr, err := newSortRowReader(r, []*OrdExp{{exp: &ColSelector{col: "number"}}}) require.NoError(t, err) orderBy := sr.OrderBy() diff --git a/embedded/sql/sql_grammar.y b/embedded/sql/sql_grammar.y index 115e350ff8..18019ada07 100644 --- a/embedded/sql/sql_grammar.y +++ b/embedded/sql/sql_grammar.y @@ -61,7 +61,7 @@ func setResult(l yyLexer, stmts []SQLStmt) { exp ValueExp binExp ValueExp err error - ordcols []*OrdCol + ordexps []*OrdExp opt_ord bool logicOp LogicOperator cmpOp CmpOperator @@ -143,7 +143,7 @@ func setResult(l yyLexer, stmts []SQLStmt) { %type opt_targets targets %type opt_max_len %type opt_as -%type ordcols opt_orderby +%type ordexps opt_orderby %type opt_ord %type opt_indexon %type opt_if_not_exists opt_auto_increment opt_not_null opt_not @@ -986,7 +986,7 @@ opt_orderby: $$ = nil } | - ORDER BY ordcols + ORDER BY ordexps { $$ = $3 } @@ -1001,15 +1001,15 @@ opt_indexon: $$ = $4 } -ordcols: - selector opt_ord +ordexps: + exp opt_ord { - $$ = []*OrdCol{{sel: $1, descOrder: $2}} + $$ = []*OrdExp{{exp: $1, descOrder: $2}} } | - ordcols ',' selector opt_ord + ordexps ',' exp opt_ord { - $$ = append($1, &OrdCol{sel: $3, descOrder: $4}) + $$ = append($1, &OrdExp{exp: $3, descOrder: $4}) } opt_ord: @@ -1086,7 +1086,13 @@ exp: | '-' exp { - $$ = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: $2} + i, isInt := $2.(*Integer) + if isInt { + i.val = -i.val + $$ = i + } else { + $$ = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: $2} + } } | boundexp opt_not LIKE exp diff --git a/embedded/sql/sql_parser.go b/embedded/sql/sql_parser.go index 33b1b4bd62..577d737da6 100644 --- a/embedded/sql/sql_parser.go +++ b/embedded/sql/sql_parser.go @@ -47,7 +47,7 @@ type yySymType struct { exp ValueExp binExp ValueExp err error - ordcols []*OrdCol + ordexps []*OrdExp opt_ord bool logicOp LogicOperator cmpOp CmpOperator @@ -311,125 +311,125 @@ var yyExca = [...]int16{ const yyPrivate = 57344 -const yyLast = 583 +const yyLast = 589 var yyAct = [...]int16{ - 131, 428, 103, 107, 310, 153, 262, 335, 201, 353, - 115, 207, 350, 240, 245, 241, 316, 305, 71, 144, - 198, 296, 395, 147, 22, 260, 341, 6, 340, 260, - 291, 416, 130, 260, 400, 260, 399, 396, 379, 367, - 106, 129, 342, 387, 300, 99, 161, 260, 101, 370, - 366, 364, 118, 114, 326, 21, 261, 324, 323, 116, - 117, 354, 96, 321, 119, 290, 109, 110, 111, 112, - 113, 108, 154, 155, 157, 156, 158, 100, 288, 287, - 355, 178, 281, 105, 106, 259, 351, 295, 280, 99, - 161, 177, 101, 177, 275, 274, 118, 114, 273, 272, + 131, 428, 310, 107, 335, 153, 262, 353, 350, 201, + 115, 207, 240, 316, 245, 241, 305, 296, 144, 147, + 198, 71, 395, 22, 341, 260, 340, 6, 260, 291, + 416, 260, 130, 260, 400, 399, 396, 379, 367, 106, + 342, 129, 300, 387, 99, 161, 260, 101, 370, 366, + 364, 118, 114, 212, 21, 261, 326, 324, 116, 117, + 354, 323, 96, 119, 321, 109, 110, 111, 112, 113, + 108, 154, 155, 157, 156, 158, 100, 290, 288, 355, + 178, 287, 105, 351, 106, 281, 259, 295, 280, 99, + 177, 177, 101, 275, 274, 161, 118, 114, 273, 272, 167, 168, 247, 116, 117, 187, 170, 172, 119, 163, - 109, 110, 111, 112, 113, 108, 132, 149, 157, 156, - 158, 100, 161, 238, 180, 176, 175, 105, 169, 143, - 142, 186, 24, 427, 159, 160, 162, 236, 145, 420, - 381, 292, 291, 260, 212, 152, 203, 234, 154, 155, - 157, 156, 158, 216, 83, 217, 218, 219, 220, 221, - 222, 223, 214, 106, 200, 174, 204, 178, 99, 184, - 185, 101, 134, 286, 238, 118, 114, 239, 242, 237, - 256, 108, 116, 117, 205, 249, 235, 119, 378, 109, - 110, 111, 112, 113, 108, 377, 163, 230, 333, 338, - 100, 94, 337, 293, 251, 32, 105, 267, 250, 210, - 211, 213, 33, 265, 229, 238, 268, 215, 161, 199, - 276, 76, 277, 162, 373, 361, 346, 269, 279, 266, - 106, 160, 319, 345, 285, 99, 209, 270, 101, 344, - 325, 308, 118, 114, 154, 155, 157, 156, 158, 116, - 117, 148, 255, 254, 119, 253, 109, 110, 111, 112, - 113, 108, 252, 246, 312, 246, 248, 100, 294, 243, - 226, 196, 314, 105, 195, 320, 188, 181, 302, 309, - 150, 242, 133, 122, 330, 331, 120, 307, 91, 307, - 54, 77, 334, 80, 31, 79, 328, 78, 75, 70, - 69, 206, 166, 376, 394, 271, 306, 336, 327, 161, - 375, 165, 352, 161, 22, 225, 343, 22, 278, 356, - 39, 227, 224, 393, 228, 159, 160, 360, 179, 362, - 363, 65, 365, 369, 358, 357, 49, 121, 372, 154, - 155, 157, 156, 158, 58, 21, 22, 231, 21, 329, - 233, 55, 242, 283, 161, 284, 90, 411, 311, 60, - 161, 429, 430, 263, 419, 382, 159, 160, 403, 388, - 214, 386, 159, 160, 385, 145, 383, 21, 402, 417, - 154, 155, 157, 156, 158, 390, 154, 155, 157, 156, - 158, 151, 408, 405, 398, 404, 359, 52, 407, 406, - 368, 62, 409, 412, 140, 397, 332, 414, 161, 56, - 57, 59, 380, 88, 161, 51, 421, 418, 50, 25, - 159, 160, 425, 423, 426, 422, 159, 160, 82, 92, - 431, 391, 289, 432, 154, 155, 157, 156, 158, 161, - 154, 155, 157, 156, 158, 161, 389, 10, 12, 11, - 338, 159, 160, 337, 64, 43, 47, 159, 160, 371, - 189, 208, 192, 193, 301, 154, 155, 157, 156, 158, - 13, 154, 155, 157, 156, 158, 190, 191, 48, 14, - 15, 53, 66, 67, 7, 137, 8, 9, 16, 17, - 258, 257, 18, 19, 415, 348, 44, 313, 182, 22, - 46, 45, 26, 30, 123, 84, 264, 42, 135, 136, - 36, 81, 85, 86, 87, 68, 2, 38, 27, 29, - 28, 322, 40, 124, 194, 34, 183, 35, 128, 127, - 21, 138, 37, 73, 74, 297, 298, 299, 125, 304, - 303, 63, 141, 139, 202, 23, 232, 41, 347, 146, - 164, 374, 392, 410, 424, 339, 95, 93, 102, 384, - 98, 282, 97, 401, 171, 318, 317, 315, 126, 72, - 89, 61, 173, 104, 349, 413, 197, 244, 20, 5, - 4, 3, 1, + 109, 110, 111, 112, 113, 108, 132, 149, 210, 211, + 213, 100, 161, 157, 156, 158, 215, 105, 238, 180, + 176, 186, 175, 169, 159, 160, 162, 143, 142, 24, + 145, 427, 236, 420, 381, 209, 203, 234, 154, 155, + 157, 156, 158, 216, 292, 217, 218, 219, 220, 221, + 222, 223, 214, 106, 200, 204, 291, 260, 99, 184, + 185, 101, 152, 83, 174, 118, 114, 239, 242, 237, + 178, 134, 116, 117, 286, 256, 205, 119, 249, 109, + 110, 111, 112, 113, 108, 235, 378, 230, 377, 338, + 100, 94, 337, 333, 251, 32, 105, 267, 250, 163, + 293, 229, 33, 76, 265, 238, 199, 268, 373, 106, + 276, 361, 277, 346, 99, 266, 345, 101, 279, 344, + 269, 118, 114, 325, 285, 308, 162, 270, 116, 117, + 148, 255, 254, 119, 253, 109, 110, 111, 112, 113, + 108, 252, 246, 248, 243, 226, 100, 196, 195, 188, + 181, 150, 105, 246, 312, 133, 122, 120, 294, 91, + 54, 80, 314, 161, 302, 320, 79, 78, 309, 75, + 70, 242, 69, 77, 330, 331, 160, 307, 206, 307, + 319, 376, 334, 161, 31, 58, 328, 394, 375, 154, + 155, 157, 156, 158, 22, 159, 160, 336, 327, 278, + 60, 393, 352, 161, 271, 166, 343, 356, 417, 154, + 155, 157, 156, 158, 165, 159, 160, 360, 306, 362, + 363, 358, 365, 369, 357, 21, 22, 225, 372, 154, + 155, 157, 156, 158, 224, 161, 227, 231, 65, 228, + 179, 121, 242, 161, 329, 22, 233, 429, 430, 90, + 56, 57, 59, 55, 382, 159, 160, 21, 411, 388, + 214, 386, 161, 283, 311, 284, 383, 263, 390, 154, + 155, 157, 156, 158, 159, 160, 21, 419, 39, 403, + 398, 385, 408, 405, 145, 407, 404, 406, 154, 155, + 157, 156, 158, 412, 49, 368, 402, 414, 359, 151, + 332, 52, 62, 161, 409, 397, 421, 418, 161, 88, + 425, 423, 422, 380, 426, 159, 160, 51, 431, 50, + 159, 160, 208, 432, 25, 82, 289, 92, 161, 154, + 155, 157, 156, 158, 154, 155, 157, 156, 158, 161, + 159, 160, 53, 64, 391, 389, 371, 10, 12, 11, + 338, 159, 160, 337, 154, 155, 157, 156, 158, 43, + 47, 189, 140, 192, 193, 154, 155, 157, 156, 158, + 13, 66, 67, 85, 86, 87, 190, 191, 137, 14, + 15, 301, 48, 258, 7, 415, 8, 9, 16, 17, + 257, 36, 18, 19, 348, 313, 182, 26, 30, 22, + 44, 135, 136, 123, 46, 45, 34, 84, 35, 2, + 81, 42, 124, 27, 29, 28, 264, 68, 38, 322, + 128, 127, 73, 74, 194, 183, 40, 297, 298, 299, + 21, 138, 125, 37, 63, 304, 303, 141, 139, 202, + 23, 232, 41, 347, 146, 164, 374, 392, 410, 424, + 339, 95, 93, 102, 384, 98, 282, 97, 401, 171, + 318, 317, 315, 126, 72, 89, 61, 173, 103, 104, + 349, 413, 197, 244, 20, 5, 4, 3, 1, } var yyPact = [...]int16{ - 443, -1000, -1000, 18, -1000, -1000, -1000, 377, -1000, -1000, - 495, 198, 502, 509, 451, 451, 371, 368, 339, 194, - 281, 321, 344, -1000, 443, -1000, 252, 252, 252, 490, - 204, -1000, 203, 517, 202, 195, 201, 199, 197, 485, - 388, 47, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 479, - 194, 194, 194, 362, -1000, 285, -1000, -1000, 192, -1000, - 390, 91, -1000, -1000, 190, 260, 187, 478, 252, 529, - -1000, -1000, 510, 12, 12, -1000, 186, 67, -1000, 480, - 522, 536, -1000, 451, 535, 15, 14, 314, 155, 261, - -1000, -1000, 184, 333, -1000, 38, 40, 225, -1000, 158, - 158, 13, -1000, -1000, -1000, 158, 158, 59, 11, -1000, - -1000, -1000, -1000, -1000, 10, -1000, -1000, -1000, -1000, -24, - -1000, 248, 9, 181, 472, 516, -1000, 12, 12, -1000, - 158, 357, -1000, -10, 180, 429, 446, 431, 514, 178, - -1000, 175, 123, 123, 538, 158, 77, -1000, 206, -1000, - -1000, 121, 158, -1000, 158, 158, 158, 158, 158, 158, - 158, 238, -1000, 174, 243, 117, -1000, 136, 8, 261, - 231, 277, 357, 41, 86, 27, 158, 158, 173, -1000, - 169, -13, 170, 85, -1000, -1000, 357, 123, -1000, 169, - 166, 159, 157, 156, 80, 461, 460, -31, 36, -1000, - -60, 299, 481, 357, 538, 155, 158, 538, 517, 290, - -16, -17, -20, -21, 127, -22, 40, 8, 8, 227, - 227, 227, 136, -36, -1000, 234, -1000, 158, -27, -1000, - -34, -1000, 280, 158, 73, -1000, -37, -38, 62, 363, - -51, 35, 357, -1000, 34, -1000, 106, 123, -28, 524, - -72, -1000, -1000, 434, -1000, -1000, 524, 532, 531, 258, - 145, 258, 293, 158, 471, 299, -1000, 357, 139, 127, - -53, 500, -58, -59, 144, -62, -1000, -1000, -1000, 136, - -32, -1000, 273, 158, 158, 332, -1000, -1000, -1000, 101, - -1000, 158, 167, -89, -74, 123, -1000, -1000, -1000, -1000, - -1000, 143, -1000, 137, 130, 469, -29, -1000, -1000, -1000, - -1000, 158, 357, -35, 293, 314, -1000, 139, 337, -1000, - -1000, 127, 129, 127, 127, -65, 127, -66, -77, -1000, - 326, 357, 158, -67, 357, 426, -1000, 158, 128, 226, - 97, 90, -1000, -78, -1000, -1000, -1000, -1000, 360, 33, - -1000, 158, 357, -1000, -1000, 123, -1000, 312, -1000, 121, - -1000, -73, -1000, -1000, -1000, -1000, -1000, -1000, 158, 357, - -1000, 412, 278, 396, 240, -1000, 220, -96, -79, -1000, - 352, -29, -80, -82, 318, 305, 538, 127, 357, -35, - 418, 158, -1000, -1000, -1000, -1000, -1000, 348, -1000, -1000, - -1000, 291, 158, 119, 468, -1000, -85, -1000, 272, -1000, - 299, 301, 357, 32, -1000, 158, -1000, 418, 293, 78, - 119, 357, -1000, -1000, 26, 294, -1000, 78, -1000, -1000, - -1000, 294, -1000, + 453, -1000, -1000, 25, -1000, -1000, -1000, 392, -1000, -1000, + 500, 198, 493, 520, 465, 465, 382, 380, 353, 174, + 293, 272, 355, -1000, 453, -1000, 269, 269, 269, 502, + 186, -1000, 184, 516, 183, 187, 181, 180, 175, 494, + 395, 66, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 491, + 174, 174, 174, 368, -1000, 288, -1000, -1000, 173, -1000, + 398, 91, -1000, -1000, 171, 274, 170, 487, 269, 533, + -1000, -1000, 512, 12, 12, -1000, 169, 76, -1000, 483, + 532, 541, -1000, 465, 540, 23, 22, 333, 144, 248, + -1000, -1000, 165, 351, -1000, 65, 40, 238, -1000, 147, + 147, 18, -1000, -1000, -1000, 147, 147, 68, 17, -1000, + -1000, -1000, -1000, -1000, 15, -1000, -1000, -1000, -1000, -25, + -1000, 270, 14, 164, 480, 525, -1000, 12, 12, -1000, + 147, 356, -1000, -10, 163, 440, 456, 442, 524, 162, + -1000, 161, 120, 120, 543, 147, 79, -1000, 193, -1000, + -1000, 30, 147, -1000, 147, 147, 147, 147, 147, 147, + 147, 260, -1000, 159, 268, 114, -1000, 191, 13, 248, + 231, 283, 356, 41, 95, 32, 147, 147, 158, -1000, + 156, -13, 157, 88, -1000, -1000, 356, 120, -1000, 156, + 155, 148, 146, 145, 85, 470, 463, -30, 60, -1000, + -61, 313, 501, 356, 543, 144, 147, 543, 516, 299, + -16, -17, -21, -22, 140, -24, 40, 13, 13, 263, + 263, 263, 191, -37, -1000, 225, -1000, 147, -27, -1000, + -31, -1000, 300, 147, 84, -1000, -35, -38, 75, 367, + -39, 59, 356, -1000, 47, -1000, 113, 120, -28, 526, + -74, -1000, -1000, 461, -1000, -1000, 526, 538, 537, 280, + 139, 280, 309, 147, 479, 313, -1000, 356, 197, 140, + -52, 508, -55, -59, 137, -60, -1000, -1000, -1000, 191, + -33, -1000, 278, 147, 147, 336, -1000, -1000, -1000, 106, + -1000, 147, 167, -91, -76, 120, -1000, -1000, -1000, -1000, + -1000, 133, -1000, 130, 127, 478, -32, -1000, -1000, -1000, + -1000, 147, 356, -36, 309, 333, -1000, 197, 349, -1000, + -1000, 140, 125, 140, 140, -66, 140, -67, -78, -1000, + 331, 356, 147, -68, 356, 423, -1000, 147, 122, 214, + 100, 98, -1000, -79, -1000, -1000, -1000, -1000, 371, 37, + -1000, 147, 356, -1000, -1000, 120, -1000, 329, -1000, 30, + -1000, -73, -1000, -1000, -1000, -1000, -1000, -1000, 147, 356, + -1000, 421, 271, 419, 228, -1000, 213, -96, -80, -1000, + 362, -32, -81, -82, 346, 326, 543, 140, 356, -36, + 428, 147, -1000, -1000, -1000, -1000, -1000, 360, -1000, -1000, + -1000, 302, 147, 119, 469, -1000, -86, -1000, 211, -1000, + 313, 324, 356, 36, -1000, 147, -1000, 428, 309, 147, + 119, 356, -1000, -1000, 34, 290, -1000, 147, -1000, -1000, + -1000, 290, -1000, } var yyPgo = [...]int16{ - 0, 582, 516, 581, 580, 579, 27, 578, 577, 14, - 20, 9, 576, 575, 574, 12, 15, 13, 573, 10, - 2, 572, 3, 571, 570, 11, 17, 461, 18, 569, - 568, 41, 567, 16, 566, 565, 7, 0, 564, 19, - 563, 562, 561, 560, 559, 6, 4, 558, 557, 556, - 555, 5, 554, 553, 1, 8, 454, 552, 551, 550, - 23, 549, 548, 21, 547, 320, 546, 545, + 0, 588, 519, 587, 586, 585, 27, 584, 583, 14, + 20, 7, 582, 581, 580, 8, 15, 12, 579, 10, + 578, 577, 3, 576, 575, 11, 16, 432, 21, 574, + 573, 41, 572, 13, 571, 570, 4, 0, 569, 18, + 568, 567, 566, 565, 564, 6, 2, 563, 562, 561, + 560, 5, 559, 558, 1, 9, 453, 557, 556, 555, + 19, 554, 553, 17, 552, 388, 551, 550, } var yyR1 = [...]int8{ @@ -523,8 +523,8 @@ var yyChk = [...]int16{ 107, 35, -57, 83, 84, 118, 116, 53, -15, 116, 116, -40, 60, 63, -55, -51, -11, -36, -37, 54, -53, 66, -37, -13, -22, 26, 116, 107, -45, 63, - 107, -37, -36, -46, -52, -20, -22, 107, -54, 67, - 68, -20, -54, + 107, -37, -36, -46, -52, -37, -22, 107, -54, 67, + 68, -37, -54, } var yyDef = [...]int16{ @@ -1468,7 +1468,7 @@ yydefault: where: yyDollar[8].exp, groupBy: yyDollar[9].cols, having: yyDollar[10].exp, - orderBy: yyDollar[11].ordcols, + orderBy: yyDollar[11].ordexps, limit: yyDollar[12].exp, offset: yyDollar[13].exp, } @@ -1734,12 +1734,12 @@ yydefault: case 157: yyDollar = yyS[yypt-0 : yypt+1] { - yyVAL.ordcols = nil + yyVAL.ordexps = nil } case 158: yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.ordcols = yyDollar[3].ordcols + yyVAL.ordexps = yyDollar[3].ordexps } case 159: yyDollar = yyS[yypt-0 : yypt+1] @@ -1754,12 +1754,12 @@ yydefault: case 161: yyDollar = yyS[yypt-2 : yypt+1] { - yyVAL.ordcols = []*OrdCol{{sel: yyDollar[1].sel, descOrder: yyDollar[2].opt_ord}} + yyVAL.ordexps = []*OrdExp{{exp: yyDollar[1].exp, descOrder: yyDollar[2].opt_ord}} } case 162: yyDollar = yyS[yypt-4 : yypt+1] { - yyVAL.ordcols = append(yyDollar[1].ordcols, &OrdCol{sel: yyDollar[3].sel, descOrder: yyDollar[4].opt_ord}) + yyVAL.ordexps = append(yyDollar[1].ordexps, &OrdExp{exp: yyDollar[3].exp, descOrder: yyDollar[4].opt_ord}) } case 163: yyDollar = yyS[yypt-0 : yypt+1] @@ -1834,7 +1834,13 @@ yydefault: case 177: yyDollar = yyS[yypt-2 : yypt+1] { - yyVAL.exp = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: yyDollar[2].exp} + i, isInt := yyDollar[2].exp.(*Integer) + if isInt { + i.val = -i.val + yyVAL.exp = i + } else { + yyVAL.exp = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: yyDollar[2].exp} + } } case 178: yyDollar = yyS[yypt-4 : yypt+1] diff --git a/embedded/sql/stmt.go b/embedded/sql/stmt.go index b8025637d3..cdb96b9bb2 100644 --- a/embedded/sql/stmt.go +++ b/embedded/sql/stmt.go @@ -1762,12 +1762,12 @@ type DeleteFromStmt struct { tableRef *tableRef where ValueExp indexOn []string - orderBy []*OrdCol + orderBy []*OrdExp limit ValueExp offset ValueExp } -func NewDeleteFromStmt(table string, where ValueExp, orderBy []*OrdCol, limit ValueExp) *DeleteFromStmt { +func NewDeleteFromStmt(table string, where ValueExp, orderBy []*OrdExp, limit ValueExp) *DeleteFromStmt { return &DeleteFromStmt{ tableRef: NewTableRef(table, ""), where: where, @@ -3182,7 +3182,7 @@ type SelectStmt struct { where ValueExp groupBy []*ColSelector having ValueExp - orderBy []*OrdCol + orderBy []*OrdExp limit ValueExp offset ValueExp as string @@ -3192,7 +3192,7 @@ func NewSelectStmt( targets []TargetEntry, ds DataSource, where ValueExp, - orderBy []*OrdCol, + orderBy []*OrdExp, limit ValueExp, offset ValueExp, ) *SelectStmt { @@ -3236,7 +3236,7 @@ func (stmt *SelectStmt) execAt(ctx context.Context, tx *SQLTx, params map[string } if stmt.containsAggregations() || len(stmt.groupBy) > 0 { - for _, sel := range stmt.getSelectors() { + for _, sel := range stmt.targetSelectors() { _, isAgg := sel.(*AggColSelector) if !isAgg && !stmt.groupByContains(sel) { return nil, fmt.Errorf("%s: %w", EncodeSelector(sel.resolve(stmt.Alias())), ErrColumnMustAppearInGroupByOrAggregation) @@ -3246,27 +3246,28 @@ func (stmt *SelectStmt) execAt(ctx context.Context, tx *SQLTx, params map[string if len(stmt.orderBy) > 0 { for _, col := range stmt.orderBy { - sel := col.sel - _, isAgg := sel.(*AggColSelector) - if (isAgg && !stmt.containsSelector(sel)) || (!isAgg && len(stmt.groupBy) > 0 && !stmt.groupByContains(sel)) { - return nil, fmt.Errorf("%s: %w", EncodeSelector(sel.resolve(stmt.Alias())), ErrColumnMustAppearInGroupByOrAggregation) + for _, sel := range col.exp.selectors() { + _, isAgg := sel.(*AggColSelector) + if (isAgg && !stmt.selectorAppearsInTargets(sel)) || (!isAgg && len(stmt.groupBy) > 0 && !stmt.groupByContains(sel)) { + return nil, fmt.Errorf("%s: %w", EncodeSelector(sel.resolve(stmt.Alias())), ErrColumnMustAppearInGroupByOrAggregation) + } } } } return tx, nil } -func (stmt *SelectStmt) getSelectors() []Selector { +func (stmt *SelectStmt) targetSelectors() []Selector { if stmt.selectors == nil { stmt.selectors = stmt.extractSelectors() } return stmt.selectors } -func (stmt *SelectStmt) containsSelector(s Selector) bool { +func (stmt *SelectStmt) selectorAppearsInTargets(s Selector) bool { encSel := EncodeSelector(s.resolve(stmt.Alias())) - for _, sel := range stmt.getSelectors() { + for _, sel := range stmt.targetSelectors() { if EncodeSelector(sel.resolve(stmt.Alias())) == encSel { return true } @@ -3338,9 +3339,9 @@ func (stmt *SelectStmt) Resolve(ctx context.Context, tx *SQLTx, params map[strin } if stmt.containsAggregations() || len(stmt.groupBy) > 0 { - if len(scanSpecs.groupBySortColumns) > 0 { + if len(scanSpecs.groupBySortExps) > 0 { var sortRowReader *sortRowReader - sortRowReader, err = newSortRowReader(rowReader, scanSpecs.groupBySortColumns) + sortRowReader, err = newSortRowReader(rowReader, scanSpecs.groupBySortExps) if err != nil { return nil, err } @@ -3359,7 +3360,7 @@ func (stmt *SelectStmt) Resolve(ctx context.Context, tx *SQLTx, params map[strin } } - if len(scanSpecs.orderBySortCols) > 0 { + if len(scanSpecs.orderBySortExps) > 0 { var sortRowReader *sortRowReader sortRowReader, err = newSortRowReader(rowReader, stmt.orderBy) if err != nil { @@ -3412,48 +3413,55 @@ func (stmt *SelectStmt) Resolve(ctx context.Context, tx *SQLTx, params map[strin return rowReader, nil } -func (stmt *SelectStmt) rearrangeOrdColumns(groupByCols, orderByCols []*OrdCol) ([]*OrdCol, []*OrdCol) { - if len(groupByCols) > 0 && len(orderByCols) > 0 && !ordColumnsHaveAggregations(orderByCols) { - if ordColsHasPrefix(orderByCols, groupByCols, stmt.Alias()) { - return orderByCols, nil +func (stmt *SelectStmt) rearrangeOrdExps(groupByCols, orderByExps []*OrdExp) ([]*OrdExp, []*OrdExp) { + if len(groupByCols) > 0 && len(orderByExps) > 0 && !ordExpsHaveAggregations(orderByExps) { + if ordExpsHasPrefix(orderByExps, groupByCols, stmt.Alias()) { + return orderByExps, nil } - if ordColsHasPrefix(groupByCols, orderByCols, stmt.Alias()) { - for i := range orderByCols { - groupByCols[i].descOrder = orderByCols[i].descOrder + if ordExpsHasPrefix(groupByCols, orderByExps, stmt.Alias()) { + for i := range orderByExps { + groupByCols[i].descOrder = orderByExps[i].descOrder } return groupByCols, nil } } - return groupByCols, orderByCols + return groupByCols, orderByExps } -func ordColsHasPrefix(cols, prefix []*OrdCol, table string) bool { +func ordExpsHasPrefix(cols, prefix []*OrdExp, table string) bool { if len(prefix) > len(cols) { return false } for i := range prefix { - if EncodeSelector(prefix[i].sel.resolve(table)) != EncodeSelector(cols[i].sel.resolve(table)) { + ls := prefix[i].AsSelector() + rs := cols[i].AsSelector() + + if ls == nil || rs == nil { + return false + } + + if EncodeSelector(ls.resolve(table)) != EncodeSelector(rs.resolve(table)) { return false } } return true } -func (stmt *SelectStmt) groupByOrdColumns() []*OrdCol { +func (stmt *SelectStmt) groupByOrdExps() []*OrdExp { groupByCols := stmt.groupBy - ordCols := make([]*OrdCol, 0, len(groupByCols)) + ordExps := make([]*OrdExp, 0, len(groupByCols)) for _, col := range groupByCols { - ordCols = append(ordCols, &OrdCol{sel: col}) + ordExps = append(ordExps, &OrdExp{exp: col}) } - return ordCols + return ordExps } -func ordColumnsHaveAggregations(cols []*OrdCol) bool { - for _, ordCol := range cols { - if _, isAgg := ordCol.sel.(*AggColSelector); isAgg { +func ordExpsHaveAggregations(exps []*OrdExp) bool { + for _, e := range exps { + if _, isAgg := e.exp.(*AggColSelector); isAgg { return true } } @@ -3461,7 +3469,7 @@ func ordColumnsHaveAggregations(cols []*OrdCol) bool { } func (stmt *SelectStmt) containsAggregations() bool { - for _, sel := range stmt.getSelectors() { + for _, sel := range stmt.targetSelectors() { _, isAgg := sel.(*AggColSelector) if isAgg { return true @@ -3507,7 +3515,7 @@ func (stmt *SelectStmt) Alias() string { } func (stmt *SelectStmt) hasTxMetadata() bool { - for _, sel := range stmt.getSelectors() { + for _, sel := range stmt.targetSelectors() { switch s := sel.(type) { case *ColSelector: if s.col == txMetadataCol { @@ -3523,15 +3531,15 @@ func (stmt *SelectStmt) hasTxMetadata() bool { } func (stmt *SelectStmt) genScanSpecs(tx *SQLTx, params map[string]interface{}) (*ScanSpecs, error) { - groupByCols, orderByCols := stmt.groupByOrdColumns(), stmt.orderBy + groupByCols, orderByCols := stmt.groupByOrdExps(), stmt.orderBy tableRef, isTableRef := stmt.ds.(*tableRef) if !isTableRef { - groupByCols, orderByCols = stmt.rearrangeOrdColumns(groupByCols, orderByCols) + groupByCols, orderByCols = stmt.rearrangeOrdExps(groupByCols, orderByCols) return &ScanSpecs{ - groupBySortColumns: groupByCols, - orderBySortCols: orderByCols, + groupBySortExps: groupByCols, + orderBySortExps: orderByCols, }, nil } @@ -3578,20 +3586,20 @@ func (stmt *SelectStmt) genScanSpecs(tx *SQLTx, params map[string]interface{}) ( orderByCols = nil } - groupByCols, orderByCols = stmt.rearrangeOrdColumns(groupByCols, orderByCols) + groupByCols, orderByCols = stmt.rearrangeOrdExps(groupByCols, orderByCols) return &ScanSpecs{ - Index: sortingIndex, - rangesByColID: rangesByColID, - IncludeHistory: tableRef.history, - IncludeTxMetadata: stmt.hasTxMetadata(), - DescOrder: descOrder, - groupBySortColumns: groupByCols, - orderBySortCols: orderByCols, + Index: sortingIndex, + rangesByColID: rangesByColID, + IncludeHistory: tableRef.history, + IncludeTxMetadata: stmt.hasTxMetadata(), + DescOrder: descOrder, + groupBySortExps: groupByCols, + orderBySortExps: orderByCols, }, nil } -func (stmt *SelectStmt) selectSortingIndex(groupByCols, orderByCols []*OrdCol, table *Table, rangesByColId map[uint32]*typedValueRange) *Index { +func (stmt *SelectStmt) selectSortingIndex(groupByCols, orderByCols []*OrdExp, table *Table, rangesByColId map[uint32]*typedValueRange) *Index { sortCols := groupByCols if len(sortCols) == 0 { sortCols = orderByCols @@ -3931,14 +3939,22 @@ type JoinSpec struct { indexOn []string } -type OrdCol struct { - sel Selector +type OrdExp struct { + exp ValueExp descOrder bool } -func NewOrdCol(table string, col string, descOrder bool) *OrdCol { - return &OrdCol{ - sel: NewColSelector(table, col), +func (oc *OrdExp) AsSelector() Selector { + sel, ok := oc.exp.(Selector) + if ok { + return sel + } + return nil +} + +func NewOrdCol(table string, col string, descOrder bool) *OrdExp { + return &OrdExp{ + exp: NewColSelector(table, col), descOrder: descOrder, } } @@ -4011,7 +4027,6 @@ func (sel *ColSelector) reduce(tx *SQLTx, row *Row, implicitTable string) (Typed if !ok { return nil, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col) } - return v, nil }