Skip to content

Commit 86e4efc

Browse files
committed
Add documentation about calling version-1 C functions from C.
This topic wasn't really covered before, so fill in some details. Author: Florents Tselai <florents.tselai@gmail.com> Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/90853055-5BBD-493D-91E5-721677C7C59B@gmail.com
1 parent 43830ec commit 86e4efc

File tree

3 files changed

+112
-5
lines changed

3 files changed

+112
-5
lines changed

doc/src/sgml/xfunc.sgml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,6 +2384,56 @@ PG_FUNCTION_INFO_V1(funcname);
23842384
takes as its argument the actual value to return.
23852385
</para>
23862386

2387+
<para>
2388+
To call another version-1 function, you can use
2389+
<function>DirectFunctionCall<replaceable>n</replaceable>(func,
2390+
arg1, ..., argn)</function>. This is particularly useful when you want
2391+
to call functions defined in the standard internal library, by using an
2392+
interface similar to their SQL signature.
2393+
</para>
2394+
2395+
<para>
2396+
These convenience functions and similar ones can be found
2397+
in <filename>fmgr.h</filename>.
2398+
The <function>DirectFunctionCall<replaceable>n</replaceable></function>
2399+
family expect a C function name as their first argument. There are also
2400+
<function>OidFunctionCall<replaceable>n</replaceable></function> which
2401+
take the OID of the target function, and some other variants. All of
2402+
these expect the function's arguments to be supplied
2403+
as <type>Datum</type>s, and likewise they return <type>Datum</type>.
2404+
Note that neither arguments nor result are allowed to be NULL when
2405+
using these convenience functions.
2406+
</para>
2407+
2408+
<para>
2409+
For example, to call the <function>starts_with(text, text)</function>
2410+
function from C, you can search through the catalog and find out that
2411+
its C implementation is the
2412+
<function>Datum text_starts_with(PG_FUNCTION_ARGS)</function>
2413+
function. Typically you would
2414+
use <literal>DirectFunctionCall2(text_starts_with, ...)</literal> to
2415+
call such a function. However, <function>starts_with(text,
2416+
text)</function> requires collation information, so it will fail
2417+
with <quote>could not determine which collation to use for string
2418+
comparison</quote> if called that way. Instead you must
2419+
use <literal>DirectFunctionCall2Coll(text_starts_with, ...)</literal>
2420+
and provide the desired collation, which typically is just passed
2421+
through from <function>PG_GET_COLLATION()</function>, as shown in the
2422+
example below.
2423+
</para>
2424+
2425+
<para>
2426+
<filename>fmgr.h</filename> also supplies macros that facilitate
2427+
conversions between C types and <type>Datum</type>. For example to
2428+
turn <type>Datum</type> into <type>text*</type>, you can
2429+
use <function>DatumGetTextPP(X)</function>. While some types have macros
2430+
named like <function>TypeGetDatum(X)</function> for the reverse
2431+
conversion, <type>text*</type> does not; it's sufficient to use the
2432+
generic macro <function>PointerGetDatum(X)</function> for that.
2433+
If your extension defines additional types, it is usually convenient to
2434+
define similar macros for your types too.
2435+
</para>
2436+
23872437
<para>
23882438
Here are some examples using the version-1 calling convention:
23892439
</para>
@@ -2482,6 +2532,25 @@ concat_text(PG_FUNCTION_ARGS)
24822532
memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
24832533
PG_RETURN_TEXT_P(new_text);
24842534
}
2535+
2536+
/* A wrapper around starts_with(text, text) */
2537+
2538+
PG_FUNCTION_INFO_V1(t_starts_with);
2539+
2540+
Datum
2541+
t_starts_with(PG_FUNCTION_ARGS)
2542+
{
2543+
text *t1 = PG_GETARG_TEXT_PP(0);
2544+
text *t2 = PG_GETARG_TEXT_PP(1);
2545+
Oid collid = PG_GET_COLLATION();
2546+
bool result;
2547+
2548+
result = DatumGetBool(DirectFunctionCall2Coll(text_starts_with,
2549+
collid,
2550+
PointerGetDatum(t1),
2551+
PointerGetDatum(t2)));
2552+
PG_RETURN_BOOL(result);
2553+
}
24852554
]]>
24862555
</programlisting>
24872556

@@ -2513,6 +2582,10 @@ CREATE FUNCTION copytext(text) RETURNS text
25132582
CREATE FUNCTION concat_text(text, text) RETURNS text
25142583
AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
25152584
LANGUAGE C STRICT;
2585+
2586+
CREATE FUNCTION t_starts_with(text, text) RETURNS boolean
2587+
AS '<replaceable>DIRECTORY</replaceable>/funcs', 't_starts_with'
2588+
LANGUAGE C STRICT;
25162589
</programlisting>
25172590

25182591
<para>

src/tutorial/funcs.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "postgres.h" /* general Postgres declarations */
1212

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

1617
PG_MODULE_MAGIC;
@@ -102,6 +103,25 @@ concat_text(PG_FUNCTION_ARGS)
102103
PG_RETURN_TEXT_P(new_text);
103104
}
104105

106+
/* A wrapper around starts_with(text, text) */
107+
108+
PG_FUNCTION_INFO_V1(t_starts_with);
109+
110+
Datum
111+
t_starts_with(PG_FUNCTION_ARGS)
112+
{
113+
text *t1 = PG_GETARG_TEXT_PP(0);
114+
text *t2 = PG_GETARG_TEXT_PP(1);
115+
Oid collid = PG_GET_COLLATION();
116+
bool result;
117+
118+
result = DatumGetBool(DirectFunctionCall2Coll(text_starts_with,
119+
collid,
120+
PointerGetDatum(t1),
121+
PointerGetDatum(t2)));
122+
PG_RETURN_BOOL(result);
123+
}
124+
105125
/* Composite types */
106126

107127
PG_FUNCTION_INFO_V1(c_overpaid);

src/tutorial/funcs.source

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,34 +123,48 @@ SELECT * FROM EMP;
123123
-----------------------------
124124

125125
CREATE FUNCTION add_one(integer) RETURNS integer
126-
AS '_OBJWD_/funcs' LANGUAGE C;
126+
AS '_OBJWD_/funcs' LANGUAGE C STRICT;
127+
128+
CREATE FUNCTION add_one(double precision) RETURNS double precision
129+
AS '_OBJWD_/funcs' LANGUAGE C STRICT;
127130

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

131134
CREATE FUNCTION copytext(text) RETURNS text
132-
AS '_OBJWD_/funcs' LANGUAGE C;
135+
AS '_OBJWD_/funcs' LANGUAGE C STRICT;
136+
137+
CREATE FUNCTION concat_text(text, text) RETURNS text
138+
AS '_OBJWD_/funcs' LANGUAGE C STRICT;
139+
140+
CREATE FUNCTION t_starts_with(text, text) RETURNS boolean
141+
AS '_OBJWD_/funcs' LANGUAGE C STRICT;
133142

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

137146
SELECT add_one(3) AS four;
138147

139148
SELECT makepoint('(1,2)'::point, '(3,4)'::point ) AS newpoint;
140149

141150
SELECT copytext('hello world!');
142151

152+
SELECT t_starts_with('foobar', 'foo');
153+
143154
SELECT name, c_overpaid(EMP, 1500) AS overpaid
144155
FROM EMP
145156
WHERE name = 'Bill' or name = 'Sam';
146157

147158
-- remove functions that were created in this file
148159

149160
DROP FUNCTION c_overpaid(EMP, integer);
161+
DROP FUNCTION t_starts_with(text, text);
162+
DROP FUNCTION concat_text(text, text);
150163
DROP FUNCTION copytext(text);
151164
DROP FUNCTION makepoint(point, point);
165+
DROP FUNCTION add_one(double precision);
152166
DROP FUNCTION add_one(integer);
153-
--DROP FUNCTION clean_EMP();
167+
DROP FUNCTION clean_EMP();
154168
DROP FUNCTION high_pay();
155169
DROP FUNCTION new_emp();
156170
DROP FUNCTION add_em(integer, integer);

0 commit comments

Comments
 (0)