// Date-truncation range rewrite: a WHERE conjunct of the shape// date(<var>.<key>) = <constant Date> tests day membership, which over an// epoch-millis integer column is exactly the half-open range// [day, day + 24h) on the RAW value. Rewriting the conjunct to two// property-vs-constant comparisons lets the pushdown machinery place and// batch-sweep them like any other integer filter, instead of evaluating a// temporal constructor per row -- the dominant filter shape in date-heavy// analytic queries. The rewrite fires on generic structure (a resolved// date() call over an integer-or-absent column against a constant Date),// never on query identity.
package execimport (chickpeas)// dateRangeRewrites counts fired rewrites -- the engagement oracle: a// date(prop) = const conjunct over an integer column must rewrite exactly// once (two range conjuncts replace it); 0 on a qualifying shape means// the rewrite is dead.var dateRangeRewrites int// disableDateRangeRewrite pins result identity in tests: the general// per-row evaluation must produce exactly the rows the rewrite does.var disableDateRangeRewrite bool// rewriteDateEqRanges maps each qualifying conjunct to its two range// conjuncts, leaving everything else untouched.func rewriteDateEqRanges( *eval.Ctx, []ast.Expr, map[string]int) []ast.Expr {ifdisableDateRangeRewrite {return } , := .G.(graph.Native)if ! {return } := .Snapshot() := make([]ast.Expr, 0, len())for , := range {if , , := dateEqRange(, , , ); { = append(, , )continue } = append(, ) }return}// dateEqRange matches date(<prop>) = <const Date> (either operand order)// and returns the equivalent raw-value range conjuncts. The property's// resolvable columns must read integer-or-absent -- an integer value// floors to the day exactly as the range tests it, an absent value nulls// out of both forms identically, and any other column type keeps the// general evaluation.func dateEqRange( *eval.Ctx, *chickpeas.Snapshot, ast.Expr, map[string]int) (, ast.Expr, bool) { , := .(*ast.Binary)if ! || .Op != ast.OpEq {returnnil, nil, false } , , := datePropAndConst(.LHS, .RHS)if ! { , , = datePropAndConst(.RHS, .LHS) }if ! || !i64OrAbsentColumns(, .Key) {returnnil, nil, false } , := compile.ConstValue(, , , )if ! {returnnil, nil, false } , , := .AsTemporal()if ! || != value.Date {returnnil, nil, false }// The constant must sit exactly at midnight: date() output always // does, but Date-kind values built by temporal arithmetic // (date(...) + duration({hours: 5})) need not -- and for those the // TRUE predicate is unsatisfiable (a truncated value never equals a // non-aligned one) while the range form would select a day of rows // starting at that time. Kind and constness both pass such a value; // only alignment catches it (rustychickpeas' eefe831 gate).if %eval.MSPerDay != 0 {returnnil, nil, false }dateRangeRewrites++return &ast.Binary{Op: ast.OpGte, LHS: , RHS: &ast.Lit{Value: ast.IntLit()}}, &ast.Binary{Op: ast.OpLt, LHS: , RHS: &ast.Lit{Value: ast.IntLit( + eval.MSPerDay)}},true}// datePropAndConst matches one operand orientation: a resolved date()// call over a bare property read, paired with the other side as the// constant candidate.func datePropAndConst(, ast.Expr) (*ast.Prop, ast.Expr, bool) { , := .(*ast.Func)if ! || .Distinct || .Star || len(.Args) != 1 {returnnil, nil, false }if , := eval.ResolveFuncOp(.Name); ! || != eval.FuncDate {returnnil, nil, false } , := .Args[0].(*ast.Prop)if ! {returnnil, nil, false }return , , true}// i64OrAbsentColumns reports whether every column that could serve a read// of key yields an integer or absent: a missing column reads absent for// every position, and an integer column is exactly the epoch-millis shape// date() floors. A float, boolean, or string column declines the rewrite.func i64OrAbsentColumns( *chickpeas.Snapshot, string) bool {if , := .ColIndexed(); && .Dtype() != chickpeas.DtypeI64 {returnfalse }if , := .RelColIndexed(); && .Dtype() != chickpeas.DtypeI64 {returnfalse }returntrue}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.