diff --git a/planner/select.go b/planner/select.go index 24b7c6f..db1a7b7 100644 --- a/planner/select.go +++ b/planner/select.go @@ -105,6 +105,26 @@ func (p *selectQueryPlanner) getQueryPlan() (*QueryPlan, error) { default: return nil, errors.New("expected scanNode") } + } else if resultColumn.AllTable != "" { + if tableName != resultColumn.AllTable { + return nil, fmt.Errorf("invalid expression %s.*", resultColumn.AllTable) + } + scanColumns, err := p.getScanColumns() + if err != nil { + return nil, err + } + switch c := child.(type) { + case *scanNode: + c.scanColumns = append(c.scanColumns, scanColumns...) + case nil: + child = &scanNode{ + tableName: tableName, + rootPage: rootPageNumber, + scanColumns: scanColumns, + } + default: + return nil, errors.New("expected scanNode") + } } else if resultColumn.Expression != nil { switch e := resultColumn.Expression.(type) { case *compiler.ColumnRef: @@ -220,6 +240,16 @@ func (p *selectQueryPlanner) getProjections() ([]projection, error) { colName: c, }) } + } else if resultColumn.AllTable != "" { + cols, err := p.catalog.GetColumns(p.stmt.From.TableName) + if err != nil { + return nil, err + } + for _, c := range cols { + projections = append(projections, projection{ + colName: c, + }) + } } else if resultColumn.Expression != nil { switch e := resultColumn.Expression.(type) { case *compiler.ColumnRef: diff --git a/planner/select_test.go b/planner/select_test.go index 8d0f8e7..09968a8 100644 --- a/planner/select_test.go +++ b/planner/select_test.go @@ -152,6 +152,43 @@ func TestGetPlanSelectMultiColumn(t *testing.T) { } } +func TestGetPlanTableAll(t *testing.T) { + expectedCommands := []vm.Command{ + &vm.InitCmd{P2: 1}, + &vm.TransactionCmd{P1: 0}, + &vm.OpenReadCmd{P1: 1, P2: 2}, + &vm.RewindCmd{P1: 1, P2: 8}, + &vm.RowIdCmd{P1: 1, P2: 1}, + &vm.ColumnCmd{P1: 1, P2: 0, P3: 2}, + &vm.ResultRowCmd{P1: 1, P2: 2}, + &vm.NextCmd{P1: 1, P2: 4}, + &vm.HaltCmd{}, + } + ast := &compiler.SelectStmt{ + StmtBase: &compiler.StmtBase{}, + From: &compiler.From{ + TableName: "foo", + }, + ResultColumns: []compiler.ResultColumn{ + { + AllTable: "foo", + }, + }, + } + mockCatalog := &mockSelectCatalog{} + mockCatalog.primaryKeyColumnName = "id" + mockCatalog.columns = []string{"id", "name"} + plan, err := NewSelect(mockCatalog, ast).ExecutionPlan() + if err != nil { + t.Errorf("expected no err got err %s", err) + } + for i, c := range expectedCommands { + if !reflect.DeepEqual(c, plan.Commands[i]) { + t.Errorf("got %#v want %#v", plan.Commands[i], c) + } + } +} + func TestGetPlanPKMiddleOrdinal(t *testing.T) { expectedCommands := []vm.Command{ &vm.InitCmd{P2: 1},