| 74 | } |
| 75 | |
| 76 | func setup(db *sql.DB, migs fs.FS) (source.Driver, *migrate.Migrate, error) { |
| 77 | if migs == nil { |
| 78 | migs = migrations |
| 79 | } |
| 80 | ctx := context.Background() |
| 81 | sourceDriver, err := iofs.New(migs, ".") |
| 82 | if err != nil { |
| 83 | return nil, nil, xerrors.Errorf("create iofs: %w", err) |
| 84 | } |
| 85 | |
| 86 | // migration_cursor is a v1 migration table. If this exists, we're on v1. |
| 87 | // Do no run v2 migrations on a v1 database! |
| 88 | row := db.QueryRowContext(ctx, "SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = 'migration_cursor';") |
| 89 | var v1Exists int |
| 90 | if row.Scan(&v1Exists) == nil { |
| 91 | return nil, nil, xerrors.New("currently connected to a Coder v1 database, aborting database setup") |
| 92 | } |
| 93 | |
| 94 | dbDriver := &pgTxnDriver{ctx: context.Background(), db: db} |
| 95 | err = dbDriver.ensureVersionTable() |
| 96 | if err != nil { |
| 97 | return nil, nil, xerrors.Errorf("ensure version table: %w", err) |
| 98 | } |
| 99 | |
| 100 | m, err := migrate.NewWithInstance("", sourceDriver, "", dbDriver) |
| 101 | if err != nil { |
| 102 | return nil, nil, xerrors.Errorf("new migrate instance: %w", err) |
| 103 | } |
| 104 | |
| 105 | // The default LockTimeout of 15s is too short for concurrent migrations, |
| 106 | // especially when the number of migrations is large. Since we use |
| 107 | // pg_advisory_xact_lock which releases automatically when the transaction |
| 108 | // ends, we just need to wait long enough for any concurrent migration to |
| 109 | // finish. |
| 110 | m.LockTimeout = 2 * time.Minute |
| 111 | |
| 112 | return sourceDriver, m, nil |
| 113 | } |
| 114 | |
| 115 | // Up runs SQL migrations to ensure the database schema is up-to-date. |
| 116 | func Up(db *sql.DB) error { |