Skip to content

Commit 90c18bc

Browse files
authored
Fix views order in the pg_dump restore (#758)
1 parent 1e3e569 commit 90c18bc

5 files changed

Lines changed: 146 additions & 2 deletions

File tree

pkg/snapshot/generator/postgres/schema/pgdumprestore/snapshot_pg_dump_restore_generator.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ type dump struct {
7979
filtered []byte
8080
cleanupPart []byte
8181
indicesAndConstraints []byte
82+
views []byte
8283
sequences []string
8384
roles map[string]role
8485
eventTriggers []byte
@@ -247,9 +248,15 @@ func (s *SnapshotGenerator) CreateSnapshot(ctx context.Context, ss *snapshot.Sna
247248

248249
s.logger.Info("restoring schema indices and constraints", loglib.Fields{"schemaTables": ss.SchemaTables})
249250
if s.snapshotTracker != nil {
250-
return s.restoreIndicesWithTracking(ctx, dump.indicesAndConstraints)
251+
if err := s.restoreIndicesWithTracking(ctx, dump.indicesAndConstraints); err != nil {
252+
return err
253+
}
254+
} else if err := s.restoreDump(ctx, dump.indicesAndConstraints); err != nil {
255+
return err
251256
}
252-
return s.restoreDump(ctx, dump.indicesAndConstraints)
257+
258+
s.logger.Info("restoring views")
259+
return s.restoreDump(ctx, dump.views)
253260
}
254261

255262
func (s *SnapshotGenerator) Close() error {
@@ -297,6 +304,7 @@ func (s *SnapshotGenerator) dumpSchema(ctx context.Context, schemaTables map[str
297304

298305
s.dumpToFile(s.getDumpFileName("-filtered"), pgdumpOpts, parsedDump.filtered)
299306
s.dumpToFile(s.getDumpFileName("-indices-constraints"), pgdumpOpts, parsedDump.indicesAndConstraints)
307+
s.dumpToFile(s.getDumpFileName("-views"), pgdumpOpts, parsedDump.views)
300308

301309
// only if clean is enabled, produce the clean up part of the dump
302310
if s.optionGenerator.cleanTargetDB {
@@ -495,10 +503,12 @@ func (s *SnapshotGenerator) parseDump(d []byte) *dump {
495503
indicesAndConstraints := strings.Builder{}
496504
filteredDump := strings.Builder{}
497505
eventTriggersDump := strings.Builder{}
506+
viewsDump := strings.Builder{}
498507
sequenceNames := []string{}
499508
dumpRoles := make(map[string]role)
500509
alterTable := ""
501510
createEventTrigger := ""
511+
createView := ""
502512
for scanner.Scan() {
503513
line := scanner.Text()
504514
switch {
@@ -535,11 +545,27 @@ func (s *SnapshotGenerator) parseDump(d []byte) *dump {
535545
eventTriggersDump.WriteString(line)
536546
eventTriggersDump.WriteString("\n")
537547

548+
case strings.HasPrefix(line, "CREATE VIEW"),
549+
strings.HasPrefix(line, "CREATE MATERIALIZED VIEW"):
550+
createView = line
551+
fallthrough
552+
case createView != "":
553+
if strings.HasSuffix(line, ";") {
554+
viewsDump.WriteString(line)
555+
viewsDump.WriteString("\n\n")
556+
createView = ""
557+
continue
558+
}
559+
viewsDump.WriteString(line)
560+
viewsDump.WriteString("\n")
561+
538562
case strings.Contains(line, `\connect`):
539563
indicesAndConstraints.WriteString(line)
540564
indicesAndConstraints.WriteString("\n\n")
541565
filteredDump.WriteString(line)
542566
filteredDump.WriteString("\n")
567+
viewsDump.WriteString(line)
568+
viewsDump.WriteString("\n\n")
543569
case strings.HasPrefix(line, "CREATE INDEX"),
544570
strings.HasPrefix(line, "CREATE UNIQUE INDEX"),
545571
strings.HasPrefix(line, "CREATE CONSTRAINT"),
@@ -604,6 +630,7 @@ func (s *SnapshotGenerator) parseDump(d []byte) *dump {
604630
full: d,
605631
filtered: []byte(filteredDump.String()),
606632
indicesAndConstraints: []byte(indicesAndConstraints.String()),
633+
views: []byte(viewsDump.String()),
607634
sequences: sequenceNames,
608635
roles: dumpRoles,
609636
eventTriggers: []byte(eventTriggersDump.String()),

pkg/snapshot/generator/postgres/schema/pgdumprestore/snapshot_pg_dump_restore_generator_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ func TestSnapshotGenerator_CreateSnapshot(t *testing.T) {
2525
t.Parallel()
2626

2727
schemaDump := []byte("schema dump\nCREATE SEQUENCE test.test_sequence\nALTER TABLE public.test_table OWNER TO test_role;\nGRANT ALL ON TABLE public.test_table TO test_role2;\nCREATE INDEX a;\n")
28+
schemaDumpWithViews := []byte("schema dump\nCREATE SEQUENCE test.test_sequence\nALTER TABLE public.test_table OWNER TO test_role;\nGRANT ALL ON TABLE public.test_table TO test_role2;\nCREATE VIEW public.test_view AS\n SELECT 1;\nCREATE INDEX a;\n")
2829
schemaDumpNoSequences := []byte("schema dump\nALTER TABLE public.test_table OWNER TO test_role;\nGRANT ALL ON TABLE public.test_table TO test_role2;\nCREATE INDEX a;\n")
2930
filteredDumpNoSequences := []byte("schema dump\nGRANT ALL ON SCHEMA \"public\" TO \"test_role\";\nALTER TABLE public.test_table OWNER TO test_role;\nGRANT ALL ON TABLE public.test_table TO test_role2;\n")
3031
filteredDump := []byte("schema dump\nCREATE SEQUENCE test.test_sequence\nGRANT ALL ON SCHEMA \"public\" TO \"test_role\";\nALTER TABLE public.test_table OWNER TO test_role;\nGRANT ALL ON TABLE public.test_table TO test_role2;\n")
3132
sequenceDump := []byte("sequence dump\n")
3233
indexDump := []byte("CREATE INDEX a;\n\n")
34+
testViewsDump := []byte("CREATE VIEW public.test_view AS\n SELECT 1;\n\n")
3335
rolesDumpOriginal := []byte("roles dump\nCREATE ROLE postgres\nCREATE ROLE test_role\nCREATE ROLE test_role2\nALTER ROLE test_role3 INHERIT FROM test_role;\n")
3436
rolesDumpFiltered := []byte("roles dump\nCREATE ROLE test_role\nCREATE ROLE test_role2\nGRANT \"test_role\" TO CURRENT_USER;\n")
3537
cleanupDump := []byte("cleanup dump\n")
@@ -261,6 +263,52 @@ func TestSnapshotGenerator_CreateSnapshot(t *testing.T) {
261263

262264
wantErr: nil,
263265
},
266+
{
267+
name: "ok - with views",
268+
snapshot: &snapshot.Snapshot{
269+
SchemaTables: map[string][]string{
270+
testSchema: {testTable},
271+
},
272+
},
273+
conn: validQuerier(),
274+
pgdumpFn: newMockPgdump(func(_ context.Context, i uint, po pglib.PGDumpOptions) ([]byte, error) {
275+
switch i {
276+
case 1:
277+
return schemaDumpWithViews, nil
278+
case 2:
279+
return sequenceDump, nil
280+
default:
281+
return nil, fmt.Errorf("unexpected call to pgdumpFn: %d", i)
282+
}
283+
}),
284+
pgdumpallFn: newMockPgdumpall(func(_ context.Context, i uint, po pglib.PGDumpAllOptions) ([]byte, error) {
285+
switch i {
286+
case 1:
287+
return rolesDumpOriginal, nil
288+
default:
289+
return nil, fmt.Errorf("unexpected call to pgdumpallFn: %d", i)
290+
}
291+
}),
292+
pgrestoreFn: newMockPgrestore(func(_ context.Context, i uint, po pglib.PGRestoreOptions, dump []byte) (string, error) {
293+
switch i {
294+
case 1:
295+
require.Equal(t, string(rolesDumpFiltered), string(dump))
296+
case 2:
297+
require.Equal(t, string(filteredDump), string(dump))
298+
case 3:
299+
require.Equal(t, string(sequenceDump), string(dump))
300+
case 4:
301+
require.Equal(t, string(indexDump), string(dump))
302+
case 5:
303+
require.Equal(t, string(testViewsDump), string(dump))
304+
default:
305+
return "", fmt.Errorf("unexpected call to pgrestoreFn: %d", i)
306+
}
307+
return "", nil
308+
}),
309+
310+
wantErr: nil,
311+
},
264312
{
265313
name: "ok - no sequence dump",
266314
snapshot: &snapshot.Snapshot{
@@ -1370,6 +1418,9 @@ func TestSnapshotGenerator_parseDump(t *testing.T) {
13701418
wantEventTriggersBytes, err := os.ReadFile("test/test_dump_event_triggers.sql")
13711419
require.NoError(t, err)
13721420

1421+
wantViewsBytes, err := os.ReadFile("test/test_dump_views.sql")
1422+
require.NoError(t, err)
1423+
13731424
sg := &SnapshotGenerator{
13741425
excludedSecurityLabels: []string{"anon"},
13751426
}
@@ -1381,12 +1432,15 @@ func TestSnapshotGenerator_parseDump(t *testing.T) {
13811432
wantConstraintsStr := strings.Trim(string(wantConstraintsBytes), "\n")
13821433
eventTriggersStr := strings.Trim(string(dump.eventTriggers), "\n")
13831434
wantEventTriggersStr := strings.Trim(string(wantEventTriggersBytes), "\n")
1435+
viewsStr := strings.Trim(string(dump.views), "\n")
1436+
wantViewsStr := strings.Trim(string(wantViewsBytes), "\n")
13841437
wantSequences := []string{`"musicbrainz"."alternative_medium_id_seq"`, `"musicbrainz"."Alternative_medium_id_seq"`}
13851438

13861439
require.Equal(t, wantFilteredStr, filteredStr)
13871440
require.Equal(t, wantConstraintsStr, constraintsStr)
13881441
require.Equal(t, wantSequences, dump.sequences)
13891442
require.Equal(t, wantEventTriggersStr, eventTriggersStr)
1443+
require.Equal(t, wantViewsStr, viewsStr)
13901444
}
13911445

13921446
func TestGetDumpsDiff(t *testing.T) {

pkg/snapshot/generator/postgres/schema/pgdumprestore/test/test_dump.sql

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,37 @@ ALTER TABLE ONLY musicbrainz.alternative_medium ALTER COLUMN id SET DEFAULT next
251251
ALTER TABLE ONLY musicbrainz.alternative_release ALTER COLUMN id SET DEFAULT nextval('musicbrainz.alternative_release_id_seq'::regclass);
252252

253253

254+
--
255+
-- Name: edit_summary; Type: VIEW; Schema: musicbrainz; Owner: postgres
256+
--
257+
258+
CREATE VIEW musicbrainz.edit_summary AS
259+
SELECT e.id,
260+
e.editor,
261+
e.type,
262+
e.status
263+
FROM musicbrainz.edit e
264+
GROUP BY e.id;
265+
266+
267+
ALTER VIEW musicbrainz.edit_summary OWNER TO postgres;
268+
269+
--
270+
-- Name: medium_summary; Type: MATERIALIZED VIEW; Schema: musicbrainz; Owner: postgres
271+
--
272+
273+
CREATE MATERIALIZED VIEW musicbrainz.medium_summary AS
274+
SELECT am.id,
275+
am.medium,
276+
am.alternative_release,
277+
am.name
278+
FROM musicbrainz.alternative_medium am
279+
GROUP BY am.id
280+
WITH NO DATA;
281+
282+
283+
ALTER MATERIALIZED VIEW musicbrainz.medium_summary OWNER TO postgres;
284+
254285
--
255286
-- Name: alternative_medium alternative_medium_pkey; Type: CONSTRAINT; Schema: musicbrainz; Owner: postgres
256287
--

pkg/snapshot/generator/postgres/schema/pgdumprestore/test/test_dump_filtered.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,20 @@ ALTER TABLE ONLY musicbrainz.alternative_medium ALTER COLUMN id SET DEFAULT next
240240
ALTER TABLE ONLY musicbrainz.alternative_release ALTER COLUMN id SET DEFAULT nextval('musicbrainz.alternative_release_id_seq'::regclass);
241241

242242

243+
--
244+
-- Name: edit_summary; Type: VIEW; Schema: musicbrainz; Owner: postgres
245+
--
246+
247+
248+
249+
250+
--
251+
-- Name: medium_summary; Type: MATERIALIZED VIEW; Schema: musicbrainz; Owner: postgres
252+
--
253+
254+
255+
256+
243257
--
244258
-- Name: alternative_medium alternative_medium_pkey; Type: CONSTRAINT; Schema: musicbrainz; Owner: postgres
245259
--
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
\connect test
2+
3+
CREATE VIEW musicbrainz.edit_summary AS
4+
SELECT e.id,
5+
e.editor,
6+
e.type,
7+
e.status
8+
FROM musicbrainz.edit e
9+
GROUP BY e.id;
10+
11+
CREATE MATERIALIZED VIEW musicbrainz.medium_summary AS
12+
SELECT am.id,
13+
am.medium,
14+
am.alternative_release,
15+
am.name
16+
FROM musicbrainz.alternative_medium am
17+
GROUP BY am.id
18+
WITH NO DATA;

0 commit comments

Comments
 (0)