Skip to content

test insert rules - #3017

Closed
jycor wants to merge 1 commit into
mainfrom
james/insert
Closed

test insert rules#3017
jycor wants to merge 1 commit into
mainfrom
james/insert

Conversation

@jycor

@jycor jycor commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
Main PR
covering_index_scan_postgres 1992.26/s 1980.44/s -0.6%
groupby_scan_postgres 140.47/s 140.97/s +0.3%
index_join_postgres 661.04/s 655.77/s -0.8%
index_join_scan_postgres 826.01/s 826.19/s 0.0%
index_scan_postgres 31.99/s 32.13/s +0.4%
oltp_delete_insert_postgres 758.60/s 777.48/s +2.4%
oltp_insert 664.16/s 698.48/s +5.1%
oltp_point_select 3331.11/s 3325.72/s -0.2%
oltp_read_only 3332.70/s 3298.06/s -1.1%
oltp_read_write 2503.86/s 2489.47/s -0.6%
oltp_update_index 719.37/s 716.05/s -0.5%
oltp_update_non_index 750.95/s 743.34/s -1.1%
oltp_write_only 1758.63/s 1795.20/s +2.0%
select_random_points 2072.31/s 2059.08/s -0.7%
select_random_ranges 1531.96/s 1524.71/s -0.5%
table_scan_postgres 31.53/s 31.43/s -0.4%
types_delete_insert_postgres 748.00/s 803.74/s +7.4%
types_table_scan_postgres 14.28/s 14.24/s -0.3%

@itoqa

itoqa Bot commented Aug 3, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: 81df585: 15 test cases ran, 13 passed ✅, 2 additional findings ⚠️.

Summary

The run covers core data-entry behavior across successful inserts, generated and default values, bound inputs, returned results, conflict handling, validation errors, and atomicity under failed batches and retries. It also checks persistence across connections and runtime readiness, while exposing deployment-toolchain compatibility issues in source-based container builds.

Safe to merge — the application behavior exercised by this PR passed without regressions or PR-attributable failures. The Docker source-build failures are unrelated pre-existing toolchain issues and should be flagged for follow-up rather than treated as merge blockers.

Tests run by Ito

View full run

Result Severity Type Description
Constraint Trying to insert a second row with the same primary key returned a controlled error. The original value stayed unchanged and the table still had one row.
Constraint Invalid CHECK and NOT NULL inserts were rejected, while a valid row was saved with the default status of ready.
Constraint The failed multi-row insert left only the original row, and a later valid insert added row 4 successfully.
Constraint The database rejected the mixed insert without saving either valid row. After the conflicting value was corrected, the retry saved exactly rows 2, 5, and 3 alongside the original row.
Constraint The qualified insert ignored the duplicate in schema_c5_a, added the new row there, and left the same-named table in schema_c5_b unchanged.
Insert Explicit values stayed in their named columns, DEFAULT produced NULL, and DEFAULT VALUES stored 123 and 456 with the expected integer and text types.
Insert Serial columns returned 1, 2, and 3, while the UUID default returned the expected UUID for every inserted row. The returned IDs matched the stored rows and had the expected integer and UUID types.
Insert The prepared insert returned id 42 and both text values, and the same values were stored in the table. Bound placeholders were handled as values rather than literal text.
Insert A duplicate row was updated as requested, and a later duplicate was ignored without creating another row.
Insert Inserting into both tables returned the expected columns, labels, defaults, arithmetic results, and uppercase names. The saved rows matched the values returned by the database.
Insert Invalid column and function names returned controlled SQL errors, and the table stayed unchanged. A later query still worked normally.
Runtime The clean module download completed, and the full INSERT test suite compiled and passed. Inserts, conflict handling, defaults, returned values, data types, and timestamp values all matched the expected results.
Runtime The server started on the local database port, accepted an INSERT with a default value, and returned the saved row with the expected values and types on a new connection.
⚠️ High severity Runtime The clean Docker build could not download the project dependencies, so it never compiled the application or ran the INSERT tests.
⚠️ Medium severity Runtime The source Docker image could not be built, so it did not produce the server binary needed by the final image.
Additional Findings Details

These findings are unrelated to the current changes but were observed during testing.

🟠 Clean Docker builds cannot resolve dependencies
  • Severity: High High severity
  • Description: The clean Docker build could not download the project dependencies, so it never compiled the application or ran the INSERT tests.
  • Impact: A clean Docker build cannot create the application image because its Go version is too old for the project. Deployments that rely on this build path are blocked until the image toolchain is updated.
  • Steps to Reproduce:
    1. Use the repository as the source mounted at /src in a fresh golang:1.25-trixie container.
    2. Set GOTOOLCHAIN=local and use an empty Go module cache.
    3. Run go version and go mod download from the repository root.
    4. Observe that Go 1.25.12 rejects the module before go test can run with: go.mod requires go >= 1.26.2.
  • Stub / mock content: No stubs, mocks, or bypasses were applied for this test in the recorded run.
  • Code Analysis: Dockerfile:12 defines the source-build stage as FROM golang:1.25-trixie. In the recorded container this resolves to Go 1.25.12, and the clean-module evidence shows GOTOOLCHAIN=local, so Go cannot select a newer toolchain automatically. The module declaration at go.mod:3 requires go 1.26.2; consequently, Dockerfile:20-24 fails at go mod download before parser generation, binary compilation, or the doltgres move can occur. The PR context shows only a one-line dependency-version change in go.mod and matching checksum changes in go.sum; it contains no Dockerfile or toolchain change. The smallest practical fix is to update Dockerfile:12 to a Go image at least as new as 1.26.2, or lower the module requirement only if the source is actually compatible with that older toolchain.
Evidence Package
🟡 Docker source build cannot create the binary
  • Severity: Medium Medium severity
  • Description: The source Docker image could not be built, so it did not produce the server binary needed by the final image.
  • Impact: Operators cannot build the service Docker image from source, so source-based deployments cannot start until the build image uses a compatible Go version.
  • Steps to Reproduce:
    1. Run docker build --no-cache --build-arg DOLTGRES_VERSION=source --target runtime -t doltgresql-runtime:source . from the repository root.
    2. Let the source-build stage use its configured Go image.
    3. Observe that dependency resolution stops because the installed Go version is older than the module requirement.
    4. Observe that the later binary move also fails because no server binary was produced.
  • Stub / mock content: No stubs, mocks, or bypasses were applied for this test in the recorded run.
  • Code Analysis: /tmp/output-agent-workspace/repo/go.mod:3 declares go 1.26.2. /tmp/output-agent-workspace/repo/Dockerfile:12 selects golang:1.25-trixie for the build-from-source stage, which supplies Go 1.25.12. The source command at /tmp/output-agent-workspace/repo/Dockerfile:20-24 runs go mod download, then builds binaries and moves out/doltgresql-*/bin/doltgres; with GOTOOLCHAIN=local, Go 1.25.12 rejects the module before those build steps can run, producing go: go.mod requires go >= 1.26.2. The recorded build then reports mv: cannot stat 'out/doltgresql-*/bin/doltgres'. The smallest practical fix is to update the Dockerfile source-stage image to a Go release that satisfies go.mod (at least 1.26.2), or otherwise keep the module requirement and build image on the same supported version.
Evidence Package

Tip

Reply with @itoqa to send us feedback on this test run.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
Main PR
Total 42090 42090
Successful 18869 18867
Failures 23221 23223
Partial Successes1 5326 5326
Main PR
Successful 44.8301% 44.8254%
Failures 55.1699% 55.1746%

${\color{red}Regressions (2)}$

subselect

QUERY:          insert into upsert values(1, 'val') on conflict (key) do update set val = 'seen with subselect ' || (select f1 from int4_tbl where f1 != 0 limit 1)::text;
RECEIVED ERROR: attempted to evaluate uninitialized subquery
QUERY:          select count(*) from tenk1 t
where (exists(select 1 from tenk1 k where k.unique1 = t.unique2) or ten < 0);
RECEIVED ERROR: timeout during Receive

Footnotes

  1. These are tests that we're marking as Successful, however they do not match the expected output in some way. This is due to small differences, such as different wording on the error messages, or the column names being incorrect while the data itself is correct.

@itoqa

itoqa Bot commented Aug 3, 2026

Copy link
Copy Markdown

Ito QA test results

History reset (rebase or force-push detected). Starting test narrative over.

Commit: 2f3a905: 13 test cases ran, 2 failed ❌, 9 passed ✅, 2 additional findings ⚠️.

Summary

Coverage spans normal and prepared inserts, returned and default-generated values, bulk loading, conflict handling, and edge cases involving invalid data and partition boundaries. Happy-path behavior generally works, but partitioned-table validation and routing show serious integrity failures under invalid or boundary inputs.

Not safe to merge yet — this PR is associated with high-severity partitioning failures that accept invalid values and leave parent and child data inconsistent, creating a risk of silent data corruption. Separate conflict-update and bulk-load validation issues are also present but are unrelated to this PR and should be treated as follow-up caveats.

Tests run by Ito

View full run

Result Severity Type Description
High severity Insert The valid rows were accepted, but the invalid inserts also returned success. The first child stored b=11, the second child stayed empty, and the parent count did not match the expected partition routing; invalid rows should have been rejected without being committed.
High severity Insert The boundary inserts returned success, the parent reported three rows, and both attached child tables reported zero rows. The out-of-range value k=20 was accepted, while the CHECK constraint error appeared only during cleanup instead of rejecting the insert atomically.
Conflict The recorded command used SQL PREPARE, which is intentionally unsupported. The repository's supported prepared-statement path uses the PostgreSQL extended query protocol and bind variables.
Copy Loading four valid text rows succeeds, and all four rows are saved with the expected numbers, text, and null value.
Engine A normal INSERT returned its completion message, while INSERT with RETURNING returned the inserted row. Both rows were saved and could be read back.
Engine A prepared insert reported four stable parameter types, returned the expected mixed values, and saved the row correctly.
Engine An unsupported value was rejected with a clear error, no partial row was saved, and a valid insert worked afterward on the same connection.
Engine The new dependency version resolved with matching checksums, the server compiled, and a clean local start accepted a table creation and insert.
Engine The prepared insert kept stable parameter types, rejected the invalid value without damaging the statement, and accepted a valid retry. Both valid rows were saved.
Insert Typed values were converted to the destination column types, default values were filled in, and the expected two rows were committed.
Insert INSERT RETURNING returned the generated serial number, UUID, and default text values. Reading the rows back with those returned values found the same committed data.
⚠️ High severity Conflict The existing row was created, but the conflict update returned table not found: excluded. The row was not updated with amount 42 and label after.
⚠️ Medium severity Copy The oversized payload was accepted and stored as 'this_pay'. The COPY command reported success and committed all three rows instead of returning a bounded-length error and rejecting the load.
Additional Findings Details

These findings are unrelated to the current changes but were observed during testing.

🟠 Conflict updates reject incoming row values
  • Severity: High High severity
  • Description: The existing row was created, but the conflict update returned table not found: excluded. The row was not updated with amount 42 and label after.
  • Impact: Users cannot update an existing row through the standard conflict-update workflow. The write fails instead of applying the incoming values, so callers need a separate update path to complete the change.
  • Steps to Reproduce:
    1. Create a table with an integer primary key and amount and label columns.
    2. Insert one row with id 7, amount 10, and label before.
    3. Run an INSERT for id 7 with amount 42 and label after, followed by ON CONFLICT (id) DO UPDATE SET amount = EXCLUDED.amount, label = EXCLUDED.label.
    4. Observe the table-not-found error instead of an updated row.
  • Stub / mock content: No stubs, mocks, or bypasses were applied for this test in the recorded run.
  • Code Analysis: The PostgreSQL AST conversion in repo/server/ast/insert.go:45-56 accepts a supported ON CONFLICT clause, converts its update expressions with nodeUpdateExprs, and places them into the Vitess/GMS OnDup list. That path preserves EXCLUDED.amount and EXCLUDED.label as expressions rather than rejecting the statement. The PostgreSQL parser model in repo/postgres/parser/sem/tree/insert.go:100-112 explicitly represents the conflict update expressions, so the syntax is part of the supported statement model. During analyzer processing, repo/server/analyzer/assign_insert_casts.go:113-126 calls assignUpdateFieldCasts for those conflict expressions and replaces the InsertInto expressions with the casted expressions. The observed error means the downstream execution plan cannot resolve the EXCLUDED relation when evaluating the preserved expressions; this is consistent with a production defect in the ON CONFLICT expression/planner integration, not a malformed test statement. The smallest practical fix is to preserve or restore the executor's EXCLUDED row-scope when constructing the OnDup plan, and add a regression assertion for EXCLUDED column references; do not broadly rewrite unrelated insert handling. The PR context changes only go.mod:9 and go.sum dependency checksums, so there is no sufficient changed-line proof that this PR introduced the behavior.
Evidence Package
🟡 Oversized text is silently shortened
  • Severity: Medium Medium severity
  • Description: The oversized payload was accepted and stored as 'this_pay'. The COPY command reported success and committed all three rows instead of returning a bounded-length error and rejecting the load.
  • Impact: Bulk imports can silently change customer data when a value is longer than its column limit. Users may not notice the loss unless they compare the saved value with the source.
  • Steps to Reproduce:
    1. Create a table with an integer key and a payload column defined as VARCHAR(8).
    2. Start COPY FROM STDIN in text mode and send valid rows followed by a payload longer than eight characters, such as this_payload.
    3. Finish the COPY and query the table for the inserted rows.
    4. Compare the stored payload with the value that was sent.
    5. Repeat with an invalid integer row to confirm that ordinary typed validation still rejects that case and leaves zero rows committed.
  • Stub / mock content: The run used a local Doltgres server and a local PostgreSQL connection. The test harness applied a local trust-authentication bypass; no external service mocks or production data were used.
  • Code Analysis: The repository defines VARCHAR length as a type modifier in server/types/varchar.go:78-86 and exposes the declared character limit through Length at server/types/type.go:773-781. The normal VARCHAR input function in server/functions/varchar.go:44-57 calculates the limit from the type modifier and returns an error when the input has more characters than allowed. The cast path applies the same rule in server/cast/utils.go:60-69: it retains the original value for error handling and returns an out-of-range error when runeLength exceeds the target limit. The recorded COPY path instead committed 'this_pay' from 'this_payload' without an error, which is inconsistent with both production validation paths and demonstrates that COPY materialization is bypassing or discarding the bounded-VARCHAR validation. The smallest practical fix is to route COPY field conversion through the target column's VARCHAR input/cast validation and propagate its error before committing any rows; do not truncate the value as a successful conversion.
Evidence Package

Tip

Reply with @itoqa to send us feedback on this test run.

Comment thread go.mod Outdated
github.com/dolthub/eventsapi_schema v0.0.0-20260715220557-d9b4a1c6b4d4
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2
github.com/dolthub/go-mysql-server v0.20.1-0.20260803203407-e49664d6062c
github.com/dolthub/go-mysql-server v0.20.1-0.20260803232249-e787bab6e784

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View All Evidence

High severity Invalid rows enter wrong partitions

What failed: The valid rows were accepted, but the invalid inserts also returned success. The first child stored b=11, the second child stayed empty, and the parent count did not match the expected partition routing; invalid rows should have been rejected without being committed.

Impact · Steps · Stub / mock · Analysis · Why this is likely a bug
  • Severity: High High severity
  • Impact: Users can insert rows outside a partition's allowed range, and those rows may be stored in the wrong partition. This can silently corrupt partitioned data and produce incorrect query results.
  • Steps to Reproduce:
    1. Create a range-partitioned table with a child covering ('a', 1) through ('a', 10) and a second child covering ('a', 10) through ('a', 20).
    2. Insert one valid row directly into the first child and one valid row through the parent table.
    3. Insert ('a', 11) directly into the first child and try out-of-range values through the parent table.
    4. Query both child tables and the parent table, then compare the stored rows and counts with the insert results.
  • Stub / mock content: The test used a local-only partition fixture and equivalent ATTACH PARTITION syntax because the original PARTITION OF and CASCADE setup syntax was unsupported; no mocks or route interception were used.
  • Code Analysis: The regression fixture at testing/go/regression/tests/insert.sql:110-133 explicitly requires direct child inserts outside a child's range to fail, including INSERT INTO part1 VALUES ('a', 11), and requires only in-range values to succeed. The test plan at testing/go/regression/tests/insert.sql:195-203 also expects parent inserts outside the configured ranges to be rejected. In the local application, server/ast/insert.go:61-75 resolves the target table, server/ast/insert.go:76-91 converts the columns and source rows, and server/ast/insert.go:109-123 constructs the vitess INSERT passed to the execution engine; this path does not implement an alternate partition router or bound validator that could explain the observed behavior. The runtime accepted all four probes and persisted b=11 in child1 while child2 remained empty, which is consistent with the pinned execution engine failing to enforce the partition metadata. The PR diff changes go.mod line 12 from go-mysql-server pseudo-version e49664d6062c to e787bab6e784, and changes go.sum to match. The smallest practical fix is to correct or revert that dependency version to one that enforces partition bounds and routes rows correctly, or apply the upstream partition-bound fix before updating the pin; do not accept successful INSERT results until the target child and range constraint have been validated.
  • Why this is likely a bug: This is not only a failed assertion or an unsupported fixture: the equivalent local ATTACH PARTITION setup succeeded, valid inserts worked, and the same execution accepted an out-of-range row and stored it in a child whose declared range excludes it. That creates silently incorrect partitioned data and contradicts the repository's explicit PostgreSQL regression expectations. The AST conversion preserves the requested target and values, so the evidence points to the execution-engine version selected by the PR rather than browser rendering or a test-only patch. A targeted dependency correction or upstream partition-enforcement fix addresses the observed defect without requiring a broad rewrite.
Relevant code

testing/go/regression/tests/insert.sql:110-133

-- direct partition inserts should check partition bound constraint
create table range_parted (
	a text,
	b int
) partition by range (a, (b+0));
create table part1 partition of range_parted for values from ('a', 1) to ('a', 10);
create table part2 partition of range_parted for values from ('a', 10) to ('a', 20);
-- fail
insert into part1 values ('a', 11);
insert into part1 values ('b', 1);
-- ok
insert into part1 values ('a', 1);

server/ast/insert.go:61-123

switch node := node.Table.(type) {
case *tree.TableName:
	tableName, err = nodeTableName(ctx, node)
...
rows, err = nodeSelect(ctx, node.Rows)
...
return &vitess.Insert{
	Action: vitess.InsertStr,
	Table: tableName,
	Columns: columns,
	Rows: rows,
}, nil

go.mod:12

github.com/dolthub/go-mysql-server v0.20.1-0.20260803232249-e787bab6e784
Evidence Package
Copy prompt for an agent
Ito QA identified the following failure during automated PR testing. Please investigate and propose a fix.

**High severity — Invalid rows enter wrong partitions**

**What failed:** The valid rows were accepted, but the invalid inserts also returned success. The first child stored b=11, the second child stayed empty, and the parent count did not match the expected partition routing; invalid rows should have been rejected without being committed.

- **Impact:** Users can insert rows outside a partition's allowed range, and those rows may be stored in the wrong partition. This can silently corrupt partitioned data and produce incorrect query results.
- **Steps to reproduce:**
  1. Create a range-partitioned table with a child covering ('a', 1) through ('a', 10) and a second child covering ('a', 10) through ('a', 20).
  2. Insert one valid row directly into the first child and one valid row through the parent table.
  3. Insert ('a', 11) directly into the first child and try out-of-range values through the parent table.
  4. Query both child tables and the parent table, then compare the stored rows and counts with the insert results.
- **Stub / mock content:** The test used a local-only partition fixture and equivalent ATTACH PARTITION syntax because the original PARTITION OF and CASCADE setup syntax was unsupported; no mocks or route interception were used.
- **Code analysis:** The regression fixture at testing/go/regression/tests/insert.sql:110-133 explicitly requires direct child inserts outside a child's range to fail, including INSERT INTO part1 VALUES ('a', 11), and requires only in-range values to succeed. The test plan at testing/go/regression/tests/insert.sql:195-203 also expects parent inserts outside the configured ranges to be rejected. In the local application, server/ast/insert.go:61-75 resolves the target table, server/ast/insert.go:76-91 converts the columns and source rows, and server/ast/insert.go:109-123 constructs the vitess INSERT passed to the execution engine; this path does not implement an alternate partition router or bound validator that could explain the observed behavior. The runtime accepted all four probes and persisted b=11 in child1 while child2 remained empty, which is consistent with the pinned execution engine failing to enforce the partition metadata. The PR diff changes go.mod line 12 from go-mysql-server pseudo-version e49664d6062c to e787bab6e784, and changes go.sum to match. The smallest practical fix is to correct or revert that dependency version to one that enforces partition bounds and routes rows correctly, or apply the upstream partition-bound fix before updating the pin; do not accept successful INSERT results until the target child and range constraint have been validated.
- **Why this is likely a bug:** This is not only a failed assertion or an unsupported fixture: the equivalent local ATTACH PARTITION setup succeeded, valid inserts worked, and the same execution accepted an out-of-range row and stored it in a child whose declared range excludes it. That creates silently incorrect partitioned data and contradicts the repository's explicit PostgreSQL regression expectations. The AST conversion preserves the requested target and values, so the evidence points to the execution-engine version selected by the PR rather than browser rendering or a test-only patch. A targeted dependency correction or upstream partition-enforcement fix addresses the observed defect without requiring a broad rewrite.

**Relevant code:**

`testing/go/regression/tests/insert.sql:110-133`

~~~sql
-- direct partition inserts should check partition bound constraint
create table range_parted (
	a text,
	b int
) partition by range (a, (b+0));
create table part1 partition of range_parted for values from ('a', 1) to ('a', 10);
create table part2 partition of range_parted for values from ('a', 10) to ('a', 20);
-- fail
insert into part1 values ('a', 11);
insert into part1 values ('b', 1);
-- ok
insert into part1 values ('a', 1);
~~~

`server/ast/insert.go:61-123`

~~~go
switch node := node.Table.(type) {
case *tree.TableName:
	tableName, err = nodeTableName(ctx, node)
...
rows, err = nodeSelect(ctx, node.Rows)
...
return &vitess.Insert{
	Action: vitess.InsertStr,
	Table: tableName,
	Columns: columns,
	Rows: rows,
}, nil
~~~

`go.mod:12`

~~~mod
github.com/dolthub/go-mysql-server v0.20.1-0.20260803232249-e787bab6e784
~~~

Comment thread go.mod Outdated
github.com/dolthub/eventsapi_schema v0.0.0-20260715220557-d9b4a1c6b4d4
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2
github.com/dolthub/go-mysql-server v0.20.1-0.20260803203407-e49664d6062c
github.com/dolthub/go-mysql-server v0.20.1-0.20260803232249-e787bab6e784

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View All Evidence

High severity Invalid partition values are accepted

What failed: The boundary inserts returned success, the parent reported three rows, and both attached child tables reported zero rows. The out-of-range value k=20 was accepted, while the CHECK constraint error appeared only during cleanup instead of rejecting the insert atomically.

Impact · Steps · Stub / mock · Analysis · Why this is likely a bug
  • Severity: High High severity
  • Impact: Partitioned tables can accept invalid inserts and leave rows or counts out of sync. This can silently corrupt stored data and make later queries return incomplete or incorrect results.
  • Steps to Reproduce:
    1. Create a partitioned parent table with adjacent child ranges and a constraint-bearing column.
    2. Insert valid boundary values and an out-of-range value through the parent table.
    3. Query the parent and each child table and compare the reported insert counts with the stored rows.
    4. Check whether the invalid insert fails immediately and leaves the transaction and table contents unchanged.
  • Stub / mock content: The test used a local Doltgres instance and an equivalent ALTER TABLE ATTACH PARTITION setup because the original PARTITION OF syntax was unsupported; no application behavior was mocked or bypassed.
  • Code Analysis: The regression fixture in testing/go/regression/tests/insert.sql:195-221 defines the expected partition behavior: values inside adjacent ranges must route to the proper child, an out-of-range value must fail, and no inconsistent row or count may remain. The local INSERT translator in server/ast/insert.go:61-123 resolves the target table, converts the input rows, and passes the original target and rows into vitess.Insert; it contains no alternative routing or constraint bypass that could explain the mismatch. Therefore the observed acceptance and parent/child divergence occur in the execution engine selected by the module graph. This PR changes go.mod:12 from go-mysql-server e49664d6062c to e787bab6e784, and go.sum records the matching checksum, so the changed dependency selection is a direct practical cause of the behavior under test. The smallest fix is to revert or correct that go-mysql-server version until partition routing validates the child bounds before reporting success and preserves the insert atomically.
  • Why this is likely a bug: A successful INSERT must correspond to a row in the correct partition, and an out-of-range partition key must be rejected before it changes visible state. The recorded result violates both guarantees: the parent count increased without matching child rows, an invalid key was accepted, and constraint failure was deferred until cleanup. This is a production execution defect rather than a browser artifact because the SQL output directly records the command results and the source shows that Doltgres forwards the INSERT to the pinned engine. The dependency pin changed in this PR, so reverting that pin is a targeted mitigation; the engine should otherwise validate routing and child constraints before returning INSERT success.
Relevant code

testing/go/regression/tests/insert.sql:195-221

-- Check tuple routing for partitioned tables
-- fail
insert into range_parted values ('a', 0);
-- ok
insert into range_parted values ('a', 1);
insert into range_parted values ('a', 10);
-- fail
insert into range_parted values ('a', 20);
select tableoid::regclass, * from range_parted;

server/ast/insert.go:61-123

tableName, err = nodeTableName(ctx, node)
rows, err = nodeSelect(ctx, node.Rows)
return &vitess.Insert{
	Table: tableName,
	Columns: columns,
	Rows: rows,
}, nil

go.mod:12

github.com/dolthub/go-mysql-server v0.20.1-0.20260803232249-e787bab6e784
Evidence Package
Copy prompt for an agent
Ito QA identified the following failure during automated PR testing. Please investigate and propose a fix.

**High severity — Invalid partition values are accepted**

**What failed:** The boundary inserts returned success, the parent reported three rows, and both attached child tables reported zero rows. The out-of-range value k=20 was accepted, while the CHECK constraint error appeared only during cleanup instead of rejecting the insert atomically.

- **Impact:** Partitioned tables can accept invalid inserts and leave rows or counts out of sync. This can silently corrupt stored data and make later queries return incomplete or incorrect results.
- **Steps to reproduce:**
  1. Create a partitioned parent table with adjacent child ranges and a constraint-bearing column.
  2. Insert valid boundary values and an out-of-range value through the parent table.
  3. Query the parent and each child table and compare the reported insert counts with the stored rows.
  4. Check whether the invalid insert fails immediately and leaves the transaction and table contents unchanged.
- **Stub / mock content:** The test used a local Doltgres instance and an equivalent ALTER TABLE ATTACH PARTITION setup because the original PARTITION OF syntax was unsupported; no application behavior was mocked or bypassed.
- **Code analysis:** The regression fixture in testing/go/regression/tests/insert.sql:195-221 defines the expected partition behavior: values inside adjacent ranges must route to the proper child, an out-of-range value must fail, and no inconsistent row or count may remain. The local INSERT translator in server/ast/insert.go:61-123 resolves the target table, converts the input rows, and passes the original target and rows into vitess.Insert; it contains no alternative routing or constraint bypass that could explain the mismatch. Therefore the observed acceptance and parent/child divergence occur in the execution engine selected by the module graph. This PR changes go.mod:12 from go-mysql-server e49664d6062c to e787bab6e784, and go.sum records the matching checksum, so the changed dependency selection is a direct practical cause of the behavior under test. The smallest fix is to revert or correct that go-mysql-server version until partition routing validates the child bounds before reporting success and preserves the insert atomically.
- **Why this is likely a bug:** A successful INSERT must correspond to a row in the correct partition, and an out-of-range partition key must be rejected before it changes visible state. The recorded result violates both guarantees: the parent count increased without matching child rows, an invalid key was accepted, and constraint failure was deferred until cleanup. This is a production execution defect rather than a browser artifact because the SQL output directly records the command results and the source shows that Doltgres forwards the INSERT to the pinned engine. The dependency pin changed in this PR, so reverting that pin is a targeted mitigation; the engine should otherwise validate routing and child constraints before returning INSERT success.

**Relevant code:**

`testing/go/regression/tests/insert.sql:195-221`

~~~sql
-- Check tuple routing for partitioned tables
-- fail
insert into range_parted values ('a', 0);
-- ok
insert into range_parted values ('a', 1);
insert into range_parted values ('a', 10);
-- fail
insert into range_parted values ('a', 20);
select tableoid::regclass, * from range_parted;
~~~

`server/ast/insert.go:61-123`

~~~go
tableName, err = nodeTableName(ctx, node)
rows, err = nodeSelect(ctx, node.Rows)
return &vitess.Insert{
	Table: tableName,
	Columns: columns,
	Rows: rows,
}, nil
~~~

`go.mod:12`

~~~go
github.com/dolthub/go-mysql-server v0.20.1-0.20260803232249-e787bab6e784
~~~

@itoqa

itoqa Bot commented Aug 4, 2026

Copy link
Copy Markdown

Ito QA test results

History reset (rebase or force-push detected). Starting test narrative over.

Commit: b3601c6: 14 test cases ran, 14 passed ✅.

Summary

Coverage spans core database behavior, including schema changes and data updates, value and type preservation, error recovery, startup and restart behavior, persistence, connection readiness, database setup, and clean shutdown. It includes normal workflows plus edge cases around invalid input, delayed readiness, startup races, raw values, and protocol-level consistency.

Safe to merge — the exercised application behaviors all passed, with no regressions, new failures, or previously flagged failures attributable to this PR. There are no identified merge blockers from this run.

Tests run by Ito

View full run

Result Severity Type Description
Execution The server created a table, inserted and updated rows, and dropped a column successfully. The final query returned the expected two rows without stale schema or decoding errors.
Execution Domain, enum-array, built-in array, catalog, and NULL queries returned the expected values. An invalid integer cast produced a contained SQL error, and the same connection successfully ran typed queries afterward.
Execution Simple and prepared queries returned the same types, values, NULL result, and raw bytes. A failed cast did not affect the next valid query.
Harness The focused SQL checks ran on a temporary local server and returned the expected normalized rows without connection errors.
Harness Representative JSONB SQL scripts passed on temporary local database servers, and the harness selected the local connection path safely.
Harness The local database server accepted connections after startup delay, and the retry check completed within its bounded window without hanging.
Harness Raw SQL values, expected errors, and command results matched their checks on a temporary local database server.
Harness Creating and selecting databases worked across fresh local servers, including database options and quoted names. Connections closed cleanly without leaving partial database state.
Resolution The upgraded SQL engine resolved correctly, and all production and test packages compiled without errors.
Resolution The server started from a clean temporary data directory, accepted a local authenticated connection, returned the expected database and arithmetic result, and released port 5432 after shutdown.
Resolution The separately launched binary started on a free port, accepted the postgres login, returned the expected query result, and shut down cleanly.
Server A fresh data directory created the default postgres database and accepted an authenticated connection before the server reported readiness.
Server The server restarted with the same data directory, kept the existing database, and returned the saved row with ID 42.
Server Clients that connected during a fresh server startup received connection-refused errors instead of partial database responses. After startup finished, an authenticated query returned the complete default database catalog.

Tip

Reply with @itoqa to send us feedback on this test run.

@jycor jycor closed this Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant