Merged PRs
dolt
- 11366: Include full table scan in index statistics
Have StatsController also create an "empty" statistic entry to indicate no index for costing. - 11365: Add dolt_squash_history procedure
This new procedure will take the content of HEAD, and squash history before it. Default behavior is to squash every commit from height 2 (commit right after initial commit) to HEAD. It is impossible to rewrite the initial commit.
This will be much faster than rebasing all history. - 11358: Fix left outer merge join wrong results with residual filters
Tests added in dolthub/go-mysql-server#3655
Fixes #11350
Based on #11351 - 11354: add missing execution call for
sqlparser.Executestatements
We were missing calls toiter.Next()anditer.Close(), when executing prepared statements throughdolt sql -q "...",
some tests in: dolthub/go-mysql-server#3653
fixes: #11345 - 11351: kvexec: fix left outer merge join wrong results with residual filters
Fixes #11350 — wrong results frommergeJoinKvIterfor left outer merge joins whose key runs contain duplicates and whose join condition carries a residual (non-merge-key) filter.
Two one-line-class defects, both in thematch:loop:l.matchedLeft = okoverwrote earlier successes. A left row that matched mid-run was re-flagged unmatched by a later failed pairing in the same run, so the run transition emitted a spurious null-extended row for it. Changed tol.matchedLeft = l.matchedLeft || ok; the run-transition reset remains the sole reset point.io.EOFduring the left advance dropped the final owed null-extension. Thecompare:loop handles left-EOF viaoldLeftKey; thematch:loop's advance branch returned the error immediately, losing the null-extended row for a final unmatched left row. Now it emits that row (whenisLeftJoin && !matchedLeft) before surfacing EOF.
Minimal repro (returnsfr:app|NULLinstead ofnl:app|NULLbefore this patch):
The regression test registers the kvexeccreate table b2 (cat varchar(50) not null, code varchar(16) not null, lang varchar(20) not null, primary key(cat, code, lang), key(code)); create table t2 (id varchar(36) primary key, code varchar(16), lang varchar(16), key(code, lang)); insert into b2 values ('cat0','P1','de:app'),('cat1','P1','fr:app'),('cat2','P1','nl:app'); insert into t2 values ('t1','P1','de'),('t2','P1','es'),('t3','P1','fr'); select /*+ MERGE_JOIN(p,w) */ p.lang, w.lang from b2 p left join t2 w on w.code = p.code and w.lang = substring_index(p.lang, ':', 1);
ExecBuilderon the test engine (as the CLI/server engines do) so the kvexec iterator — not the GMS fallback, which was already correct — is what's exercised; the new test fails 7 assertions without the fix and passes with it.kvexecsuite andenginetestTestJoinQueries/TestJoinOpspass. Also verified against a 15k-row synthetic (anti-join now agrees exactly withNOT EXISTS: 5,000) and the production database where this was found (197-row orphan audit no longer inflates to ~15k when the planner picks the merge join path).
🤖 Generated with Claude Code
https://claude.ai/code/session_01VpTxMfzCXHoM8ojJn5aQiv - 11344: Fail amend commits when branch head has moved
When a SQL transaction ranCALL DOLT_COMMIT('--amend')after another connection had added a commit or merged a branch, the amend silently replaced the transactionHEADcommit up to the newHEADcommit. The data from the erased commits survived, but the commit itself, including merge records we're gone.datas.CommitOptions.Amendis replaced withAmendedCommit(hash.Hash), the address of the commit an amend replaces.datas.BuildNewCommitrejects an amend unlessAmendedCommitis still the datasetHEAD, relying on theCAS inCommitWithWorkingSet` for atomic comparison.dsess.doCommitrunsvalidateAmendedHeadbefore the working set merge to specify the head conflict over a row conflict.- Amend is refused mid
merge,cherry-pick, in parity withgitandrevert, a Dolt-specific addition because it follows the same merge state. - The admin createchunk command's
HEADcheck bypass moves from theAmendflag to a new explicitCommitOptions.Forcefield.
Fix #9072
- 11343: Add retries to branch creation on ErrOptimisticLockFailed errors
Adds a retry loop toNewBranchAtCommitso branch creation can recover from a concurrent optimistic-lock conflict on the working set (e.g. from a background auto-GC cycle). This matches the existing retry behavior of other write paths (e.g. SQL transaction commit). - 11333: Bug fixes for secondary indexes using virtual columns
When a virtual generated column is used in a secondary index, rebuilding the index can generate incorrect index data in some situations. For example, dropping a column in the table will trigger a table rewrite as well a rebuilding the secondary indexes. In this case, the virtual generated column expressions were not properly being evaluated to store the correct data in the index.
go-mysql-server
-
3657: check stats prov for empty stat
Instead of creating the (potentially same) empty stat every time, we should check if it has already been made in the StatsProvider. -
3656: Bug fix for
CASEexpressions withExtendedTypeinstances
Related to: dolthub/doltgresql#2980
Doltgres fix: dolthub/doltgresql#2987 -
3653: adding prepare tests for insert and update
-
3652: Allow aliasing column names in a table function
Depends on: dolthub/vitess#477
-
3644: add ExtendedTableFunction interface to support table function schema …
…on OUT parameters -
3643: Use
buildScalarto getGetFieldexpression forON UPDATEcolumns
fixes #11346
Building theGetFieldexpression for a column using its index in a table was causing indexing issues when there was also a CTE. Instead, we need to build the theGetFieldusingbuildScalarto properly resolve the column within the scope. -
3641: Bug fix for a panic when calling a stored procedure without a database selected
-
3639: have coster consider not picking secondary indexes
This PR adds a "no index" option to the coster and some additional heuristics for index costing.
Before, we would always pick any available index, which would sometimes be sub-optimal, especially if the index is a non-covering secondary index.
Additionally, thenormal_distandexp_disttables are now seeded to reduce random variability between test runs.
Benchmarks:
#11336 (comment) -
3638: Bug fixes for secondary indexes using virtual columns
When updating a row in a secondary index, any virtual generated columns need their generation expression evaluated to get the correct data stored in the secondary index. There were a few edge case with virtual columns and secondary indexes where this evaluation wasn't happening. This PR closes those gaps.
The first case is when a table rewrite is performed and secondary indexes are rebuilt (e.g. when dropping a column on a table). Not properly evaluating a virtual column's expression caused incorrect data to be stored in the index when it was rebuilt.
A second case is for referential actions on a foreign key that update a table and its secondary index. Not properly evaluating a virtual column's expression here can also cause incorrect data to be written to the secondary index.
Fix for failing Dolt CI integration test in: #11333 -
3634: Add support for multiple expressions in functional indexes
-
3623: memory: use stable sort for secondary index ordering
memory.TableData.sortSecondaryIndexessorted secondary index storage withsort.Slice, which uses Go's unstable pdqsort algorithm. Rows that tie on the indexed columns (same key, different primary key) could be reordered relative to each other on every sort, so repeated index rebuilds of the same data could produce different physical row orders.
This PR switches tosort.SliceStable, which preserves the relative (insertion) order of tied rows, making secondary index storage ordering deterministic across rebuilds.
Fixes #2877 -
3618: Error on SELECT @@SESSION., matching MySQL
GMS silently returned the global value when a GLOBAL-only system variable was read with an explicitly-qualified SESSION/LOCAL scope (e.g.SELECT @@SESSION.innodb_autoinc_lock_mode), instead of raising MySQL's ERROR 1238 (ErrSystemVariableGlobalOnly).
buildSysVar's case forSetScope_None/SetScope_Sessionalready carriesspecifiedScope, which is empty for a bare@@fooreference and non-empty ("session"/"local") only when the scope was explicitly written in the query. This change uses that existing signal to raiseErrSystemVariableGlobalOnlywhen a global-only variable's scope is explicitly specified as session/local, while leaving the bare@@foofallback-to-global behavior untouched (MySQL allows that case).
Also un-skips a pre-existing enginetest case invariable_queries.gothat already asserted this exact error — the test was written in anticipation of this fix (Skip: true) and now passes.
Fixes #6722 -
3584: Add LockSubsystem.TryLock for non-blocking lock acquisition
Extract the single CAS attempt from Lock into a private tryLock helper and expose it as a public TryLock method that returns immediately if the lock is held by another session.
Callers no longer need to pass a short timeout to Lock and treat ErrLockTimeout as a false return. Referenced by a TODO in dolthub/doltgresql.
vitess
- 477: Adding
Columnsfield toTableFuncExpr
Allows aliasing columns from a table function.
Needed primarily for Doltgres, which supports more expressive table functions than MySQL. - 476: Small fixes for functional indexes
- adds test coverage for multi column function indexes
- fixes Walk() to walk index fields
- 474: go/mysql: add Conn.WaitForClientActivity to detect a departed client
On context cancelation, the function returns with anilerror. If the client unexpectedly writes to the connection or closes it, then this method will return a non-nilerror.
Unlike the first attempt at this method, this new implementation accounts for LoadDataInFile. It uses a preempt-able read lease to let the handler read from the client socket even while WaitForClientActivity is outstanding. The Peek becomes active once again after the reads are issued and completed.
Closed Issues
- 11350: kvexec: left outer merge join with residual filter emits spurious null-extended rows and drops final unmatched left row (wrong anti-join results)
- 11345: dolt sql -q/-f: EXECUTE of a prepared DML statement (UPDATE/INSERT) silently applies nothing
- 11087: Optimize Git remote backend object reads to avoid many git cat-file subprocesses
- 11346: WITH ... UPDATE fails with 'attempted to write non-string value to string field' when the table has ON UPDATE CURRENT_TIMESTAMP
- 11317: panic: index out of range in prolly index writer during ON DELETE CASCADE on a table with an indexed generated column (2.2.0)
- 6722: Dolt differs from MySQL on allowing query global only system variable with session scope
- 2877: MemoryDB: Building non-unique indexes is nondeterministic