| From: | Henson Choi <assam258(at)gmail(dot)com> |
|---|---|
| To: | Corey Huinker <corey(dot)huinker(at)gmail(dot)com>, jian he <jian(dot)universality(at)gmail(dot)com> |
| Cc: | Vik Fearing <vik(at)postgresfriends(dot)org>, Amul Sul <sulamul(at)gmail(dot)com>, Kirill Reshke <reshkekirill(at)gmail(dot)com>, Isaac Morland <isaac(dot)morland(at)gmail(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org |
| Subject: | Re: CAST(... ON DEFAULT) - WIP build on top of Error-Safe User Functions |
| Date: | 2026-06-30 07:07:23 |
| Message-ID: | CAAAe_zAi=PGO4j89w5Hu_Gu+njKeWY9YeX0hp91qvWVMXt0igw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi hackers,
While reviewing the error-safe text->regclass cast -- the first patch,
"error safe for casting text to other types per pg_cast" -- I built it and
ran a few cases under ON CONVERSION ERROR to see how the cast behaves.
Three behaviors stand out, and together they surface one inconsistency and
a policy question I'd like to raise. The concrete site and fix below are in
that patch, independently of the main DEFAULT-syntax patch; ON CONVERSION
ERROR is only the lens that makes the cast's soft/hard behavior observable.
(Examples use ::text so they exercise the text_regclass cast function rather
than the regclass input function.)
* Observed behaviors (built from this patch, tested)
(i) A value-conversion error is caught and replaced by the DEFAULT, as
intended:
SELECT CAST('x' AS integer DEFAULT 0 ON CONVERSION ERROR); -- 0
(ii) The DEFAULT expression itself is evaluated without the soft-error net
(expr2 being the "non-error-safe typecast", as described early in this
thread). For a value type that never matters, but for a binding type like
regclass a DEFAULT that names a missing object hard-aborts:
SELECT CAST('public.nosuchA'::text AS regclass
DEFAULT 'public.nosuchB'::text ON CONVERSION ERROR);
-- ERROR: relation "public.nosuchb" does not exist (DEFAULT NULL is
fine)
This is by design; I note it only because a binding-type DEFAULT can itself
fail, unlike a value-type DEFAULT.
(iii) A "not found" lookup failure is mostly treated as soft. A missing
relation folds into the DEFAULT, and the regclass input function already
reports a missing schema softly (as "relation does not exist", 42P01):
SELECT CAST('public.nosuchtable'::text AS regclass
DEFAULT 999 ON CONVERSION ERROR); -- 999
SELECT message, sql_error_code
FROM pg_input_error_info('nosuch_schema.foo','regclass');
-- relation "nosuch_schema.foo" does not exist | 42P01
I couldn't find a point in the thread where it was decided whether a
lookup/not-found failure should be caught by ON CONVERSION ERROR at all --
the reg* casts seem to have been swept into the error-safe batch alongside
value casts, without distinguishing a binding failure from a value
conversion. The de-facto behavior, though, is soft.
* The inconsistency
Against that mostly-soft behavior, one not-found is hard: a missing SCHEMA
in a schema-qualified name. text_regclass() calls
RangeVarGetRelidExtendedSafe(rv, NoLock, 0, NULL, NULL, fcinfo->context)
with flags=0 (so missing_ok=false), and the schema-resolution step
LookupExplicitNamespace() -> get_namespace_oid() is not threaded with
escontext, so it raises ERRCODE_UNDEFINED_SCHEMA as a hard ereport:
SELECT CAST('nosuch_schema.foo'::text AS regclass
DEFAULT NULL ON CONVERSION ERROR);
-- ERROR: schema "nosuch_schema" does not exist (get_namespace_oid,
namespace.c)
So a missing schema hard-aborts, while the parallel missing relation one
branch below is soft (and regclassin softens the same missing-schema input).
* The question
This reads less like a localized slip and more like a policy decision that
was never made: under ON CONVERSION ERROR, should a "not found"
(lookup/binding) failure be hard or soft?
- If soft (consistent with the current majority behavior and with
regclassin), then LookupExplicitNamespace()/get_namespace_oid() need
escontext threaded on the not-found path -- equivalently text_regclass()
could pass RVR_MISSING_OK as regclassin does -- while the USAGE-permission
check stays hard, which it correctly does today:
-- as a role lacking USAGE on schema s1:
SELECT CAST('s1.t'::text AS regclass DEFAULT NULL ON CONVERSION
ERROR);
-- ERROR: permission denied for schema s1 (stays hard, not folded)
- If hard, then the inconsistency runs the other way: the relation-not-found
softening and regclassin's behavior would need revisiting, and whether
catalog-resolving reg* casts belong in ON CONVERSION ERROR at all deserves
a second look.
Either way, the current schema-vs-relation split is inconsistent. I'd
rather see the policy settled than just patch the one site.
Best regards,
Henson
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Chao Li | 2026-06-30 07:45:43 | Fix RLS checks for UPDATE/DELETE FOR PORTION OF leftover rows |
| Previous Message | Ewan Young | 2026-06-30 07:01:31 | JSON_VALUE/JSON_TABLE DEFAULT expression ignores RETURNING typmod |