0305: 执行SQL语句
执行解析后的SQL
之前已经实现了一些关系型数据库的函数接口:
func (db *DB) Select(schema *Schema, row Row) (ok bool, err error)
func (db *DB) Insert(schema *Schema, row Row) (updated bool, err error)
func (db *DB) Update(schema *Schema, row Row) (updated bool, err error)
func (db *DB) Delete(schema *Schema, row Row) (deleted bool, err error)现在又将SQL解析成了各种 StmtXXX,可以把这两部分打通:
type SQLResult struct {
Updated int
Header []string
Values []Row
}
func (db *DB) ExecStmt(stmt interface{}) (r SQLResult, err error) {
switch ptr := stmt.(type) {
case *StmtCreatTable:
err = db.execCreateTable(ptr)
case *StmtSelect:
r.Header = ptr.cols
r.Values, err = db.execSelect(ptr)
case *StmtInsert:
r.Updated, err = db.execInsert(ptr)
case *StmtUpdate:
r.Updated, err = db.execUpdate(ptr)
case *StmtDelete:
r.Updated, err = db.execDelete(ptr)
default:
panic("unreachable")
}
return
}SQLResult 返回一条语句的执行结果:
- Select 语句返回
Header、Values。以后会返回多个 row,所以接口是 slice。 - 其他更新语句返回
Updated,记录更新的行数。当然,现在只能是 0、1。
储存表定义
各种操作都依赖 schema,所以首先要实现 execCreateTable(),把表定义序列化后储存到一个 key 里。 DB 增加一个 map 缓存,key 是表名:
type DB struct {
KV KV
tables map[string]Schema
}func (db *DB) GetSchema(table string) (Schema, error) {
schema, ok := db.tables[table]
if !ok {
val, ok, err := db.KV.Get([]byte("@schema_" + table))
if err == nil && ok {
err = json.Unmarshal(val, &schema)
}
if err != nil {
return Schema{}, err
}
if !ok {
return Schema{}, errors.New("table is not found")
}
db.tables[table] = schema
}
return schema, nil
}实现 execCreateTable():
- 将
StmtCreatTable转化为Schema。 - 将
Schema储存到@schema_+ 表名这个 key 里。 - 加到
DB.tablesmap 里。
func (db *DB) execCreateTable(stmt *StmtCreatTable) (err error)执行 select 语句
建议拆分成几个小函数,其他语句可以复用:
lookupColumns():检查列名(select a,b),返回schema.Cols数组下标。makePKey():检查WHERE是否是主键,返回一个填充了主键的Row。subsetRow():只返回select a,b里的列。
func (db *DB) execSelect(stmt *StmtSelect) ([]Row, error) {
schema, ok := db.tables[stmt.table]
if !ok {
return nil, errors.New("table is not found")
}
indices, err := lookupColumns(schema.Cols, stmt.cols)
if err != nil {
return nil, err
}
row, err := makePKey(&schema, stmt.keys)
if err != nil {
return nil, err
}
if ok, err = db.Select(&schema, row); err != nil {
return nil, err
}
if !ok {
return nil, nil
}
row = subsetRow(row, indices)
return []Row{row}, nil
}执行更新语句
实现其他SQL语句(调用 DB.Insert()、DB.Update()、DB.Delete()):
func (db *DB) execInsert(stmt *StmtInsert) (count int, err error)
func (db *DB) execUpdate(stmt *StmtUpdate) (count int, err error)
func (db *DB) execDelete(stmt *StmtDelete) (count int, err error)要求:
- 如果 KV 有更新,
count返回 1,否则返回 0。 - 检查
StmtXXX是否跟Schema匹配。
其中 update 语句不需要支持更新主键,也就是说 update 只是更新 KV 里的 V。如果要更新主键,相对于删除 KV 里的 key 再重新插入,实际应用上也很少这种需求。
您正在阅读免费版教程,从第4章起只有简单的指引,适合爱好挑战和自学的读者。
可以购买有详细指导+背景知识的完整版。