Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions docs/docs/adding-field-with-default.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,30 @@ This statement is only safe when your default is non-volatile.
:::

```sql
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT 10 NOT NULL;
-- blocks reads and writes while schema is changed (fast)
ALTER TABLE "account" ADD COLUMN "foo" integer DEFAULT 10;
```

### adding a volatile default

Add the field as nullable, then set a default, backfill, and remove nullabilty.
Add the field without a default, set the default, and then backfill existing rows in batches.

Instead of:

```sql
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT 10 NOT NULL;
-- blocks reads and writes while table is rewritten (slow)
ALTER TABLE "account" ADD COLUMN "ab_group" integer DEFAULT random();
```

Use:

```sql
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer;
ALTER TABLE "core_recipe" ALTER COLUMN "foo" SET DEFAULT 10;
-- backfill column in batches
ALTER TABLE "core_recipe" ALTER COLUMN "foo" SET NOT NULL;
```
-- blocks reads and writes while schema is changed (fast)
ALTER TABLE "account" ADD COLUMN "ab_group" integer;
-- blocks reads and writes while schema is changed (fast)
ALTER TABLE "account" ALTER COLUMN "ab_group" SET DEFAULT random();

We add our column as nullable, set a default for new rows, backfill our column (ideally done in batches to limit locking), and finally remove nullability.
-- backfill existing rows in batches to set the "last_modified" column
```

See ["How not valid constraints work"](constraint-missing-not-valid.md#how-not-valid-validate-works) for more information on adding constraints as `NOT VALID`.
1 change: 1 addition & 0 deletions linter/src/rules/adding_field_with_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT uuid();
let ok_sql = r#"
-- NON-VOLATILE
ALTER TABLE "core_recipe" ADD COLUMN "foo" integer DEFAULT 10;
ALTER TABLE "account" ADD COLUMN "last_modified" timestamptz DEFAULT now();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

our code for checking volatility of functions doesn't work. now() is stable, while a function like random is volatile.

select
  proname,
  pronamespace::regnamespace,
  provolatile
from pg_proc
where proname = 'now'
  or proname = 'random';

I think we could hard code in a list of functions and then warn when we can't know for certain with a more detailed error message.

"#;

let pg_version_11 = Some(Version::from_str("11.0.0").unwrap());
Expand Down