TRY_CONVERT - #901
Conversation
| if (OidIsValid(sourceTypeId)) | ||
| sourceTypeId = getBaseType(sourceTypeId); | ||
| if (OidIsValid(targetTypeId)) | ||
| targetTypeId = getBaseType(targetTypeId); |
There was a problem hiding this comment.
What if the source or target type is invalid?
There was a problem hiding this comment.
All will happend like in
cloudberry/src/backend/parser/parse_coerce.c
Line 3151 in e601fb6
We will look in pg_cast table - will find nothing, will try to get TypeCategory and will get assert in TypeCategory(targetTypeId)
|
|
||
| *funcId = castForm->castfunc; | ||
| ReleaseSysCache(tuple); | ||
| } |
There was a problem hiding this comment.
Better add else branch here.
| } | ||
|
|
||
| Datum | ||
| convert_from_function(Datum value, int32 typmod, Oid funcId, bool *is_failed) |
There was a problem hiding this comment.
Why is the error handling undetermined?
7c1d1e5 to
c3b4c2b
Compare
737228d to
fde465f
Compare
* Add README for try_convert extension
| @@ -0,0 +1,92 @@ | |||
| # TRY_CONVERT | |||
|
|
|||
| TRY_CONVERT is Greenplum extension, which adds function for error-safe type cast like [TRY_CAST from SQL-Server](https://learn.microsoft.com/ru-ru/sql/t-sql/functions/try-cast-transact-sql?view=sql-server-ver16) | |||
There was a problem hiding this comment.
| TRY_CONVERT is Greenplum extension, which adds function for error-safe type cast like [TRY_CAST from SQL-Server](https://learn.microsoft.com/ru-ru/sql/t-sql/functions/try-cast-transact-sql?view=sql-server-ver16) | |
| TRY_CONVERT is Greenplum/Cloudberry extension, which adds function for error-safe type cast like [TRY_CAST from SQL-Server](https://learn.microsoft.com/ru-ru/sql/t-sql/functions/try-cast-transact-sql?view=sql-server-ver16) |
|
|
||
| ## Why signature is so strange? | ||
|
|
||
| Greenplum function polymorphism accept to have polymorphic functions only one any type in signature. |
There was a problem hiding this comment.
| Greenplum function polymorphism accept to have polymorphic functions only one any type in signature. | |
| Greenplum/Cloudberry function polymorphism accept to have polymorphic functions only one any type in signature. |
|
Hi @robozmey thanks for your updates! Now the license headers look good to me. Please make sure these files are originally created by our community members, not cherry-picked or copied from other projects. Before merging, welcome to squash your commits into one and revise the commit message body, you can take this template as a reference. |
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing. Query cancellation and assertion failures are re-thrown
rather than swallowed, following what plpgsql does for "EXCEPTION WHEN
others". Once the input functions are converted to the soft error
handling infrastructure of PostgreSQL 17, the PG_TRY() block can go
away.
Polymorphism only accepts a single "any" type per signature, hence the
default value carrying the target type. The built-in types are
registered by the extension script; add_type_for_try_convert(regtype)
registers additional ones, for example the hstore and citext types.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
The regression test is derived from the catalog files and from the
sample values in contrib/try_convert/data/, so "make installcheck"
generates it instead of the tree carrying it. The ic-contrib job of the
build workflows runs it.
The extension was written by Vladimir Rachkin and proposed in PR#901;
this commit rebases that work and addresses the review comments
left on it.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <apache#901>
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing. Query cancellation and assertion failures are re-thrown
rather than swallowed, following what plpgsql does for "EXCEPTION WHEN
others". Once the input functions are converted to the soft error
handling infrastructure of PostgreSQL 17, the PG_TRY() block can go
away.
Polymorphism only accepts a single "any" type per signature, hence the
default value carrying the target type. The built-in types are
registered by the extension script; add_type_for_try_convert(regtype)
registers additional ones, for example the hstore and citext types.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
The regression test is derived from the catalog files and from the
sample values in contrib/try_convert/data/, so "make installcheck"
generates it instead of the tree carrying it. The ic-contrib job of the
build workflows runs it.
The extension was written by Vladimir Rachkin and proposed in PR#901;
this commit rebases that work and addresses the review comments
left on it.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <apache#901>
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <apache#901>
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <apache#901>
|
I don't have push access to the original fork, and the head branch of an existing PR can't be changed, so instead of updating this one I opened a separate PR #1872 with the rebased version. All credit for the extension goes to @robozmey - the commit lists him as a co-author. On top of the rebase I addressed the open review comments, pulled in the follow-up fixes the extension got in open-gpdb since this PR was opened, added the module to the ic-contrib CI matrix (nothing was running its tests before), and marked the extension trusted so that a non-superuser with CREATE privilege on the database can install it. |
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <apache#901>
|
Maybe we can close this PR since we have a new one. |
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <apache#901>
TRY_CONVERT(source_value, default_value) casts source_value to the type
of default_value and returns default_value whenever the cast fails,
which is the behaviour of TRY_CAST in SQL Server. Without it a single
malformed value makes the whole query fail, and the plpgsql workarounds
that catch the error per row are several times slower.
TRY_CONVERT('42'::text, NULL::int2) -- returns 42::int2
TRY_CONVERT('42d'::text, NULL::int2) -- returns NULL::int2
TRY_CONVERT('42d'::text, 1234::int2) -- returns 1234::int2
The conversion to use is resolved the same way the parser resolves an
explicit cast in coerce_type(): a pg_cast entry, an I/O conversion or a
binary-compatible relabel, followed by the length coercion of the
target type. Casts between array types and casts to domain types are
not supported and are reported as query errors, the same as a cast that
does not exist at all; only a failure caused by the converted data is
turned into the default value.
The cast itself runs inside a PG_TRY() block, since the datatype input
functions of Cloudberry cannot yet report a conversion failure without
throwing.
The extension is marked trusted, so the owner of a database can install
it without being a superuser.
Co-authored-by: Vladimir Rachkin <vova@kpnn.ru>
See: PR#901 <#901>
Extension TRY_CONVERT adds function TRY_CONVERT
TRY_CONVERT was made to use like TRY_CAST from SQL-Server
Due polymorphism have strange signature (some_type, anyelement) -> anyelement
First parament is SOURCE_VALUE
Second parameter is DEFAULT_VALUE::TARGET_TYPE
We cannot have (any1, any2) -> any2 signature with different anyelement types, but we can create multiple (_, any) -> any functions in
contrib/try_convert/try_convert--1.0.sqlor useselect add_type_for_try_convert('date'::regtype);to add types.In init we can add all supported types, but with
add_type_for_try_convertuser can add whatever type he wantsERROR HANDLING
Error handles by PG_TRY() PG_CATCH()
But better way is use "soft" error handling from Postgres 17 (postgres/postgres@ccff2d2) it also realising OPENGPDB (open-gpdb/gpdb@21be368). Of course it needs to convert datatype function to support "soft" error handling
Fixes #ISSUE_Number
What does this PR do?
Type of Change
Breaking Changes
Test Plan
make installcheckmake -C src/test installcheck-cbdb-parallelImpact
Performance:
User-facing changes:
Dependencies:
Checklist
Additional Context
CI Skip Instructions