The way I wished Postgres DDLs worked (at least optionally) is that you have to explicitly acquire the correct lock before a DDL statement, or it just immediately fails. Something like:
ACQUIRE ACCESS SHARE TABLE LOCK ON my_table ALTER TABLE my_table ALTER COLUMN my_column TYPE bigint
This way I _know_ that if the operation needs a stronger lock than I thought or than I'm willing to give it, it will just fail rather than locking up my database and causing unexpected downtime.
I think you could automate this with 2 transactions
- connection A, lock timeout=0, acquire unwanted lock
- connection B, lock timeout=0, run migration
- collection A, rollback
Then connection B will fail if it tries to acquire an undesirable lock since it will conflict with A. You'd be adding a very small window when you're actually holding the undesirable lock, though
That’s an interesting idea but not all locks are held for the duration of the statement. A lot of them take a less intrusive lock for the whole statement and take an exclusive lock for a very short time when they finish up.
Edit: Looking this up, I’m not sure this is correct.
The biggest problem with that right now is that postgres doesn't allow explicit lock acquisitions (via the LOCK stmt) for all the object types. I've been thinking we should change that for a while, albeit partially just because it is useful for writing tests. With that added, a mode that refuses new lock acquisitions wouldn't be that hard...
I invite you to start a discussion on the lists about that feature, I've wished for it before.