build-a-sql-database / lesson-06.md
Lesson 06 · In-memory tables

Scanning into a result set

Every query returns a result set - named columns plus rows. Today you build that shape and the scan that turns a whole table into one, the first operator in your execution pipeline.

The goal

Scan a table into a result set that carries the column names and every row in order.

Start here - the target
TO DO
Scenario: Scanning a table into a result set
Givena table "users" with columns (id, name) holding rows [1, "alice"] and [2, "bob"]
Whenthe table is scanned into a result set
Thenthe result set columns are ["id", "name"]
Andits rows are [1, "alice"] and [2, "bob"] in that order
Background

Queries do not return tables; they return result sets - a list of column names and the rows under them. Making this its own type is the key design decision of the execution engine: every operator you build (filter, project, sort, join) will take result sets and return result sets, so they snap together into a pipeline without caring where the rows originally came from.

Scan is the source at the bottom of every pipeline: it reads a table and produces the result set of all its rows, columns named straight from the schema. It does no filtering and no reshaping - just lifts stored data into the form queries consume. From here on, “run a query” means “start with a scan and transform the result set.”

Make it work
// the currency of the whole engine: named columns + rows
type ResultSet struct { Columns []string; Rows []Row }
func Scan(t *Table) ResultSet {
// column names from the schema, rows copied straight through
}
CheckpointDONE
A table becomes a result set with named columns - the shape every operator speaks. Commit and stop here.