Странный вопрос, в column_default таблицы information_schema.columns.
Казалось бы вопрос закрыт, но что произойдёт когда мы удалим дефолт с колонки?
Как известно, начиная с 11 версии postgresql, при добавлении новой not null колонки со значением по умолчанию, физически не меняет данные в таблицы. Просто в момент чтения старых данных возвращает указанное значение. Но что если удалить дефолт?
Вот что говорит chatGTP по этому поводу:

Я тоже удивился тому, что not null колонка может возвращаться null и провёл небольшой эксперимент.
Время экспериментов!
Все примеры содержат ссылку на www.db-fiddle.com, чтобы можно было поэкспериментировать с за запросами самостоятельно.
Для начала проверим, какое значение возвращается для колонки после удаления дефолта.
-- 1. Создание таблицы с одним полем id CREATE TABLE test_table ( id BIGINT ); -- 2. Вставка 1000 записей (id от 1 до 1000) INSERT INTO test_table (id) SELECT generate_series(1, 1000); -- 3. Добавление NOT NULL поля name со значением по умолчанию 'none' ALTER TABLE test_table ADD COLUMN name TEXT NOT NULL DEFAULT 'none'; -- 4. Удаление значения по умолчанию у поля name ALTER TABLE test_table ALTER COLUMN name DROP DEFAULT; -- 5. Чтение первых 10 записей SELECT * FROM test_table LIMIT 10; | id | name | | --- | ---- | | 1 | none | | 2 | none | | 3 | none | | 4 | none | | 5 | none | | 6 | none | | 7 | none | | 8 | none | | 9 | none | | 10 | none |
Возвращается none. Получается СhatGTP оказался не прав. Можно выдыхать not null колонка по прежнему не возвращает null.
На всякий случай проверим, что будет если установить другой дефолт. Изменится ли значение для старых строк?
-- 5. Установка значения по умолчанию 'another' для поля name ALTER TABLE test_table ALTER COLUMN name SET DEFAULT 'another'; -- 6. Чтение первых 10 записей SELECT * FROM test_table LIMIT 10; | id | name | | --- | ---- | | 1 | none | | 2 | none | | 3 | none | | 4 | none | | 5 | none | | 6 | none | | 7 | none | | 8 | none | | 9 | none | | 10 | none |
Не изменилось, none на месте. Получается, что никакие манипуляции с дефолтом не изменяют значения, заданного при создании столбца. Значит дефолтное значение не при чём.
Но и сама таблица не при чём, т.к. не изменяется. Убедиться в этом довольно просто.
-- 1. Создание таблицы с одним полем id CREATE TABLE test_table ( id BIGINT ); -- 2. Вставка 1000 записей (id от 1 до 1000) INSERT INTO test_table (id) SELECT generate_series(1, 100000); -- 3. Измерение размера таблицы ДО добавления колонки SELECT 'before_add_column' AS stage, pg_size_pretty(pg_total_relation_size('test_table')) AS total_size, pg_size_pretty(pg_relation_size('test_table')) AS heap_size; -- 4. Добавление колонку с DEFAULT ALTER TABLE test_table ADD COLUMN name TEXT DEFAULT 'none'; -- 5. Измерение размера таблицы ПОСЛЕ добавления колонки SELECT 'after_add_column_default' AS stage, pg_size_pretty(pg_total_relation_size('test_table')) AS total_size, pg_size_pretty(pg_relation_size('test_table')) AS heap_size; -- 6. Обновление имени UPDATE test_table SET name = 'edit'; -- 8. Вакуум, чтобы изменить размер только обновлённых строк VACUUM FULL test_table; -- 8. Измерение размера таблицы ПОСЛЕ UPDATE SELECT 'after_update_materialized' AS stage, pg_size_pretty(pg_total_relation_size('test_table')) AS total_size, pg_size_pretty(pg_relation_size('test_table')) AS heap_size; | stage | total_size | heap_size | | ------------------------- | ---------- | --------- | | before_add_column | 3568 kB | 3544 kB | | after_add_column_default | 3576 kB | 3544 kB | | after_update_materialized | 4336 kB | 4328 kB |
Видно, что размер таблицы увеличился только после обновления, когда значение editфизически записалось в строки таблицы.
Так где хранится дефолт для созданной колонки?
В атрибутах столбца: колонка attmissingval таблицы pg_attribute.
Это значение устанавливается 1 раз при создании столбца и больше не меняется. С его помощью имитируется поведение, когда при создании новой колонки его значение по умолчанию физически записывалось в таблицу, как это было в ранних версия постгреса.
Давайте, прочитаем это значение:
-- 1. Создание таблицы с одним полем id CREATE TABLE test_table ( id BIGINT ); -- 2. Вставка 1000 записей (id от 1 до 1000) INSERT INTO test_table (id) SELECT generate_series(1, 1000); -- 3. Добавление NOT NULL поля name со значением по умолчанию 'none' ALTER TABLE test_table ADD COLUMN name TEXT NOT NULL DEFAULT 'none'; -- 4. Удаление значения по умолчанию у поля name ALTER TABLE test_table ALTER COLUMN name DROP DEFAULT; -- 5. Установка значения по умолчанию 'another' для поля name ALTER TABLE test_table ALTER COLUMN name SET DEFAULT 'another'; --6. Получение текущего значения по умолчанию SELECT column_default FROM information_schema.columns WHERE table_name = 'test_table' AND column_name = 'name'; --6. Получение значения по умолчанию указанного при создании колонки SELECT a.attname, a.attmissingval FROM pg_attribute a JOIN pg_class c ON c.oid = a.attrelid WHERE c.relname = 'test_table' AND a.attname = 'name'; | column_default | | --------------- | | 'another'::text | | attname | attmissingval | | ------- | --------------- | | name | {none} |
Как видно, attmissingval задан и равен изначальном значению по умолчанию none, в то время как текущее значение по умолчанию another.