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

Reply via email to