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

0304: Statements

Other Statements

Following the previous parseSelect(), add more statements:

create table t (
    a int64,
    b string,
    c string,
    primary key (b, c)
);
insert into t values (1, 'x', 'y');
update t set a = 1 where b = 'x' and c = 'y';
delete from t where b = 'x' and c = 'y';

Corresponding types:

type StmtCreatTable struct {
    table string
    cols  []Column
    pkey  []string
}
type StmtInsert struct {
    table string
    value []Cell
}
type StmtUpdate struct {
    table string
    keys  []NamedCell
    value []NamedCell
}
type StmtDelete struct {
    table string
    keys  []NamedCell
}

Only single-row operations by primary key are supported now, so the WHERE part maps to keys. Range queries and indexes will be added later, with more complex syntax.

Recognize SQL Statements

Add parseStmt(), which returns different statement types using interface{}:

func (p *Parser) parseStmt() (out interface{}, err error) {
    if p.tryKeyword("SELECT") {
        stmt := &StmtSelect{}
        err = p.parseSelect(stmt)
        out = stmt
    } else if p.tryKeyword("CREATE", "TABLE") {
        stmt := &StmtCreatTable{}
        err = p.parseCreateTable(stmt)
        out = stmt
    } else if p.tryKeyword("INSERT", "INTO") {
        stmt := &StmtInsert{}
        err = p.parseInsert(stmt)
        out = stmt
    } else if p.tryKeyword("UPDATE") {
        stmt := &StmtUpdate{}
        err = p.parseUpdate(stmt)
        out = stmt
    } else if p.tryKeyword("DELETE", "FROM") {
        stmt := &StmtDelete{}
        err = p.parseDelete(stmt)
        out = stmt
    } else {
        err = errors.New("unknown statement")
    }
    if err != nil {
        return nil, err
    }
    return out, nil
}

The tryKeyword() function is updated to match multiple tokens in sequence:

func (p *Parser) tryKeyword(kws ...string) bool

Since parseStmt() already consumes the leading tokens, the earlier parseSelect() must be updated.

This shows that when parsing SQL, looking at the next 1 or 2 tokens is enough to decide what to do. Many languages are this easy to parse and do not need compiler construction theory. Even with syntax like select a+b*c, recursion is enough.

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