Skip to content

csv

Package csv exposes RFC 4180 comma-separated values as a SQLite virtual table. Read a CSV file as if it were a regular SQL table — JOINs, WHERE clauses, aggregates all compose normally.

import (
sqlite "gosqlite.org"
"gosqlite.org/ext/csv"
)
if err := csv.Register(conn); err != nil { ... }
// Then in SQL:
// CREATE VIRTUAL TABLE temp.sales USING csv(filename='sales.csv', header=on);
// SELECT region, SUM(amount) FROM temp.sales GROUP BY region;

For a typed Go handle that hides the USING csv(…) argument string and its quoting — Create / Open / Columns / Rows / Name / Drop — see Table.

The vtab needs to be created on the same connection that will query it (SQLite virtual tables are per-connection). Either pin a *sql.Conn, open with MaxOpenConns=1, or install via a Driver.ConnectHook.

CREATE VIRTUAL TABLE name USING csv(named-args) accepts:

  • filename=‘path.csv’ — file path; opened via the fs.FS handed to RegisterFS (defaults to os-backed access via Register).
  • data=‘inline CSV content’ — embed CSV literally in the CREATE. Mutually exclusive with filename.
  • schema=‘CREATE TABLE x(a INTEGER, b TEXT, …)’ — column names + affinity hints. Without schema, the vtab declares all columns as TEXT and derives names from the header row (or c1, c2, c3, …).
  • header=on — treat the first row as the column-name header. Default off.
  • columns=N — force a fixed column count; truncates wider rows, pads narrower with NULLs. Default: count from the header (or first data row).
  • comma=’,’ — column separator; any single-rune literal. Default ’,’.
  • comment=’#’ — lines starting with this rune are skipped. Default unset.
  • skip=N — discard N leading rows before the header / first record (provenance banners, export metadata). Default 0.

With comma= (any delimiter, e.g. tab or pipe), schema= (per-column affinity so numeric fields read back as INTEGER/REAL), and skip=, this module covers the affinity-typed / custom-separator CSV variants that some toolchains expose as a separate “vsv” extension.

When schema is provided, the vtab scans each column declaration for the keywords INTEGER / INT / REAL / FLOAT / DOUBLE / NUMERIC. Matching columns return INTEGER or REAL when their CSV string parses; otherwise the value is returned as TEXT (best-effort coercion, matches the SQLite-bundled csv.c semantics). All other columns return TEXT.

Empty CSV cells in non-TEXT columns return SQL NULL.

Use RegisterFS to scope file access to a specific io/fs.FS:

  • embed.FS — bundle CSV fixtures inside a binary
  • fstest.MapFS — in-memory CSV for tests
  • os.DirFS(prefix) — sandbox to a directory
import _ "gosqlite.org/ext/csv/auto"

Auto-registration uses Register (os-backed file access). For sandboxed deployments, call RegisterFS from your own ConnectHook.

Ported from ncruces/ext/csv. Function lineup and named-arg shape match upstream; the type-affinity parser is intentionally simpler (keyword scan, not a full DDL parser).


Full API: pkg.go.dev/gosqlite.org/ext/csv