v16-0004-error-safe-for-casting-text-to-other-types-per-pg_cast.patch
application/x-patch
Filename: v16-0004-error-safe-for-casting-text-to-other-types-per-pg_cast.patch
Type: application/x-patch
Part: 19
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v16-0004
Subject: error safe for casting text to other types per pg_cast
| File | + | − |
|---|---|---|
| src/backend/catalog/namespace.c | 47 | 11 |
| src/backend/utils/adt/regproc.c | 10 | 3 |
| src/backend/utils/adt/varlena.c | 8 | 2 |
| src/backend/utils/adt/xml.c | 1 | 1 |
| src/include/catalog/namespace.h | 6 | 0 |
| src/include/utils/varlena.h | 1 | 0 |
From 3fce1c0eb706c1c6f036e986becb13d7c672d564 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 12 Dec 2025 15:31:17 +0800
Subject: [PATCH v16 04/23] error safe for casting text to other types per
pg_cast
select castsource::regtype, casttarget::regtype, castfunc,
castcontext,castmethod, pp.prosrc, pp.proname from pg_cast pc join pg_proc pp on
pp.oid = pc.castfunc and pc.castfunc > 0
and castsource::regtype = 'text'::regtype
order by castsource::regtype;
castsource | casttarget | castfunc | castcontext | castmethod | prosrc | proname
------------+------------+----------+-------------+------------+---------------+----------
text | regclass | 1079 | i | f | text_regclass | regclass
text | "char" | 944 | a | f | text_char | char
text | name | 407 | i | f | text_name | name
text | xml | 2896 | e | f | texttoxml | xml
(4 rows)
already error safe: text_name, text_char.
texttoxml is refactored in character type error safe patch.
discussion: https://postgr.es/m/CADkLM=fv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ@mail.gmail.com
---
src/backend/catalog/namespace.c | 58 ++++++++++++++++++++++++++-------
src/backend/utils/adt/regproc.c | 13 ++++++--
src/backend/utils/adt/varlena.c | 10 ++++--
src/backend/utils/adt/xml.c | 2 +-
src/include/catalog/namespace.h | 6 ++++
src/include/utils/varlena.h | 1 +
6 files changed, 73 insertions(+), 17 deletions(-)
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index c94089caa58..bd25eb4550d 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -440,6 +440,16 @@ Oid
RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
uint32 flags,
RangeVarGetRelidCallback callback, void *callback_arg)
+{
+ return RangeVarGetRelidExtendedSafe(relation, lockmode, flags,
+ callback, callback_arg,
+ NULL);
+}
+
+Oid
+RangeVarGetRelidExtendedSafe(const RangeVar *relation, LOCKMODE lockmode, uint32 flags,
+ RangeVarGetRelidCallback callback, void *callback_arg,
+ Node *escontext)
{
uint64 inval_count;
Oid relId;
@@ -456,7 +466,7 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
if (relation->catalogname)
{
if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
- ereport(ERROR,
+ ereturn(escontext, InvalidOid,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
relation->catalogname, relation->schemaname,
@@ -513,7 +523,7 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
* return InvalidOid.
*/
if (namespaceId != myTempNamespace)
- ereport(ERROR,
+ ereturn(escontext, InvalidOid,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("temporary tables cannot specify a schema name")));
}
@@ -593,13 +603,23 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
{
int elevel = (flags & RVR_SKIP_LOCKED) ? DEBUG1 : ERROR;
- if (relation->schemaname)
- ereport(elevel,
+ if (relation->schemaname && elevel == DEBUG1)
+ ereport(DEBUG1,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on relation \"%s.%s\"",
relation->schemaname, relation->relname)));
- else
- ereport(elevel,
+ else if (relation->schemaname && elevel == ERROR)
+ ereturn(escontext, InvalidOid,
+ errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("could not obtain lock on relation \"%s.%s\"",
+ relation->schemaname, relation->relname));
+ else if (elevel == DEBUG1)
+ ereport(DEBUG1,
+ errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("could not obtain lock on relation \"%s\"",
+ relation->relname));
+ else if (elevel == ERROR)
+ ereturn(escontext, InvalidOid,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on relation \"%s\"",
relation->relname)));
@@ -626,13 +646,23 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
{
int elevel = missing_ok ? DEBUG1 : ERROR;
- if (relation->schemaname)
- ereport(elevel,
+ if (relation->schemaname && elevel == DEBUG1)
+ ereport(DEBUG1,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s.%s\" does not exist",
relation->schemaname, relation->relname)));
- else
- ereport(elevel,
+ else if (relation->schemaname && elevel == ERROR)
+ ereturn(escontext, InvalidOid,
+ errcode(ERRCODE_UNDEFINED_TABLE),
+ errmsg("relation \"%s.%s\" does not exist",
+ relation->schemaname, relation->relname));
+ else if (elevel == DEBUG1)
+ ereport(DEBUG1,
+ errcode(ERRCODE_UNDEFINED_TABLE),
+ errmsg("relation \"%s\" does not exist",
+ relation->relname));
+ else if (elevel == ERROR)
+ ereturn(escontext, InvalidOid,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist",
relation->relname)));
@@ -3622,6 +3652,12 @@ get_namespace_oid(const char *nspname, bool missing_ok)
*/
RangeVar *
makeRangeVarFromNameList(const List *names)
+{
+ return makeRangeVarFromNameListSafe(names, NULL);
+}
+
+RangeVar *
+makeRangeVarFromNameListSafe(const List *names, Node *escontext)
{
RangeVar *rel = makeRangeVar(NULL, NULL, -1);
@@ -3640,7 +3676,7 @@ makeRangeVarFromNameList(const List *names)
rel->relname = strVal(lthird(names));
break;
default:
- ereport(ERROR,
+ ereturn(escontext, NULL,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper relation name (too many dotted names): %s",
NameListToString(names))));
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index e5c2246f2c9..59cc508f805 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -1901,12 +1901,19 @@ text_regclass(PG_FUNCTION_ARGS)
text *relname = PG_GETARG_TEXT_PP(0);
Oid result;
RangeVar *rv;
+ List *namelist;
- rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
+ namelist = textToQualifiedNameListSafe(relname, fcinfo->context);
+ if (SOFT_ERROR_OCCURRED(fcinfo->context))
+ PG_RETURN_NULL();
+
+ rv = makeRangeVarFromNameListSafe(namelist, fcinfo->context);
+ if (SOFT_ERROR_OCCURRED(fcinfo->context))
+ PG_RETURN_NULL();
/* We might not even have permissions on this relation; don't lock it. */
- result = RangeVarGetRelid(rv, NoLock, false);
-
+ result = RangeVarGetRelidExtendedSafe(rv, NoLock, 0, NULL, NULL,
+ fcinfo->context);
PG_RETURN_OID(result);
}
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index baa5b44ea8d..ccd601ec34c 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -2695,6 +2695,12 @@ name_text(PG_FUNCTION_ARGS)
*/
List *
textToQualifiedNameList(text *textval)
+{
+ return textToQualifiedNameListSafe(textval, NULL);
+}
+
+List *
+textToQualifiedNameListSafe(text *textval, Node *escontext)
{
char *rawname;
List *result = NIL;
@@ -2706,12 +2712,12 @@ textToQualifiedNameList(text *textval)
rawname = text_to_cstring(textval);
if (!SplitIdentifierString(rawname, '.', &namelist))
- ereport(ERROR,
+ ereturn(escontext, NIL,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax")));
if (namelist == NIL)
- ereport(ERROR,
+ ereturn(escontext, NIL,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax")));
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 6301115d625..dd0955d1e44 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -1043,7 +1043,7 @@ xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, Node
return (xmltype *) data;
#else
- ereturn(escontext, NULL
+ ereturn(escontext, NULL,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unsupported XML feature"),
errdetail("This functionality requires the server to be built with libxml support."));
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index f1423f28c32..ab61af55ddc 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -103,6 +103,11 @@ extern Oid RangeVarGetRelidExtended(const RangeVar *relation,
LOCKMODE lockmode, uint32 flags,
RangeVarGetRelidCallback callback,
void *callback_arg);
+extern Oid RangeVarGetRelidExtendedSafe(const RangeVar *relation,
+ LOCKMODE lockmode, uint32 flags,
+ RangeVarGetRelidCallback callback,
+ void *callback_arg,
+ Node *escontext);
extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation);
extern Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation,
LOCKMODE lockmode,
@@ -168,6 +173,7 @@ extern Oid LookupCreationNamespace(const char *nspname);
extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid);
extern Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(const List *names);
+extern RangeVar *makeRangeVarFromNameListSafe(const List *names, Node *escontext);
extern char *NameListToString(const List *names);
extern char *NameListToQuotedString(const List *names);
diff --git a/src/include/utils/varlena.h b/src/include/utils/varlena.h
index db9fdf72941..0cf01ae5281 100644
--- a/src/include/utils/varlena.h
+++ b/src/include/utils/varlena.h
@@ -27,6 +27,7 @@ extern int varstr_levenshtein_less_equal(const char *source, int slen,
int ins_c, int del_c, int sub_c,
int max_d, bool trusted);
extern List *textToQualifiedNameList(text *textval);
+extern List *textToQualifiedNameListSafe(text *textval, Node *escontext);
extern bool SplitIdentifierString(char *rawstring, char separator,
List **namelist);
extern bool SplitDirectoriesString(char *rawstring, char separator,
--
2.34.1