Skip to content

Commit

Permalink
Lab 2
Browse files Browse the repository at this point in the history
  • Loading branch information
Valerie Kwek authored and Valerie Kwek committed Oct 14, 2024
1 parent 5359545 commit 909a80b
Show file tree
Hide file tree
Showing 30 changed files with 450 additions and 68 deletions.
Binary file added godb/InsertTestFile.dat
Binary file not shown.
Binary file added godb/JoinTestFile.dat
Binary file not shown.
54 changes: 47 additions & 7 deletions godb/agg_op.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package godb

import (
"fmt"
)

type Aggregator struct {
// Expressions that when applied to tuples from the child operators,
// respectively, return the value of the group by key tuple
Expand Down Expand Up @@ -48,7 +44,15 @@ func NewAggregator(emptyAggState []AggState, child Operator) *Aggregator {
// HINT: use [TupleDesc.merge] to merge the two [TupleDesc]s.
func (a *Aggregator) Descriptor() *TupleDesc {
// TODO: some code goes here
return &TupleDesc{} //replace me
noGroupBy := &TupleDesc{}
for _, aggState := range a.newAggState {
noGroupBy = noGroupBy.merge(aggState.GetTupleDesc())
}
groupBy := &TupleDesc{}
for _, expr := range a.groupByFields {
groupBy.Fields = append(groupBy.Fields, expr.GetExprType())
}
return groupBy.merge(noGroupBy) //replace me
}

// Returns an iterator over the results of the aggregate. The aggregate should
Expand Down Expand Up @@ -143,7 +147,20 @@ func (a *Aggregator) Iterator(tid TransactionID) (func() (*Tuple, error), error)
// If there is any error during expression evaluation, return the error.
func extractGroupByKeyTuple(a *Aggregator, t *Tuple) (*Tuple, error) {
// TODO: some code goes here
return &Tuple{}, fmt.Errorf("extractGroupByKeyTuple not implemented.") // replace me
var fields []DBValue
for _, expr := range a.groupByFields {
value, err := expr.EvalExpr(t)
if err != nil {
return nil, err
}
fields = append(fields, value)
}
groupByKeyTuple := &Tuple{
Desc: t.Desc,
Fields: fields,
Rid: t.Rid,
}
return groupByKeyTuple, nil // replace me
}

// Given a tuple t from child and (a pointer to) the array of partially computed
Expand All @@ -154,6 +171,13 @@ func extractGroupByKeyTuple(a *Aggregator, t *Tuple) (*Tuple, error) {
// field and add the new aggState to grpAggState.
func addTupleToGrpAggState(a *Aggregator, t *Tuple, grpAggState *[]AggState) {
// TODO: some code goes here
for i := 0; i < len(*grpAggState); i++ {
if (*grpAggState)[i] == nil {
newAggState := a.newAggState[i].Copy()
(*grpAggState)[i] = newAggState
}
(*grpAggState)[i].AddTuple(t)
}
}

// Given that all child tuples have been added, return an iterator that iterates
Expand All @@ -166,8 +190,24 @@ func addTupleToGrpAggState(a *Aggregator, t *Tuple, grpAggState *[]AggState) {
// tuples using the joinTuples function in tuple.go you wrote in lab 1.
func getFinalizedTuplesIterator(a *Aggregator, groupByList []*Tuple, aggState map[any]*[]AggState) func() (*Tuple, error) {
// TODO: some code goes here
curr := len(groupByList) - 1
return func() (*Tuple, error) {
// TODO: some code goes here
return nil, fmt.Errorf("getFinalizedTuplesIterator not implemented.") // replace me
if curr < 0 {
return nil, nil
}
group := groupByList[curr]
aggTuple, _ := extractGroupByKeyTuple(a, group)
groupAggStates := aggState[aggTuple.tupleKey()]
if groupAggStates != nil {
for _, state := range *groupAggStates {
aggStateTuple := state.Finalize()
aggTuple = joinTuples(aggTuple, aggStateTuple)
}
curr -= 1
aggTuple.Desc = *a.Descriptor()
return aggTuple, nil // replace me
}
return nil, nil
}
}
163 changes: 143 additions & 20 deletions godb/agg_state.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package godb

import (
"fmt"
)

// interface for an aggregation state
type AggState interface {
// Initializes an aggregation state. Is supplied with an alias, an expr to
Expand Down Expand Up @@ -67,131 +63,258 @@ func (a *CountAggState) GetTupleDesc() *TupleDesc {
// Implements the aggregation state for SUM
type SumAggState struct {
// TODO: some code goes here
alias string
expr Expr
sum any
}

func (a *SumAggState) Copy() AggState {
// TODO: some code goes here
return nil // replace me
return &SumAggState{a.alias, a.expr, a.sum} // replace me
}

func intAggGetter(v DBValue) any {
// TODO: some code goes here
value, ok := v.(IntField)
if ok {
return value.Value
}
return nil // replace me
}

func stringAggGetter(v DBValue) any {
// TODO: some code goes here
value, ok := v.(StringField)
if ok {
return value.Value
}
return nil // replace me
}

func (a *SumAggState) Init(alias string, expr Expr) error {
// TODO: some code goes here
return fmt.Errorf("SumAggState.Init not implemented") // replace me
a.sum = nil
a.expr = expr
a.alias = alias
return nil // replace me
}

func (a *SumAggState) AddTuple(t *Tuple) {
// TODO: some code goes here
dbVal, _ := a.expr.EvalExpr(t)
intValue := intAggGetter(dbVal)
if intValue != nil {
if a.sum == nil {
a.sum = int64(0)
}
a.sum = a.sum.(int64) + intValue.(int64)
} else {
if a.sum == nil {
a.sum = ""
}
a.sum = a.sum.(string) + stringAggGetter(dbVal).(string)
}
}

func (a *SumAggState) GetTupleDesc() *TupleDesc {
// TODO: some code goes here
return &TupleDesc{} // replace me
ft := FieldType{a.alias, "", IntType}
fts := []FieldType{ft}
td := TupleDesc{}
td.Fields = fts
return &td // replace me
}

func (a *SumAggState) Finalize() *Tuple {
// TODO: some code goes here
return &Tuple{} // replace me
td := a.GetTupleDesc()
var f DBValue
if intValue, ok := a.sum.(int64); ok {
f = IntField{intValue}
} else {
f = StringField{a.sum.(string)}
}
return &Tuple{*td, []DBValue{f}, nil} // replace me
}

// Implements the aggregation state for AVG
// Note that we always AddTuple() at least once before Finalize()
// so no worries for divide-by-zero
type AvgAggState struct {
// TODO: some code goes here
alias string
expr Expr
total int64
size int64
}

func (a *AvgAggState) Copy() AggState {
// TODO: some code goes here
return nil // replace me
return &AvgAggState{a.alias, a.expr, a.total, a.size} // replace me
}

func (a *AvgAggState) Init(alias string, expr Expr) error {
// TODO: some code goes here
return fmt.Errorf("AvgAggState.Init not implemented") // replace me
a.total = 0
a.size = 0
a.expr = expr
a.alias = alias
return nil // replace me
}

func (a *AvgAggState) AddTuple(t *Tuple) {
// TODO: some code goes here
dbVal, err := a.expr.EvalExpr(t)
if err == nil {
a.total += dbVal.(IntField).Value
a.size += 1
}
}

func (a *AvgAggState) GetTupleDesc() *TupleDesc {
// TODO: some code goes here
return &TupleDesc{} // replace me
ft := FieldType{a.alias, "", IntType}
fts := []FieldType{ft}
td := TupleDesc{}
td.Fields = fts
return &td // replace me
}

func (a *AvgAggState) Finalize() *Tuple {
// TODO: some code goes here
return &Tuple{} // replace me
td := a.GetTupleDesc()
f := IntField{a.total / a.size}
return &Tuple{*td, []DBValue{f}, nil} // replace me
}

// Implements the aggregation state for MAX
// Note that we always AddTuple() at least once before Finalize()
// so no worries for NaN max
type MaxAggState struct {
// TODO: some code goes here
alias string
expr Expr
max any
}

func (a *MaxAggState) Copy() AggState {
// TODO: some code goes here
return nil // replace me
return &MaxAggState{a.alias, a.expr, a.max} // replace me
}

func (a *MaxAggState) Init(alias string, expr Expr) error {
// TODO: some code goes here
return fmt.Errorf("MaxAggState.Init not implemented") // replace me
a.max = nil
a.expr = expr
a.alias = alias
return nil // replace me
}

func (a *MaxAggState) AddTuple(t *Tuple) {
// TODO: some code goes here
dbVal, _ := a.expr.EvalExpr(t)
intValue := intAggGetter(dbVal)
if intValue != nil {
if a.max == nil {
a.max = intValue.(int64)
}
if a.max.(int64) < intValue.(int64) {
a.max = intValue.(int64)
}
} else {
strValue := stringAggGetter(dbVal).(string)
if a.max == nil {
a.max = strValue
}
if a.max.(string) < strValue {
a.max = strValue
}
}
}

func (a *MaxAggState) GetTupleDesc() *TupleDesc {
// TODO: some code goes here
return &TupleDesc{} // replace me
ft := FieldType{a.alias, "", IntType}
fts := []FieldType{ft}
td := TupleDesc{}
td.Fields = fts
return &td // replace me
}

func (a *MaxAggState) Finalize() *Tuple {
// TODO: some code goes here
return &Tuple{} // replace me
td := a.GetTupleDesc()
var f DBValue
if intValue, ok := a.max.(int64); ok {
f = IntField{intValue}
} else {
f = StringField{a.max.(string)}
}
return &Tuple{*td, []DBValue{f}, nil} // replace me
}

// Implements the aggregation state for MIN
// Note that we always AddTuple() at least once before Finalize()
// so no worries for NaN min
type MinAggState struct {
// TODO: some code goes here
alias string
expr Expr
min any
}

func (a *MinAggState) Copy() AggState {
// TODO: some code goes here
return nil // replace me
return &MinAggState{a.alias, a.expr, a.min} // replace me
}

func (a *MinAggState) Init(alias string, expr Expr) error {
// TODO: some code goes here
return fmt.Errorf("MinAggState.Init not implemented") // replace me
a.min = nil
a.expr = expr
a.alias = alias
return nil // replace me
}

func (a *MinAggState) AddTuple(t *Tuple) {
// TODO: some code goes here
dbVal, _ := a.expr.EvalExpr(t)
intValue := intAggGetter(dbVal)
if intValue != nil {
if a.min == nil {
a.min = intValue.(int64)
}
if a.min.(int64) > intValue.(int64) {
a.min = intValue.(int64)
}
} else {
strValue := stringAggGetter(dbVal).(string)
if a.min == nil {
a.min = strValue
}
if a.min.(string) > strValue {
a.min = strValue
}
}
}

func (a *MinAggState) GetTupleDesc() *TupleDesc {
// TODO: some code goes here
return &TupleDesc{} // replace me
ft := FieldType{a.alias, "", IntType}
fts := []FieldType{ft}
td := TupleDesc{}
td.Fields = fts
return &td // replace me
}

func (a *MinAggState) Finalize() *Tuple {
// TODO: some code goes here
return &Tuple{} // replace me
td := a.GetTupleDesc()
var f DBValue
if intValue, ok := a.min.(int64); ok {
f = IntField{intValue}
} else {
f = StringField{a.min.(string)}
}
return &Tuple{*td, []DBValue{f}, nil} // replace me
}
Loading

0 comments on commit 909a80b

Please sign in to comment.