Help us shape the future of Go! Take the 2026 Go Developer Survey

source

package
v0.6.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package source is the runtime half of ursus's scan contract.

The logical half lives in internal/plan: plan.Source knows only how to report a schema and its pushdown capabilities, which is all the optimizer needs. This package adds the data side.

They are split so the dependency runs the right way. A concrete source (in-memory, Parquet, a user's own storage) implements both interfaces, and it must be able to do so without importing the physical planner — otherwise every new source would create an import cycle. Keeping the runtime contract in a low package means the physical layer imports sources, never the reverse.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Decompressed added in v0.6.7

func Decompressed(rc io.ReadCloser) (io.ReadCloser, error)

Decompressed is rc's bytes, decompressed where they begin as a gzip, a zlib or a Zstandard stream does, and rc's own otherwise. Closing it closes rc.

gzip's two bytes, 1f 8b, and Zstandard's four, 28 b5 2f fd, begin no text. zlib's, 78 and one of 01, 5e, 9c and da, can: "x^" may start a CSV header. So a zlib header is trusted only where the stream is zlib's beyond doubt (isZlib); a text it begins is read as text, where Polars reads a CSV of "x^2,b" as no rows. Bytes after a zlib stream's end are refused, as a gzip stream's are.

func WithColumn added in v0.6.7

func WithColumn(schema *dtype.Schema, pos int, b *data.Batch, col *data.Column) (*data.Batch, error)

WithColumn is b, of schema's columns but the one at pos, with col inserted there.

func WithPathColumn added in v0.6.7

func WithPathColumn(op string, schema *dtype.Schema, name string) (*dtype.Schema, error)

WithPathColumn is schema with a String column name after its others, each row's file path, as Polars' include_file_paths (step 359); op names the scan in the refusal of a name the files' columns have already, Polars' "column name for file paths conflicts with column name from file".

Types

type BatchSource

type BatchSource interface {
	Schema() *dtype.Schema

	// Next returns the next batch, or (nil, io.EOF) when the stream is exhausted.
	// An empty non-nil batch is allowed and is not end-of-stream.
	Next(ctx context.Context) (*data.Batch, error)

	Close() error
}

BatchSource produces batches.

Implementations MUST be safe for concurrent Next. v0.1 has a single consumer, but v0.2's morsel scheduler will have several, and retrofitting the synchronisation into a shipped reader is much worse than putting it in now.

type Openable

type Openable interface {
	Open(ctx context.Context, spec ScanSpec) (BatchSource, error)
}

Openable is implemented by a plan.Source that can produce data.

The physical planner type-asserts to this. A plan.Source that does not implement it can still be type-checked and explained — useful for planning against a catalog — but not executed.

type RowsOnly added in v0.6.8

type RowsOnly interface {
	RowsOnly(spec ScanSpec) bool
}

RowsOnly is implemented by a source that may answer a scan of no columns, an empty non-nil Projection, with batches of its rows and no columns: a count's, which reads no column (step 370). RowsOnly says whether it answers spec's; where it does not, or the source is not one, it is asked for one column, its cheapest, which the scan trims away.

type ScanSpec

type ScanSpec struct {
	// Projection is the exact column list to EMIT, in this order. nil means every
	// column.
	//
	// Honouring it is optional: a source that ignores it gets a trim operator
	// inserted above the scan. Honouring it is where the win is, though — the
	// point of projection pushdown is that the reader never touches the bytes.
	Projection []string

	// Predicate holds conjuncts the source said it could use, via
	// plan.PredicatePushdown.ClassifyPredicates. A source that never claimed a
	// capability never sees this non-empty.
	//
	// # The read set is Projection PLUS these columns
	//
	// A conjunct classified Exact is removed from the plan, so nothing above the
	// scan references its columns and they are absent from Projection. The source
	// must still read them to evaluate the predicate, and must NOT emit them.
	//
	//	Projection: [a]   Predicate: [c > 5]
	//	  =>  decode {a, c}, filter on c, emit {a}
	//
	// A reader that decodes only Projection and then evaluates Predicate is
	// reading a column it never loaded. This is the one place where ignoring a
	// field is not the safe option: having claimed Exact, the source is now the
	// only thing applying that filter.
	//
	// Dropping rows the predicate rejects is required only for a conjunct the
	// source classified Exact. For Inexact, returning a superset is the definition
	// — skip what you can prove cannot match and let the Filter above finish.
	Predicate []expr.Node

	// MaxRows is an upper bound on the rows that will be consumed; 0 means
	// unlimited. Stopping early is the entire value of Head(n) on a large file.
	//
	// Overshooting is fine — a Parquet reader stopping at a row-group boundary,
	// say. A Limit operator above the scan always enforces the real bound.
	MaxRows int

	// Threads is how many workers the query is running on, so a source that can
	// use more than one core knows whether it may. 0 or 1 means stay serial.
	//
	// A source is free to ignore it — most have nothing to parallelise, because
	// reading is I/O and the work above them is where the CPU goes. The CSV and
	// Parquet readers are the exceptions: turning text into typed columns, and
	// decompressing and decoding pages, is real compute, and each used to do all of
	// it on one core while eight sat idle. The Parquet reader decodes row groups in
	// parallel (step 102), and a profile had found it at nearly half the CPU of the
	// queries it measured.
	//
	// It must be honoured in the direction that matters: WithThreads(1) is
	// documented as reproducing the serial operator tree exactly, so a source that
	// parallelised regardless would make that knob a lie.
	Threads int

	// BatchSize is the requested rows per batch. A source may return fewer.
	BatchSize int

	// ReadAhead is how many bytes of decoded batches a source may hold ahead of its
	// consumer; 0 is the source's own default. The Parquet reader decodes several
	// row groups at once and returns them in order, and before step 214 a row group
	// not at the head stopped three batches in, so most of each decoded only once it
	// was the head, one at a time.
	//
	// It is not charged to the memory budget: it is transient and bounded, and
	// charging it would make sinks spill for bytes about to be consumed. The engine
	// derives the bound from the budget instead.
	ReadAhead int64

	// Eval evaluates an expression over a batch, as the engine does. A source that
	// evaluates a pushed conjunct itself uses it; the engine sets it, and a source
	// handed none evaluates nothing. The Parquet reader evaluates a string
	// conjunct once per dictionary value, to drop the rows that fail it before
	// copying them (step 193).
	Eval func(ctx context.Context, n expr.Node, b *data.Batch) (*data.Column, error)
}

ScanSpec is what the physical planner asks a source to produce.

Every field is a REQUEST, not a contract the source must meet. A source that ignores all of them is correct and merely slow: the engine trims columns, re-applies predicates and enforces limits above the scan regardless. Nothing below is load-bearing for correctness — with one exception, spelled out under Predicate, which is load-bearing in the other direction.

func (ScanSpec) ReadSet

func (s ScanSpec) ReadSet(full *dtype.Schema) []string

ReadSet returns the columns this scan must decode: Projection plus every column referenced by Predicate, in full's order.

It is here rather than left to each reader because getting it wrong is silent. A source that decodes only Projection and then evaluates Predicate reads a column it never loaded, and every source that pushes predicates needs this identical derivation — the kind of duplication that has already diverged once in this codebase.

A nil Projection means "everything", and stays nil: there is nothing to widen.

Directories

Path Synopsis
Package arrowsrc scans a stream of Arrow records: an IPC stream, a Flight response, a C Data Interface stream — anything that is an array.RecordReader.
Package arrowsrc scans a stream of Arrow records: an IPC stream, a Flight response, a C Data Interface stream — anything that is an array.RecordReader.
Package csv reads and writes delimited text files.
Package csv reads and writes delimited text files.
Package files reads several files of one format as one scan, in order, each file by a source of its own, with columns every row of a file shares after the files' own: a hive dataset's partition keys, and the file's path (step 360).
Package files reads several files of one format as one scan, in order, each file by a source of its own, with columns every row of a file shares after the files' own: a hive dataset's partition keys, and the file's path (step 360).
Package hive reads a dataset's partition columns from its files' paths, as Hive lays a dataset out and Polars reads one: each directory below the dataset's root named key=value gives every file beneath it a column key of value (step 347).
Package hive reads a dataset's partition columns from its files' paths, as Hive lays a dataset out and Polars reads one: each directory below the dataset's root named key=value gives every file beneath it a column key of value (step 347).
Package memsrc is an in-memory scan source.
Package memsrc is an in-memory scan source.
Package ndjson reads newline-delimited JSON (step 334): Polars' read_ndjson and scan_ndjson, a JSON object a line, a column a key.
Package ndjson reads newline-delimited JSON (step 334): Polars' read_ndjson and scan_ndjson, a JSON object a line, a column a key.
Package parquet reads and writes Apache Parquet files.
Package parquet reads and writes Apache Parquet files.
Package sqlrows reads a database/sql result into a batch: Polars' read_database (step 353).
Package sqlrows reads a database/sql result into a batch: Polars' read_database (step 353).
Package testsrc is a scan source that lies about its capabilities on purpose.
Package testsrc is a scan source that lies about its capabilities on purpose.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL