Re: [PATCH] Add some documentation on how to call internal functions - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [PATCH] Add some documentation on how to call internal functions
Date
Msg-id 933739.1729283023@sss.pgh.pa.us
Whole thread Raw
In response to Re: [PATCH] Add some documentation on how to call internal functions  (Pavel Stehule <pavel.stehule@gmail.com>)
Responses Re: [PATCH] Add some documentation on how to call internal functions
List pgsql-hackers
Pavel Stehule <pavel.stehule@gmail.com> writes:
> I'll mark this patch as ready for committer

I spent a little time looking at this.  I agree that it's better to
show conversion of the example function's arguments to and from text*
rather than leaving them as Datum.  I also do think that we need to
incorporate the example into src/tutorial, if only because that
provides a chance to test it.  And indeed, testing exposed that the
example doesn't work:

$ cd src/tutorial
$ make
$ psql postgres
psql (18devel)
Type "help" for help.

postgres=# \i funcs.sql

psql:funcs.sql:152: ERROR:  could not determine which collation to use for string comparison
HINT:  Use the COLLATE clause to set the collation explicitly.

The problem here is that we failed to pass through the result of
PG_GET_COLLATION() to text_starts_with.  We could do that, certainly,
for a couple more lines of code.  But it feels like this is getting
into details that obscure the main point.  I wonder if it'd be better
to choose a different example that calls a non-collation-dependent
target function.

Anyway, proposed v3 attached.  I folded the two patches into one,
and editorialized on the text a little.

            regards, tom lane

diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index af7864a1b5..03fa7633ef 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -2384,6 +2384,48 @@ PG_FUNCTION_INFO_V1(funcname);
      takes as its argument the actual value to return.
     </para>

+    <para>
+     To call another version-1 function, you can use
+     <function>DirectFunctionCall<replaceable>n</replaceable>(func,
+     arg1, ..., argn)</function>.  This is particularly useful when you want
+     to call functions defined in the standard internal library, by using an
+     interface similar to their SQL signature.
+    </para>
+
+    <para>
+     These convenience functions and similar ones can be found
+     in <filename>fmgr.h</filename>.
+     The <function>DirectFunctionCall<replaceable>n</replaceable></function>
+     family expect a C function name as their first argument.  There are also
+     <function>OidFunctionCall<replaceable>n</replaceable></function> which
+     take the OID of the target function, and some other variants.  All of
+     these expect the function's arguments to be supplied
+     as <type>Datum</type>s, and likewise they return <type>Datum</type>.
+     Note that neither arguments nor result are allowed to be NULL when
+     using these convenience functions.
+    </para>
+
+    <para>
+     For example, to call the <function>starts_with(text, text)</function>
+     function from C, you can search through the catalog and find out that
+     its C implementation is the
+     <function>Datum text_starts_with(PG_FUNCTION_ARGS)</function> function.
+     So you would use <literal>DirectFunctionCall2(text_starts_with,
+     ...)</literal> to call it.
+    </para>
+
+    <para>
+     <filename>fmgr.h</filename> also supplies macros that facilitate
+     conversions between C types and <type>Datum</type>.  For example to
+     turn <type>Datum</type> into <type>text*</type>, you can
+     use <function>DatumGetTextPP(X)</function>.  While some types have macros
+     named like <function>TypeGetDatum(X)</function> for the reverse
+     conversion, <type>text*</type> does not; it's sufficient to use the
+     generic macro <function>PointerGetDatum(X)</function> for that.
+     If your extension defines additional types, it is usually convenient to
+     define similar macros for your types too.
+    </para>
+
     <para>
      Here are some examples using the version-1 calling convention:
     </para>
@@ -2482,6 +2524,23 @@ concat_text(PG_FUNCTION_ARGS)
     memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
     PG_RETURN_TEXT_P(new_text);
 }
+
+/* A wrapper around starts_with(text, text) */
+
+PG_FUNCTION_INFO_V1(t_starts_with);
+
+Datum
+t_starts_with(PG_FUNCTION_ARGS)
+{
+    text       *t1 = PG_GETARG_TEXT_PP(0);
+    text       *t2 = PG_GETARG_TEXT_PP(1);
+    bool        result;
+
+    result = DatumGetBool(DirectFunctionCall2(text_starts_with,
+                                              PointerGetDatum(t1),
+                                              PointerGetDatum(t2)));
+    PG_RETURN_BOOL(result);
+}
 ]]>
 </programlisting>

@@ -2513,6 +2572,10 @@ CREATE FUNCTION copytext(text) RETURNS text
 CREATE FUNCTION concat_text(text, text) RETURNS text
      AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
      LANGUAGE C STRICT;
+
+CREATE FUNCTION t_starts_with(text, text) RETURNS boolean
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 't_starts_with'
+     LANGUAGE C STRICT;
 </programlisting>

     <para>
diff --git a/src/tutorial/funcs.c b/src/tutorial/funcs.c
index f597777a1f..73ecc023b1 100644
--- a/src/tutorial/funcs.c
+++ b/src/tutorial/funcs.c
@@ -11,6 +11,7 @@
 #include "postgres.h"            /* general Postgres declarations */

 #include "executor/executor.h"    /* for GetAttributeByName() */
+#include "utils/fmgrprotos.h"    /* for text_starts_with() */
 #include "utils/geo_decls.h"    /* for point type */

 PG_MODULE_MAGIC;
@@ -102,6 +103,23 @@ concat_text(PG_FUNCTION_ARGS)
     PG_RETURN_TEXT_P(new_text);
 }

+/* A wrapper around starts_with(text, text) */
+
+PG_FUNCTION_INFO_V1(t_starts_with);
+
+Datum
+t_starts_with(PG_FUNCTION_ARGS)
+{
+    text       *t1 = PG_GETARG_TEXT_PP(0);
+    text       *t2 = PG_GETARG_TEXT_PP(1);
+    bool        result;
+
+    result = DatumGetBool(DirectFunctionCall2(text_starts_with,
+                                              PointerGetDatum(t1),
+                                              PointerGetDatum(t2)));
+    PG_RETURN_BOOL(result);
+}
+
 /* Composite types */

 PG_FUNCTION_INFO_V1(c_overpaid);
diff --git a/src/tutorial/funcs.source b/src/tutorial/funcs.source
index 542b5c81ec..eb56153754 100644
--- a/src/tutorial/funcs.source
+++ b/src/tutorial/funcs.source
@@ -123,16 +123,25 @@ SELECT * FROM EMP;
 -----------------------------

 CREATE FUNCTION add_one(integer) RETURNS integer
-   AS '_OBJWD_/funcs' LANGUAGE C;
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;
+
+CREATE FUNCTION add_one(double precision) RETURNS double precision
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;

 CREATE FUNCTION makepoint(point, point) RETURNS point
-   AS '_OBJWD_/funcs' LANGUAGE C;
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;

 CREATE FUNCTION copytext(text) RETURNS text
-   AS '_OBJWD_/funcs' LANGUAGE C;
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;
+
+CREATE FUNCTION concat_text(text, text) RETURNS text
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;
+
+CREATE FUNCTION t_starts_with(text, text) RETURNS boolean
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;

 CREATE FUNCTION c_overpaid(EMP, integer) RETURNS boolean
-   AS '_OBJWD_/funcs' LANGUAGE C;
+   AS '_OBJWD_/funcs' LANGUAGE C STRICT;

 SELECT add_one(3) AS four;

@@ -140,6 +149,8 @@ SELECT makepoint('(1,2)'::point, '(3,4)'::point ) AS newpoint;

 SELECT copytext('hello world!');

+SELECT t_starts_with('foobar', 'foo');
+
 SELECT name, c_overpaid(EMP, 1500) AS overpaid
 FROM EMP
 WHERE name = 'Bill' or name = 'Sam';
@@ -147,10 +158,13 @@ WHERE name = 'Bill' or name = 'Sam';
 -- remove functions that were created in this file

 DROP FUNCTION c_overpaid(EMP, integer);
+DROP FUNCTION t_starts_with(text, text);
+DROP FUNCTION concat_text(text, text);
 DROP FUNCTION copytext(text);
 DROP FUNCTION makepoint(point, point);
+DROP FUNCTION add_one(double precision);
 DROP FUNCTION add_one(integer);
---DROP FUNCTION clean_EMP();
+DROP FUNCTION clean_EMP();
 DROP FUNCTION high_pay();
 DROP FUNCTION new_emp();
 DROP FUNCTION add_em(integer, integer);

pgsql-hackers by date:

Previous
From: Mark Hill
Date:
Subject: msvc directory missing in PostgreSQL 17.0
Next
From: "Devulapalli, Raghuveer"
Date:
Subject: RE: Proposal for Updating CRC32C with AVX-512 Algorithm.