diff --git a/internal/source/postgres/postgres.go b/internal/source/postgres/postgres.go index b59354c..e6d35b3 100644 --- a/internal/source/postgres/postgres.go +++ b/internal/source/postgres/postgres.go @@ -109,7 +109,12 @@ func createTable(src *model.Source, text string, pos model.Pos) { name = name[:p] } schema, table := splitQualified(name) - body, rest, ok := ddl.Body(text[strings.Index(text, w[i]):]) + // The column list is the first parenthesis after TABLE. Searching for + // the name's word instead panicked when the name was glued to a paren + // that opens a multi-line list ("reactions(\n userid ..."): the word + // splitter folds that list's whitespace, so the word is not in the text + // and the index is -1. Found on Mattermost's migrations. + body, rest, ok := ddl.Body(text[strings.Index(strings.ToUpper(text), "TABLE")+len("TABLE"):]) if !ok { return } diff --git a/internal/source/postgres/postgres_test.go b/internal/source/postgres/postgres_test.go index caa6049..731fb7c 100644 --- a/internal/source/postgres/postgres_test.go +++ b/internal/source/postgres/postgres_test.go @@ -67,3 +67,19 @@ func formatSlice(s []string) string { } return out + "]" } + +func TestANameGluedToAMultiLineColumnListDoesNotPanic(t *testing.T) { + // Mattermost 000016_create_reactions.up.sql, as written. + src := &model.Source{} + text := "CREATE TABLE IF NOT EXISTS reactions(\n userid VARCHAR(26) NOT NULL,\n postid VARCHAR(26) NOT NULL\n);" + if err := Apply(src, "000016_create_reactions.up.sql", text); err != nil { + t.Fatal(err) + } + r := src.Table("public", "reactions") + if r == nil || len(r.Columns) != 2 || r.Columns[0].Name != "userid" || r.Columns[1].Name != "postid" { + t.Fatalf("public.reactions = %+v", r) + } + if r.Columns[1].Pos.Line != 3 { + t.Errorf("postid line = %d, want 3", r.Columns[1].Pos.Line) + } +}