Skip to content

Why These Types Error Instead of Truncating

This is the one real behavioral gap in the VARCHAR2/NVARCHAR2 domain family, and it's worth understanding precisely rather than discovering it by surprise.

How real orafce's type behaves

Real orafce's oracle.varchar2(n) (and PostgreSQL core's own varchar(n), for that matter) behaves differently depending on context:

Context Behavior
Assignment (INSERT, UPDATE, assigning to a PL/pgSQL variable) Errors if the value overflows the declared length.
Explicit cast (value::oracle.varchar2(10)) Truncates silently to the declared length — no error, the extra characters are just dropped.

This dual behavior is possible because a real, C-backed, typmod-aware type can register a dedicated coercion function for the explicit-cast path, separate from the assignment path.

Why orafce_no_c can't do the same

The domain family is built from ordinary CREATE DOMAIN ... CHECK (...) statements — the only mechanism available without C. A CHECK constraint has exactly one behavior: it either passes or raises an error. There's no "truncate on cast, error on assignment" split available to a domain.

This was tested directly, not assumed: it's possible to register a custom CREATE CAST using exactly the 3-argument (value, typmod, is_explicit boolean) convention PostgreSQL's own core varchar/numeric types use internally to implement this exact truncate-vs-error split. PostgreSQL accepts the syntax — then immediately warns cast will be ignored because the target data type is a domain, and the domain's own CHECK constraint runs regardless. PostgreSQL categorically refuses any custom cast targeting a domain, full stop, regardless of the cast function's signature. There is no way around this without a real base type — which brings back the cstring problem from Working with Types.

What this means in practice

Context Real orafce oracle.varchar2(n) orafce_no_c oracle.varchar_Nb/_Nc
INSERT/UPDATE overflow Errors Errors (matches exactly)
PL/pgSQL variable assignment overflow Errors Errors (matches exactly)
Explicit cast (::type) overflow Truncates silently Errors (does not match)

The common case — inserting or assigning a too-long value — behaves identically. Only the explicit-cast path diverges, and it diverges in the safer direction: erroring loudly instead of silently discarding data.

Check for code that relies on silent truncation

If your migrated code deliberately casts an oversized value to VARCHAR2(n) expecting it to be quietly cut down to size — a pattern sometimes used for defensive truncation before display or logging — that code will now raise an error instead. Review any explicit ::VARCHAR2(n)/::NVARCHAR2(n) casts in your source before migrating; an assignment or column insert with the same length constraint will already have been erroring in real orafce too, so those paths need no changes.

Continue to Customizing the Type Family.