Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
chirst committed Nov 21, 2024
1 parent d2e36da commit 665c2da
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 19 deletions.
2 changes: 1 addition & 1 deletion compiler/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type InsertStmt struct {

// Expr defines the interface of an expression.
type Expr interface {
Type() string
Type() string // TODO this pattern may not be the best
}

// BinaryExpr is for an expression with two operands.
Expand Down
8 changes: 4 additions & 4 deletions compiler/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,19 @@ var keywords = []string{

// Operators where op is operator.
const (
opAdd = "+"
opSub = "-"
opMul = "*"
opAdd = "+"
opDiv = "/"
opMul = "*"
opExp = "^"
)

// operators is a list of all operators.
var operators = []string{
opAdd,
opSub,
opMul,
opAdd,
opDiv,
opMul,
opExp,
}

Expand Down
8 changes: 5 additions & 3 deletions compiler/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ func (p *parser) getOperand() (Expr, error) {
return &IntLit{Value: intValue}, nil
}
if first.tokenType == tkIdentifier {
dot := p.peekNextNonSpace()
if dot.tokenType == tkSeparator {
next := p.peekNextNonSpace()
if next.tokenType == tkSeparator {
p.nextNonSpace()
prop := p.peekNextNonSpace()
if prop.tokenType == tkIdentifier {
Expand All @@ -208,7 +208,9 @@ func (p *parser) getOperand() (Expr, error) {
}, nil
}
}
return nil, errors.New("failed to parse identifier")
return &ColumnRef{
Column: first.value,
}, nil
}
// TODO support unary prefix expression
// TODO support parens
Expand Down
67 changes: 56 additions & 11 deletions planner/select.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package planner

import (
"slices"

"github.com/chirst/cdb/compiler"
"github.com/chirst/cdb/vm"
)
Expand Down Expand Up @@ -84,7 +86,12 @@ func (p *selectQueryPlanner) getQueryPlan() (*QueryPlan, error) {
}
var child logicalNode
resultColumn := p.stmt.ResultColumns[0]
if resultColumn.All {
if resultColumn.Count {
child = &countNode{
tableName: tableName,
rootPage: rootPageNumber,
}
} else if resultColumn.All {
scanColumns, err := p.getScanColumns()
if err != nil {
return nil, err
Expand All @@ -94,11 +101,37 @@ func (p *selectQueryPlanner) getQueryPlan() (*QueryPlan, error) {
rootPage: rootPageNumber,
scanColumns: scanColumns,
}
} else {
child = &countNode{
tableName: tableName,
rootPage: rootPageNumber,
} else if resultColumn.Expression != nil {
switch e := resultColumn.Expression.(type) {
case *compiler.ColumnRef:
if e.Table == "" {
// TODO should do better at checking no table
e.Table = p.stmt.From.TableName
}
cols, err := p.catalog.GetColumns(e.Table)
if err != nil {
return nil, err
}
colIdx := slices.Index(cols, e.Column)
pkCol, err := p.catalog.GetPrimaryKeyColumn(e.Table)
if err != nil {
return nil, err
}
child = &scanNode{
tableName: e.Table,
rootPage: rootPageNumber,
scanColumns: []scanColumn{
{
isPrimaryKey: pkCol == e.Column,
colIdx: colIdx,
},
},
}
default:
panic("unhandled expression")
}
} else {
panic("unhandled result column")
}
projections, err := p.getProjections()
if err != nil {
Expand Down Expand Up @@ -139,6 +172,13 @@ func (p *selectQueryPlanner) getScanColumns() ([]scanColumn, error) {

func (p *selectQueryPlanner) getProjections() ([]projection, error) {
resultColumn := p.stmt.ResultColumns[0]
if resultColumn.Count {
return []projection{
{
isCount: true,
},
}, nil
}
if resultColumn.All {
cols, err := p.catalog.GetColumns(p.stmt.From.TableName)
if err != nil {
Expand All @@ -152,12 +192,17 @@ func (p *selectQueryPlanner) getProjections() ([]projection, error) {
}
return projections, nil
}
if resultColumn.Count {
return []projection{
{
isCount: true,
},
}, nil
if resultColumn.Expression != nil {
switch e := resultColumn.Expression.(type) {
case *compiler.ColumnRef:
return []projection{
{
colName: e.Column,
},
}, nil
default:
panic("unhandled expression")
}
}
panic("unhandled projection")
}
Expand Down
38 changes: 38 additions & 0 deletions planner/select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,44 @@ func TestGetPlan(t *testing.T) {
}
}

func TestGetPlanSelectColumn(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: 7},
&vm.RowIdCmd{P1: 1, P2: 1},
&vm.ResultRowCmd{P1: 1, P2: 1},
&vm.NextCmd{P1: 1, P2: 4},
&vm.HaltCmd{},
}
ast := &compiler.SelectStmt{
StmtBase: &compiler.StmtBase{},
From: &compiler.From{
TableName: "foo",
},
ResultColumns: []compiler.ResultColumn{
{
Expression: &compiler.ColumnRef{
Column: "id",
},
},
},
}
mockCatalog := &mockSelectCatalog{}
mockCatalog.primaryKeyColumnName = "id"
mockCatalog.columns = []string{"name", "id", "age"}
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},
Expand Down

0 comments on commit 665c2da

Please sign in to comment.