Documentation
¶
Overview ¶
Package collide is the COLLIDING-BARE-NAME fixture: three relations whose columns are all called c0, c1, c2, the way SQLancer names every schema it generates.
It exists because every other corpus in this repository prefixes its column names per table — TPC-H's `l_`, `o_`, `c_`, `n_`; the type matrix's `c_i32`, `c_str`; multikey's shared `s`, `n`, `d` across four tables of ONE schema — so no two DIFFERENT relations in one query ever share a bare column name that means different things. That is the blind spot #843 lived in for twelve releases: inside a derived table with two or more UNALIASED relations, every base scan was re-aliased to the derived table's alias, so `t0.c1` bound to whichever relation was planned last and the query answered another table's column with no error at all. A fixture whose bare names collide is the only shape that can see it, and it belongs in the corpora whether or not any particular defect is fixed.
Every Want here was measured on live postgres:17-alpine over these exact rows.
Index ¶
Constants ¶
const ( T0 = "clt0" T1 = "clt1" T2 = "clt2" // T4 and T5 carry ONE column whose names differ only by CASE. Since an // unquoted reference folds (#731) those two names are one name to every // resolver, so a qualified reference to either is only resolvable through // its RELATION — the identity is (relation, folded name) and never the // bare folded name (ADR-0026). Without them nothing in any corpus made // that distinction: the arc's round-0 review found `SELECT clt4.MixedCol, // clt5.mixedcol FROM clt4, clt5` answering clt5's value TWICE on all four // arms. T4 = "clt4" T5 = "clt5" // T6 is the THIRD spelling of that one folded name, all upper case, so a // query can name all three relations at once and each reference has two // wrong answers available to it rather than one. Round 1's review found // single and dag DISAGREEING on exactly that shape. T6 = "clt6" // TCam is a CamelCase SCHEMA — the shape a parquet-registered table has, // and ClickBench's `hits` exactly. It is here because no DAG or worker // gate put one through `batch.resolveFoldedIndex`'s case-insensitive arm: // the two-path corpora all run on all-lower-case fixtures, so the half of // #731 that keeps ClickBench working never executed on a worker. TCam = "cltcam" )
The three relations. SQLancer's own names, kept, so a dump from it can be replayed against this fixture without renaming anything.
Variables ¶
This section is empty.
Functions ¶
func CamelSchema ¶
CamelSchema is TCam's: names a parquet file would carry, not names a DDL would fold.
func CaseData ¶
CaseData is one case-colliding relation's rows. The three relations' value ranges do not overlap, so a reference bound to the wrong one cannot answer the right number by accident.
func CaseSchema ¶
CaseSchema is T4's and T5's, parameterized by the case-carrying column's spelling: `MixedCol` in one relation, `mixedcol` in the other.
Types ¶
type Case ¶
type Case struct {
Name string
SQL string
Want []string
Ordered bool
// PGSQL is the spelling PostgreSQL needs for the same question, when the
// wadjet spelling is one PostgreSQL cannot resolve. It is filled in
// automatically for every entry naming a CamelCase column of this fixture
// — see pgSpelling — because that unquoted spelling IS the divergence
// ADR-0012 records: PostgreSQL matches a folded name exactly against the
// catalog, so `clt4.MixedCol` is 42703 there and `clt4."MixedCol"` is the
// question it can answer. Every value this corpus asserts is therefore
// PostgreSQL's answer to the quoted spelling, which is the contract that
// entry states.
PGSQL string
// Ref is the same question with DISTINCT output names, for the entries
// whose own names collide. A result read BY NAME cannot represent two
// columns of one name, so the duplicate spelling is compared against its
// reference — which is positional by construction and works on the DAG,
// where no positional accessor reaches the caller.
Ref string
// KnownBug pins a divergence from Want. The comparison still runs and
// Want stays exactly as PostgreSQL wrote it, so a pinned entry that
// starts AGREEING fails and deleting the pin is the proof of a fix
// (ADR-0013 §Pins).
KnownBug string
Issue string
// KnownBugArms narrows the pin to the EXECUTION ARMS that diverge, by
// the two-path gate's own names ("single", "spilled", "dag",
// "dag-shuffled"). Empty means every arm, which is what a pin meant
// before this existed.
//
// A divergence that is real on ONE arm is the most dangerous kind — two
// engines answering one query differently — and pinning it everywhere
// would stop asserting the arms that are RIGHT, which is how a fix on
// three arms silently regresses on the fourth. With the arms named, an
// unlisted arm is asserted normally and a listed one still fails the day
// it agrees. The single-process PostgreSQL oracle ignores an entry whose
// pin does not name "single": that comparison is not the divergent path.
KnownBugArms []string
}
Case is one corpus entry. Want is the ROW LIST PostgreSQL 17 answers, rendered one string per row, in the entry's own ORDER when Ordered is set.
func Corpus ¶
func Corpus() []Case
Corpus is the shape list. Each entry names a way two relations that share a bare column name can be confused for one another.
func DuplicateNameCorpus ¶
func DuplicateNameCorpus() []Case
DuplicateNameCorpus is the part of this fixture whose answer cannot be read through a map keyed by column NAME, so it is kept apart from Corpus(): both of these project two columns called `c0`, and `map[string]any` holds one of them. That losing map is not an accident of the harness — it is the same mistake the ENGINE makes in #844, where a UNION ALL branch projecting two columns of one bare name binds the first to the LAST one's value. A gate that reads rows by name cannot tell the two apart, which is why these entries are gated POSITIONALLY (wadjet.QueryResult.Cells) instead.
Want here is one string per row, cells joined by "|", in the entry's own ORDER. Measured on live postgres:17-alpine.
type FixtureTable ¶
FixtureTable is one loadable table. Every consumer loads Tables(), so a relation cannot be added to the corpus and forgotten in one of the gates.