Repository navigation
v0.8.23
Built against Mojo 1.0.0 (ed45d567).
A patch release with two things the front ends were turning down and one thing the execution engine was doing the long way round.
Added: a capturing group inside a lookaround keeps what it matched
str.extract(r"(?=(ab))a") answers the column ab now, and every other shape of a group written inside an assertion answers too. The refusal was in the compiler rather than in the machine, so the four methods that never ask for groups were answering the construct all along and str.extract was the one raising. The nested walk carries slots now, runs the body with a copy per thread, and writes the winner's copy back only once the body has matched, which is where the rule for a negative form comes from without a case for it. Which thread wins is picked the way the machine outside picks one, which is what (?=(ab)|(a))ab needs. Seven shapes went into the extract tests with every expectation read off a running CPython, the corpus gained twenty patterns, and all seven differentials are still at zero disagreements.
Added: AT on a table reads and prints, and lowering is what turns it down
SELECT a FROM t AT (VERSION => 42) asks for a table as of a version and AT (TIMESTAMP => ...) asks for it as of a moment. The transformer used to stop on both. It reads them now and the printer writes them back, and what turns them down is lowering, because what the clause asks for is a table the catalog has no way to hand back and not a spelling the parser cannot make sense of. What follows the arrow is a whole expression, so a call, a subquery, an arithmetic on a timestamp and a typed literal all go into the AST as the expressions they are. Eight more corpus statements make the round trip.
Changed: a group by on a text key keeps a group's ordinal across chunks
A streaming group by has had two routes for a while. One looks each chunk's keys up in a map that outlives the chunk, so a group keeps the ordinal it was first given. The other groups each chunk on its own and then stacks the running table on top of the chunk's table, groups the whole stack again, and gathers the key columns back out of it, which is a copy, a rehash and a regather of the entire running table once per chunk.
A text key took the second route, because the map stores a 64 bit hash and nothing else. That is exact for a fixed width key and is not exact for text, where two names longer than eight bytes can land on one hash. So the map keeps the bytes now: it copies a key the first time it sees one, into a builder it holds for the query, and a hash match is a candidate those bytes settle. The copy is one per group rather than one per row, and the builder is also the key column the operator hands out at the end, so the keys are stored once and not twice.
A count of rows is let through the value side of the gate as well, since it never reads a column, which is what count(*) group by url was failing over.
Measured on the ClickBench 1M set through the planner, CPU time per run, five runs a side and five rounds interleaved: q36 falls from 159 to 101 milliseconds, q12 from 26 to 15, q33 from 175 to 140, q13 from 33 to 27, q37 from 71 to 59 and q38 from 18 to 16. An int key does not move and neither does a query with no group by in it. A key of two columns still takes the stacking merge. All forty three ClickBench statements were run through both builds and agree on every row count, sum and hash.