| From: | Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com> |
|---|---|
| To: | Postgres hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Cc: | Andrew Dunstan <andrew(at)dunslane(dot)net>, jian he <jian(dot)universality(at)gmail(dot)com> |
| Subject: | Fix domain fast defaults on empty tables |
| Date: | 2026-06-05 07:48:00 |
| Message-ID: | 7033D663-DDB4-4B35-922C-F33DE53B1502@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
I tested "[a0b6ef29a] Enable fast default for domains with non-volatile constraints". After tracing some cases from the regression tests, I came up with this test case and found a bug:
```
evantest=# create domain d_div as int check (1 / (value - 1) > 0);
CREATE DOMAIN
evantest=# create table t (a int);
CREATE TABLE
evantest=# alter table t add column b d_div default 1;
ERROR: division by zero
```
It looks like errors inside the CHECK expression itself, such as the int4div division-by-zero in this test, are still hard errors that can fail the ALTER TABLE command.
For the fix, I worked out two solutions:
Solution 1
========
We can add PG_TRY/PG_CATCH to capture those hard errors. But as a0b6ef29a's commit message mentions, the fallback should only apply while evaluating the CoerceToDomain expression. To avoid broadly suppressing hard errors, I only catch hard errors from domain_check_safe(), which verifies the default value against the domain. The default expression itself is still evaluated with hard errors.
My concern with this solution is that there might be some error from domain_check_safe() that I am not aware of and that would be hidden by the try-catch. But that may be acceptable, because it matches the behavior before a0b6ef29a, so at least it is not a regression.
Solution 2
========
This solution is simpler and is based on the purpose of the original feature. a0b6ef29a's commit message says the purpose of the feature is to avoid table rewriting. Since an empty table has no data to rewrite, we can bypass the fast path for empty tables.
The problem with this solution is that I currently use RelationGetNumberOfBlocks(rel) to decide whether the table is empty, so it cannot handle cases like:
```
Begin;
Delete from t;
Alter table t add column …
```
See the attached patches for details. v1-s1 is solution 1, and v1-s2 is solution 2. Please let me know which solution is preferred.
Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/
| Attachment | Content-Type | Size |
|---|---|---|
| v1-s1-0001-Handle-throwing-domain-checks-when-probing-fas.patch | application/octet-stream | 9.8 KB |
| v1-s2-0001-Preserve-empty-table-behavior-for-domain-fast-.patch | application/octet-stream | 8.6 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Richard Guo | 2026-06-05 07:50:13 | Re: Reduce LEFT/FULL JOIN to ANTI JOIN in more cases |
| Previous Message | Shlok Kyal | 2026-06-05 07:44:11 | Re: Support EXCEPT for ALL SEQUENCES publications |