⚠

The web version only has simple instructions since chapter 04, while the full book has detailed explanations and background info.

0506: WHERE Expression

Parse WHERE

This step adds no new features. It refactor the WHERE part into an expression.

type StmtSelect struct {
    table string
    cols  []interface{} // ExprUnOp | ExprBinOp | string | *Cell
    // keys  []NamedCell
    cond  interface{}
}

type StmtUpdate struct {
    table string
    // keys  []NamedCell
    cond  interface{}
    value []ExprAssign
}

type StmtDelete struct {
    table string
    // keys  []NamedCell
    cond  interface{}
}

Update parser:

func (p *Parser) parseSelect(out *StmtSelect) (err error) {
    // ...
    out.cond, err = p.parseWhere()
    return err
}

func (p *Parser) parseWhere() (expr interface{}, err error)

Match Expressions

During execution, extract primary key values from the expression:

func (db *DB) execSelect(stmt *StmtSelect) ([]Row, error) {
    // ...
    row, err := matchPKey(&schema, stmt.cond)
    if err != nil {
        return nil, err
    }
    if ok, err = db.Select(&schema, row); err != nil {
        return nil, err
    }
    // ...
}
func matchPKey(schema *Schema, cond interface{}) (Row, error) {
    if keys, ok := matchAllEq(cond, nil); ok {
        return makePKey(schema, keys)
    }
    return nil, errors.New("unimplemented WHERE")
}

matchAllEq() detects expressions like a = 123 AND b = 456 AND ... and outputs column names and values. It recursively walks the expression. Implement this:

func matchAllEq(cond interface{}, out []NamedCell) ([]NamedCell, bool)

For now, only primary key queries that return a single row are supported. To add other query types, you must recognize other expression forms, such as range queries in the next step.

ⓘ

CodeCrafters.io has similar courses in many programming languages, including build your own Redis, SQLite, Docker, etc. It’s worth checking out.