Re: Error-safe user functions - Mailing list pgsql-hackers

From Tom Lane
Subject Re: Error-safe user functions
Date
Msg-id 3910031.1672095600@sss.pgh.pa.us
Whole thread Raw
In response to Re: Error-safe user functions  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Error-safe user functions  (Andrew Dunstan <andrew@dunslane.net>)
List pgsql-hackers
I wrote:
> (Perhaps we should go further than this, and convert all these
> functions to just be DirectInputFunctionCallSafe wrappers
> around the corresponding input functions?  That would save
> some duplicative code, but I've not done it here.)

I looked closer at that idea, and realized that it would do more than
just save some code: it'd cause the to_regfoo functions to accept
numeric OIDs, as they did not before (and are documented not to).
It is unclear to me whether that inconsistency with the input
functions is really desirable or not --- but I don't offhand see a
good argument for it.  If we change this though, it should probably
happen in a separate commit.  Accordingly, here's a delta patch
doing that.

            regards, tom lane

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 836b9254fb..3bf8d021c3 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24100,8 +24100,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regclass</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>

@@ -24118,8 +24117,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regcollation</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>

@@ -24136,8 +24134,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regnamespace</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>

@@ -24154,8 +24151,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regoper</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found or is ambiguous.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found or is ambiguous.
        </para></entry>
       </row>

@@ -24172,8 +24168,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regoperator</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>

@@ -24190,8 +24185,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regproc</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found or is ambiguous.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found or is ambiguous.
        </para></entry>
       </row>

@@ -24208,8 +24202,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regprocedure</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>

@@ -24226,8 +24219,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regrole</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>

@@ -24244,8 +24236,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         obtained by casting the string to type <type>regtype</type> (see
         <xref linkend="datatype-oid"/>); however, this function will return
         <literal>NULL</literal> rather than throwing an error if the name is
-        not found.  Also unlike the cast, this does not accept
-        a numeric OID as input.
+        not found.
        </para></entry>
       </row>
      </tbody>
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 14d76c856d..3635a94633 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -118,24 +118,15 @@ Datum
 to_regproc(PG_FUNCTION_ARGS)
 {
     char       *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    List       *names;
-    FuncCandidateList clist;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Parse the name into components and see if it matches any pg_proc
-     * entries in the current search path.
-     */
-    names = stringToQualifiedNameList(pro_name, (Node *) &escontext);
-    if (names == NIL)
-        PG_RETURN_NULL();
-
-    clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
-
-    if (clist == NULL || clist->next != NULL)
+    if (!DirectInputFunctionCallSafe(regprocin, pro_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
-
-    PG_RETURN_OID(clist->oid);
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -287,31 +278,15 @@ Datum
 to_regprocedure(PG_FUNCTION_ARGS)
 {
     char       *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    List       *names;
-    int            nargs;
-    Oid            argtypes[FUNC_MAX_ARGS];
-    FuncCandidateList clist;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Parse the name and arguments, look up potential matches in the current
-     * namespace search list, and scan to see which one exactly matches the
-     * given argument types.    (There will not be more than one match.)
-     */
-    if (!parseNameAndArgTypes(pro_name, false,
-                              &names, &nargs, argtypes,
-                              (Node *) &escontext))
+    if (!DirectInputFunctionCallSafe(regprocedurein, pro_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
-
-    clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true);
-
-    for (; clist; clist = clist->next)
-    {
-        if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
-            PG_RETURN_OID(clist->oid);
-    }
-
-    PG_RETURN_NULL();
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -552,24 +527,15 @@ Datum
 to_regoper(PG_FUNCTION_ARGS)
 {
     char       *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    List       *names;
-    FuncCandidateList clist;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Parse the name into components and see if it matches any pg_operator
-     * entries in the current search path.
-     */
-    names = stringToQualifiedNameList(opr_name, (Node *) &escontext);
-    if (names == NIL)
+    if (!DirectInputFunctionCallSafe(regoperin, opr_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
-
-    clist = OpernameGetCandidates(names, '\0', true);
-
-    if (clist == NULL || clist->next != NULL)
-        PG_RETURN_NULL();
-
-    PG_RETURN_OID(clist->oid);
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -728,31 +694,15 @@ Datum
 to_regoperator(PG_FUNCTION_ARGS)
 {
     char       *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    Oid            result;
-    List       *names;
-    int            nargs;
-    Oid            argtypes[FUNC_MAX_ARGS];
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Parse the name and arguments, look up potential matches in the current
-     * namespace search list, and scan to see which one exactly matches the
-     * given argument types.    (There will not be more than one match.)
-     */
-    if (!parseNameAndArgTypes(opr_name_or_oid, true,
-                              &names, &nargs, argtypes,
-                              (Node *) &escontext))
-        PG_RETURN_NULL();
-
-    if (nargs != 2)
+    if (!DirectInputFunctionCallSafe(regoperatorin, opr_name_or_oid,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
-
-    result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
-
-    if (!OidIsValid(result))
-        PG_RETURN_NULL();
-
-    PG_RETURN_OID(result);
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -975,25 +925,15 @@ Datum
 to_regclass(PG_FUNCTION_ARGS)
 {
     char       *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    Oid            result;
-    List       *names;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Parse the name into components and see if it matches any pg_class
-     * entries in the current search path.
-     */
-    names = stringToQualifiedNameList(class_name, (Node *) &escontext);
-    if (names == NIL)
-        PG_RETURN_NULL();
-
-    /* We might not even have permissions on this relation; don't lock it. */
-    result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
-
-    if (OidIsValid(result))
-        PG_RETURN_OID(result);
-    else
+    if (!DirectInputFunctionCallSafe(regclassin, class_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -1128,24 +1068,15 @@ Datum
 to_regcollation(PG_FUNCTION_ARGS)
 {
     char       *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    Oid            result;
-    List       *names;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Parse the name into components and see if it matches any pg_collation
-     * entries in the current search path.
-     */
-    names = stringToQualifiedNameList(collation_name, (Node *) &escontext);
-    if (names == NIL)
-        PG_RETURN_NULL();
-
-    result = get_collation_oid(names, true);
-
-    if (OidIsValid(result))
-        PG_RETURN_OID(result);
-    else
+    if (!DirectInputFunctionCallSafe(regcollationin, collation_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -1278,17 +1209,15 @@ Datum
 to_regtype(PG_FUNCTION_ARGS)
 {
     char       *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    Oid            result;
-    int32        typmod;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    /*
-     * Invoke the full parser to deal with special cases such as array syntax.
-     */
-    if (parseTypeString(typ_name, &result, &typmod, (Node *) &escontext))
-        PG_RETURN_OID(result);
-    else
+    if (!DirectInputFunctionCallSafe(regtypein, typ_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -1634,23 +1563,15 @@ Datum
 to_regrole(PG_FUNCTION_ARGS)
 {
     char       *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    Oid            result;
-    List       *names;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    names = stringToQualifiedNameList(role_name, (Node *) &escontext);
-    if (names == NIL)
-        PG_RETURN_NULL();
-
-    if (list_length(names) != 1)
-        PG_RETURN_NULL();
-
-    result = get_role_oid(strVal(linitial(names)), true);
-
-    if (OidIsValid(result))
-        PG_RETURN_OID(result);
-    else
+    if (!DirectInputFunctionCallSafe(regrolein, role_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
+    PG_RETURN_DATUM(result);
 }

 /*
@@ -1759,23 +1680,15 @@ Datum
 to_regnamespace(PG_FUNCTION_ARGS)
 {
     char       *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
-    Oid            result;
-    List       *names;
+    Datum        result;
     ErrorSaveContext escontext = {T_ErrorSaveContext};

-    names = stringToQualifiedNameList(nsp_name, (Node *) &escontext);
-    if (names == NIL)
-        PG_RETURN_NULL();
-
-    if (list_length(names) != 1)
-        PG_RETURN_NULL();
-
-    result = get_namespace_oid(strVal(linitial(names)), true);
-
-    if (OidIsValid(result))
-        PG_RETURN_OID(result);
-    else
+    if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
+                                     InvalidOid, -1,
+                                     (Node *) &escontext,
+                                     &result))
         PG_RETURN_NULL();
+    PG_RETURN_DATUM(result);
 }

 /*

pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: Passing relation metadata to Exec routine
Next
From: Michael Paquier
Date:
Subject: Re: [PATCH] Teach pg_waldump to extract FPIs from the WAL