Skip to content

Commit 418b576

Browse files
committed
Strip psql meta-commands from schema files (fixes #4065)
pg_dump 17.6+ (backported to 13.22, 14.19, 15.14, 16.10) emits \restrict/\unrestrict meta-commands that are valid psql syntax but not valid SQL, causing sqlc to fail when parsing schema.sql from pg_dump. Add a regex-based preprocessor in the migrations package that strips any line starting with a psql meta-command (\<command>), and call it from parseCatalog after RemoveRollbackStatements. Extend the pg_dump end-to-end schema fixture with \restrict/\unrestrict lines so TestReplay exercises this path.
1 parent 3e9e3d4 commit 418b576

File tree

4 files changed

+45
-0
lines changed

4 files changed

+45
-0
lines changed

internal/compiler/compile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func (c *Compiler) parseCatalog(schemas []string) error {
3939
continue
4040
}
4141
contents := migrations.RemoveRollbackStatements(string(blob))
42+
contents = migrations.RemovePsqlMetaCommands(contents)
4243
c.schema = append(c.schema, contents)
4344

4445
// In database-only mode, we parse the schema to validate syntax

internal/endtoend/testdata/pg_dump/schema.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
-- Dumped from database version 15.3 (Debian 15.3-1.pgdg120+1)
66
-- Dumped by pg_dump version 15.3
77

8+
\restrict auwherpfqaiuwrhgp
9+
810
SET statement_timeout = 0;
911
SET lock_timeout = 0;
1012
SET idle_in_transaction_session_timeout = 0;
@@ -83,6 +85,8 @@ ALTER TABLE ONLY public.authors
8385
ADD CONSTRAINT authors_pkey PRIMARY KEY (id);
8486

8587

88+
\unrestrict auwherpfqaiuwrhgp
89+
8690
--
8791
-- PostgreSQL database dump complete
8892
--

internal/migrations/migrations.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@ package migrations
22

33
import (
44
"bufio"
5+
"regexp"
56
"strings"
67
)
78

9+
// psqlMetaCommand matches a psql meta-command (a line that begins with a
10+
// backslash followed by a command name). pg_dump emits these starting with
11+
// PostgreSQL 17.6 / 16.10 / 15.14 / 14.19 / 13.22 (e.g. `\restrict KEY` and
12+
// `\unrestrict KEY`), and sqlc's SQL parsers cannot handle them.
13+
var psqlMetaCommand = regexp.MustCompile(`^\\[A-Za-z!?;][^\n]*$`)
14+
815
// Remove all lines after a rollback comment.
916
//
1017
// goose: -- +goose Down
@@ -33,6 +40,22 @@ func RemoveRollbackStatements(contents string) string {
3340
return strings.Join(lines, "\n")
3441
}
3542

43+
// RemovePsqlMetaCommands strips psql meta-command lines (e.g. `\restrict KEY`,
44+
// `\unrestrict KEY`, `\connect foo`) from SQL input. These are emitted by
45+
// pg_dump but are not valid SQL, so they must be removed before parsing.
46+
func RemovePsqlMetaCommands(contents string) string {
47+
s := bufio.NewScanner(strings.NewReader(contents))
48+
var lines []string
49+
for s.Scan() {
50+
line := s.Text()
51+
if psqlMetaCommand.MatchString(line) {
52+
continue
53+
}
54+
lines = append(lines, line)
55+
}
56+
return strings.Join(lines, "\n")
57+
}
58+
3659
func IsDown(filename string) bool {
3760
// Remove golang-migrate rollback files.
3861
return strings.HasSuffix(filename, ".down.sql")

internal/migrations/migrations_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ const outputDbmate = `
5656
-- migrate:up
5757
CREATE TABLE foo (bar int);`
5858

59+
const inputPsqlMeta = `\restrict auwherpfqaiuwrhgp
60+
61+
CREATE TABLE foo (id int);
62+
63+
\unrestrict auwherpfqaiuwrhgp
64+
`
65+
66+
const outputPsqlMeta = `
67+
CREATE TABLE foo (id int);
68+
`
69+
5970
func TestRemoveRollback(t *testing.T) {
6071
if diff := cmp.Diff(outputGoose, RemoveRollbackStatements(inputGoose)); diff != "" {
6172
t.Errorf("goose migration mismatch:\n%s", diff)
@@ -71,6 +82,12 @@ func TestRemoveRollback(t *testing.T) {
7182
}
7283
}
7384

85+
func TestRemovePsqlMetaCommands(t *testing.T) {
86+
if diff := cmp.Diff(outputPsqlMeta, RemovePsqlMetaCommands(inputPsqlMeta)); diff != "" {
87+
t.Errorf("psql meta-command mismatch:\n%s", diff)
88+
}
89+
}
90+
7491
func TestRemoveGolangMigrateRollback(t *testing.T) {
7592
filenames := map[string]bool{
7693
// make sure we let through golang-migrate files that aren't rollbacks

0 commit comments

Comments
 (0)