(ctx context.Context, conn *sql.Conn, statement string, version string)
| 192 | } |
| 193 | |
| 194 | func executeMigration(ctx context.Context, conn *sql.Conn, statement string, version string) error { |
| 195 | // Get current database context for error reporting |
| 196 | var currentUser, currentDatabase string |
| 197 | _ = conn.QueryRowContext(ctx, "SELECT current_user, current_database()").Scan(¤tUser, ¤tDatabase) |
| 198 | |
| 199 | txn, err := conn.BeginTx(ctx, nil) |
| 200 | if err != nil { |
| 201 | return err |
| 202 | } |
| 203 | defer txn.Rollback() |
| 204 | |
| 205 | if _, err := txn.ExecContext(ctx, statement); err != nil { |
| 206 | // Extract SQLSTATE and provide contextual information |
| 207 | var sqlState string |
| 208 | if pqErr, ok := err.(*pq.Error); ok { |
| 209 | sqlState = string(pqErr.Code) |
| 210 | } |
| 211 | |
| 212 | // Truncate statement for readability in error message |
| 213 | stmtPreview, truncated := common.TruncateString(statement, 100) |
| 214 | if truncated { |
| 215 | stmtPreview += "..." |
| 216 | } |
| 217 | |
| 218 | return errors.Errorf("migration %s failed\n"+ |
| 219 | "Statement: %s\n"+ |
| 220 | "User: %s\n"+ |
| 221 | "Database: %s\n"+ |
| 222 | "Error: %v\n"+ |
| 223 | "SQLSTATE: %s", |
| 224 | version, stmtPreview, currentUser, currentDatabase, err, sqlState) |
| 225 | } |
| 226 | if _, err := txn.ExecContext(ctx, |
| 227 | `INSERT INTO instance_change_history (version) VALUES ($1)`, |
| 228 | version, |
| 229 | ); err != nil { |
| 230 | return err |
| 231 | } |
| 232 | |
| 233 | return txn.Commit() |
| 234 | } |
| 235 | |
| 236 | func getLatestDatabaseVersion(ctx context.Context, conn *sql.Conn) (*semver.Version, error) { |
| 237 | query := `SELECT version FROM instance_change_history ORDER BY id DESC` |
no test coverage detected