Skip to content

Segmentation violation when adding unique constraint #623

@agedemenli

Description

@agedemenli

When adding a unique constraint, at the end of Start phase, we try to perform backfills. If there's no column that is unique and not nullable, backfill errors out. Instead of returning that error, we first try to Rollback and that's where the segmentation violation happens. Because of segv, the user doesn't even see the error message that comes from Backfill.

func (m *Roll) performBackfills(ctx context.Context, tables []*schema.Table, cbs ...migrations.CallbackFn) error {
	for _, table := range tables {
		if err := migrations.Backfill(ctx, m.pgConn, table, m.backfillBatchSize, m.backfillBatchDelay, cbs...); err != nil {
			errRollback := m.Rollback(ctx)

			return errors.Join(
				fmt.Errorf("unable to backfill table %q: %w", table.Name, err),
				errRollback)
		}
	}

	return nil
}

If any column might become an identity column because of the newly added unique constraint, ideally, backfill should succeed. If not, we should error out gracefully instead of a segv.

Can reproduce using the existing migration file examples/44_add_table_unique_constraint.json:

{
  "name": "44_add_table_unique_constraint",
  "operations": [
    {
      "create_constraint": {
        "type": "unique",
        "table": "tickets",
        "name": "unique_zip_name",
        "columns": [
          "sellers_name",
          "sellers_zip"
        ],
        "up": {
          "sellers_name": "sellers_name",
          "sellers_zip": "sellers_zip"
        },
        "down": {
          "sellers_name": "sellers_name",
          "sellers_zip": "sellers_zip"
        }
      }
    }
  ]
}

Create the table:

create table tickets(sellers_name text not null, sellers_zip int not null); --not null is optional, it will segv anyway

Then

./pgroll start ./examples/44_add_table_unique_constraint.json --complete

Starting migration... (0s)panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x30 pc=0x1011ccebc]

goroutine 1 [running]:
github.com/xataio/pgroll/pkg/schema.(*Table).GetColumn(...)
        /Users/ahmet/pgroll/pkg/schema/schema.go:204
github.com/xataio/pgroll/pkg/migrations.(*OpCreateConstraint).Start(0x1400029c690, {0x1017c1d20, 0x101c3a5c0}, {0x1017c2308, 0x101c3a5c0}, {0x0, 0x0}, {0x1017b9ae0, 0x1017b54f0}, 0x1400028f518, ...)
        /Users/ahmet/pgroll/pkg/migrations/op_create_constraint.go:22 +0xec
github.com/xataio/pgroll/pkg/migrations.(*Migration).UpdateVirtualSchema(0x1400028e198?, {0x1017c1d20, 0x101c3a5c0}, 0x1400028f518)
        /Users/ahmet/pgroll/pkg/migrations/migrations.go:104 +0x84
github.com/xataio/pgroll/pkg/roll.(*Roll).Rollback(0x1400012c080, {0x1017c1d20, 0x101c3a5c0})
        /Users/ahmet/pgroll/pkg/roll/execute.go:258 +0x24c
github.com/xataio/pgroll/pkg/roll.(*Roll).performBackfills(0x1400012c080, {0x1017c1d20, 0x101c3a5c0}, {0x14000288570, 0x1, 0x1?}, {0x140001160e8, 0x1, 0x1})
        /Users/ahmet/pgroll/pkg/roll/execute.go:314 +0xd8
github.com/xataio/pgroll/pkg/roll.(*Roll).Start(0x1400012c080, {0x1017c1d20, 0x101c3a5c0}, 0x4?, {0x140001160e8, 0x1, 0x1})
        /Users/ahmet/pgroll/pkg/roll/execute.go:25 +0x74
github.com/xataio/pgroll/cmd.runMigration({0x1017c1d20, 0x101c3a5c0}, 0x1400012c080, 0x14000114120, 0x1)
        /Users/ahmet/pgroll/cmd/start.go:70 +0x13c
github.com/xataio/pgroll/cmd.runMigrationFromFile({0x1017c1d20, 0x101c3a5c0}, 0x1400012c080, {0x16efe3707?, 0x0?}, 0x1)
        /Users/ahmet/pgroll/cmd/start.go:54 +0x68
github.com/xataio/pgroll/cmd.startCmd.func1(0x140001be608, {0x140000a4a80?, 0x4?, 0x10141f203?})
        /Users/ahmet/pgroll/cmd/start.go:36 +0xcc
github.com/spf13/cobra.(*Command).execute(0x140001be608, {0x140000a4a60, 0x2, 0x2})
        /Users/ahmet/go/pkg/mod/github.com/spf13/[email protected]/command.go:985 +0x834
github.com/spf13/cobra.(*Command).ExecuteC(0x101ba6720)
        /Users/ahmet/go/pkg/mod/github.com/spf13/[email protected]/command.go:1117 +0x344
github.com/spf13/cobra.(*Command).Execute(...)
        /Users/ahmet/go/pkg/mod/github.com/spf13/[email protected]/command.go:1041
github.com/xataio/pgroll/cmd.Execute()
        /Users/ahmet/pgroll/cmd/root.go:84 +0x218
main.main()
        /Users/ahmet/pgroll/main.go:12 +0x1c

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions