Skip to content

fix(sqlparser): do not drop the statement after an empty StatementBegin block - #1164

Open
JayOfTheKeyboard wants to merge 1 commit into
pressly:mainfrom
JayOfTheKeyboard:fix/empty-statement-block
Open

JayOfTheKeyboard wants to merge 1 commit into
pressly:mainfrom
JayOfTheKeyboard:fix/empty-statement-block

Conversation

@JayOfTheKeyboard

Copy link
Copy Markdown

A StatementBegin/StatementEnd block that holds only comments makes the parser throw away the line that follows it. goose then applies the migration, records the version, and reports success:

-- +goose Up
-- +goose StatementBegin
-- CREATE FUNCTION placeholder: disabled for SQLite
-- +goose StatementEnd
CREATE TABLE users (id INTEGER PRIMARY KEY);

-- +goose Down
DROP TABLE users;
$ goose -dir m sqlite3 ./db.sqlite up
OK   00001_init.sql (19.53ms)
goose: successfully migrated database to version: 1

goose status shows 00001 as applied, but the only tables in the database are goose_db_version and sqlite_sequence. ParseSQLMigration returns [""] for the Up direction. If the next statement spans several lines, its first line is dropped and the rest is stored as a statement (["", "id INTEGER PRIMARY KEY\n);"]), which fails when run. The Down direction behaves the same way. Built from main at 2d285d2.

The check that skips comments and blank lines before a statement runs whenever the buffer is empty, and after an empty block that includes the -- +goose StatementEnd line itself. That line is skipped before the code that stores the block and moves the state back to gooseUp/gooseDown, so the parser stays in gooseStatementEndUp. In that state the next line is not written to the buffer, and an empty statement is stored in its place.

The comment check no longer applies to the -- +goose StatementEnd line, so the parser always leaves the block. A block with no SQL in it now produces no statement instead of "", which matches how comment-only text outside a block is already handled. Blocks that contain SQL, plain semicolon splitting and annotation parsing are unchanged.

valid-up/test10 is a new golden file where the CREATE TABLE after an empty block has to come through whole, and TestSplitStatements gains a case with an empty block in each direction. On the parent both fail: TestSplitStatements with incorrect number of up stmts. got 2 ([ id int NOT NULL\n);]), want 1, and TestValidUp/test10 with 2 statements parsed where 1 is expected. Never setting the new StatementEnd flag fails the down count (got 0), and restoring either append of an empty statement fails a count (got 2).

Ran locally on Go 1.27.3, linux/amd64: gofmt -s -l ., go vet ./... and go build ./... are clean. go test -race -count=1 over the make test-packages package list passes all 10 packages on both the parent and this branch. After make add-gowork, go test ./internal/testing/integration -run='^TestPostgres$|TestMySQL' (Docker) passes on both. I didn't run the ClickHouse, YDB, StarRocks, Spanner or Turso suites. With the CLI built from this branch, the migration above creates users, and down drops it.

…in block

When a StatementBegin/StatementEnd block holds only comments (or nothing),
the StatementEnd line reaches the parser with an empty buffer and is skipped
as an ordinary leading comment. The parser then stays in the StatementEnd
state, so the next line is discarded and an empty statement is stored in its
place. A migration such as

    -- +goose StatementBegin
    -- placeholder
    -- +goose StatementEnd
    CREATE TABLE users (id INTEGER PRIMARY KEY);

is applied and recorded without ever creating the table.

Never treat the StatementEnd line as a skippable comment, and do not store
an empty statement for a block that held no SQL.
JayOfTheKeyboard added a commit to JayOfTheKeyboard/JayOfTheKeyboard that referenced this pull request Nov 8, 2026
@mfridman

Copy link
Copy Markdown
Collaborator

Good find!

This branch has not been deployed

No deployments
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.

2 participants