Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitadbe62d

Browse files
committed
Add PL/Sample to src/test/modules/
PL/Sample is an example template of procedural-language handler. Thiscan be used as a base to implement a custom PL, or as a facility to testAPIs dedicated to PLs. Much more could be done in this module, likeadding a simple validator, but this is left as future work.The documentation included originally some C code to understand thebasics of PL handler implementation, but it was outdated, and not reallyhelpful either if trying to implement a new procedural language,particularly when it came to the integration of a PL installation withCREATE EXTENSION.Author: Mark WongReviewed-by: Tom Lane, Michael PaquierDiscussion:https://postgr.es/m/20200612172648.GA3327@2ndQuadrant.com
1 parent6e70443 commitadbe62d

File tree

10 files changed

+290
-56
lines changed

10 files changed

+290
-56
lines changed

‎doc/src/sgml/plhandler.sgml

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -96,62 +96,10 @@
9696
</para>
9797

9898
<para>
99-
This is a template for a procedural-language handler written in C:
100-
<programlisting>
101-
#include "postgres.h"
102-
#include "executor/spi.h"
103-
#include "commands/trigger.h"
104-
#include "fmgr.h"
105-
#include "access/heapam.h"
106-
#include "utils/syscache.h"
107-
#include "catalog/pg_proc.h"
108-
#include "catalog/pg_type.h"
109-
110-
PG_MODULE_MAGIC;
111-
112-
PG_FUNCTION_INFO_V1(plsample_call_handler);
113-
114-
Datum
115-
plsample_call_handler(PG_FUNCTION_ARGS)
116-
{
117-
Datum retval;
118-
119-
if (CALLED_AS_TRIGGER(fcinfo))
120-
{
121-
/*
122-
* Called as a trigger function
123-
*/
124-
TriggerData *trigdata = (TriggerData *) fcinfo-&gt;context;
125-
126-
retval = ...
127-
}
128-
else
129-
{
130-
/*
131-
* Called as a function
132-
*/
133-
134-
retval = ...
135-
}
136-
137-
return retval;
138-
}
139-
</programlisting>
140-
Only a few thousand lines of code have to be added instead of the
141-
dots to complete the call handler.
142-
</para>
143-
144-
<para>
145-
After having compiled the handler function into a loadable module
146-
(see <xref linkend="dfunc"/>), the following commands then
147-
register the sample procedural language:
148-
<programlisting>
149-
CREATE FUNCTION plsample_call_handler() RETURNS language_handler
150-
AS '<replaceable>filename</replaceable>'
151-
LANGUAGE C;
152-
CREATE LANGUAGE plsample
153-
HANDLER plsample_call_handler;
154-
</programlisting>
99+
A template for a procedural-language handler written as a C extension is
100+
provided in <literal>src/test/modules/plsample</literal>. This is a
101+
working sample demonstrating one way to create a procedural-language
102+
handler, process parameters, and return a value.
155103
</para>
156104

157105
<para>

‎src/test/modules/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SUBDIRS = \
1010
delay_execution\
1111
dummy_index_am\
1212
dummy_seclabel\
13+
plsample\
1314
snapshot_too_old\
1415
test_bloomfilter\
1516
test_ddl_deparse\

‎src/test/modules/plsample/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Generated subdirectories
2+
/log/
3+
/results/

‎src/test/modules/plsample/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# src/test/modules/plsample/Makefile
2+
3+
MODULES = plsample
4+
5+
EXTENSION = plsample
6+
DATA = plsample--1.0.sql
7+
PGFILEDESC = "PL/Sample - template for procedural language"
8+
9+
REGRESS = plsample
10+
11+
ifdefUSE_PGXS
12+
PG_CONFIG = pg_config
13+
PGXS :=$(shell$(PG_CONFIG) --pgxs)
14+
include$(PGXS)
15+
else
16+
subdir = src/test/modules/plsample
17+
top_builddir = ../../../..
18+
include$(top_builddir)/src/Makefile.global
19+
include$(top_srcdir)/contrib/contrib-global.mk
20+
endif

‎src/test/modules/plsample/README

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
PL/Sample
2+
=========
3+
4+
PL/Sample is an example template of procedural-language handler. It is
5+
a simple implementation, yet demonstrates some of the things that can be done
6+
to build a fully functional procedural-language handler.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
CREATE EXTENSION plsample;
2+
-- Create and test some dummy functions
3+
CREATE FUNCTION plsample_result_text(a1 numeric, a2 text, a3 integer[])
4+
RETURNS TEXT
5+
AS $$
6+
Example of source with text result.
7+
$$ LANGUAGE plsample;
8+
SELECT plsample_result_text(1.23, 'abc', '{4, 5, 6}');
9+
NOTICE: source text of function "plsample_result_text":
10+
Example of source with text result.
11+
12+
NOTICE: argument: 0; name: a1; value: 1.23
13+
NOTICE: argument: 1; name: a2; value: abc
14+
NOTICE: argument: 2; name: a3; value: {4,5,6}
15+
plsample_result_text
16+
---------------------------------------
17+
+
18+
Example of source with text result.+
19+
20+
(1 row)
21+
22+
CREATE FUNCTION plsample_result_void(a1 text[])
23+
RETURNS VOID
24+
AS $$
25+
Example of source with void result.
26+
$$ LANGUAGE plsample;
27+
SELECT plsample_result_void('{foo, bar, hoge}');
28+
NOTICE: source text of function "plsample_result_void":
29+
Example of source with void result.
30+
31+
NOTICE: argument: 0; name: a1; value: {foo,bar,hoge}
32+
plsample_result_void
33+
----------------------
34+
35+
(1 row)
36+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* src/test/modules/plsample/plsample--1.0.sql*/
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use"CREATE EXTENSION plsample" to load this file. \quit
5+
6+
CREATEFUNCTIONplsample_call_handler() RETURNS language_handler
7+
AS'MODULE_PATHNAME' LANGUAGE C;
8+
9+
CREATE TRUSTED LANGUAGE plsample
10+
HANDLER plsample_call_handler;
11+
12+
ALTERLANGUAGE plsample OWNER TO @extowner@;
13+
14+
COMMENTON LANGUAGE plsample IS'PL/Sample procedural language';

‎src/test/modules/plsample/plsample.c

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* plsample.c
4+
* Handler for the PL/Sample procedural language
5+
*
6+
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
*
10+
* IDENTIFICATION
11+
*src/test/modules/plsample/plsample.c
12+
*
13+
*-------------------------------------------------------------------------
14+
*/
15+
16+
#include"postgres.h"
17+
18+
#include"catalog/pg_proc.h"
19+
#include"catalog/pg_type.h"
20+
#include"commands/event_trigger.h"
21+
#include"commands/trigger.h"
22+
#include"funcapi.h"
23+
#include"utils/builtins.h"
24+
#include"utils/lsyscache.h"
25+
#include"utils/syscache.h"
26+
27+
PG_MODULE_MAGIC;
28+
29+
PG_FUNCTION_INFO_V1(plsample_call_handler);
30+
31+
staticDatumplsample_func_handler(PG_FUNCTION_ARGS);
32+
33+
/*
34+
* Handle function, procedure, and trigger calls.
35+
*/
36+
Datum
37+
plsample_call_handler(PG_FUNCTION_ARGS)
38+
{
39+
Datumretval= (Datum)0;
40+
41+
PG_TRY();
42+
{
43+
/*
44+
* Determine if called as function or trigger and call appropriate
45+
* subhandler.
46+
*/
47+
if (CALLED_AS_TRIGGER(fcinfo))
48+
{
49+
/*
50+
* This function has been called as a trigger function, where
51+
* (TriggerData *) fcinfo->context includes the information of the
52+
* context.
53+
*/
54+
}
55+
elseif (CALLED_AS_EVENT_TRIGGER(fcinfo))
56+
{
57+
/*
58+
* This function is called as an event trigger function, where
59+
* (EventTriggerData *) fcinfo->context includes the information
60+
* of the context.
61+
*/
62+
}
63+
else
64+
{
65+
/* Regular function handler */
66+
retval=plsample_func_handler(fcinfo);
67+
}
68+
}
69+
PG_FINALLY();
70+
{
71+
}
72+
PG_END_TRY();
73+
74+
returnretval;
75+
}
76+
77+
/*
78+
* plsample_func_handler
79+
*
80+
* Function called by the call handler for function execution.
81+
*/
82+
staticDatum
83+
plsample_func_handler(PG_FUNCTION_ARGS)
84+
{
85+
HeapTuplepl_tuple;
86+
Datumret;
87+
char*source;
88+
boolisnull;
89+
FmgrInfo*arg_out_func;
90+
Form_pg_typetype_struct;
91+
HeapTupletype_tuple;
92+
Form_pg_procpl_struct;
93+
volatileMemoryContextproc_cxt=NULL;
94+
Oid*argtypes;
95+
char**argnames;
96+
char*argmodes;
97+
char*proname;
98+
Form_pg_typepg_type_entry;
99+
Oidresult_typioparam;
100+
FmgrInforesult_in_func;
101+
intnumargs;
102+
103+
/* Fetch the source text of the function. */
104+
pl_tuple=SearchSysCache(PROCOID,
105+
ObjectIdGetDatum(fcinfo->flinfo->fn_oid),0,0,0);
106+
if (!HeapTupleIsValid(pl_tuple))
107+
elog(ERROR,"cache lookup failed for function %u",
108+
fcinfo->flinfo->fn_oid);
109+
110+
/*
111+
* Extract and print the source text of the function. This can be used as
112+
* a base for the function validation and execution.
113+
*/
114+
pl_struct= (Form_pg_proc)GETSTRUCT(pl_tuple);
115+
proname=pstrdup(NameStr(pl_struct->proname));
116+
ret=SysCacheGetAttr(PROCOID,pl_tuple,Anum_pg_proc_prosrc,&isnull);
117+
if (isnull)
118+
elog(ERROR,"could not find source text of function \"%s\"",
119+
proname);
120+
ReleaseSysCache(pl_tuple);
121+
source=DatumGetCString(DirectFunctionCall1(textout,ret));
122+
ereport(NOTICE,
123+
(errmsg("source text of function \"%s\": %s",
124+
proname,source)));
125+
126+
/*
127+
* Allocate a context that will hold all the Postgres data for the
128+
* procedure.
129+
*/
130+
proc_cxt=AllocSetContextCreate(TopMemoryContext,
131+
"PL/Sample function",
132+
ALLOCSET_SMALL_SIZES);
133+
134+
arg_out_func= (FmgrInfo*)palloc0(fcinfo->nargs*sizeof(FmgrInfo));
135+
numargs=get_func_arg_info(pl_tuple,&argtypes,&argnames,&argmodes);
136+
137+
/*
138+
* Iterate through all of the function arguments, printing each input
139+
* value.
140+
*/
141+
for (inti=0;i<numargs;i++)
142+
{
143+
Oidargtype=pl_struct->proargtypes.values[i];
144+
char*value;
145+
146+
type_tuple=SearchSysCache1(TYPEOID,ObjectIdGetDatum(argtype));
147+
if (!HeapTupleIsValid(type_tuple))
148+
elog(ERROR,"cache lookup failed for type %u",argtype);
149+
150+
type_struct= (Form_pg_type)GETSTRUCT(type_tuple);
151+
fmgr_info_cxt(type_struct->typoutput,&(arg_out_func[i]),proc_cxt);
152+
ReleaseSysCache(type_tuple);
153+
154+
value=OutputFunctionCall(&arg_out_func[i],fcinfo->args[i].value);
155+
ereport(NOTICE,
156+
(errmsg("argument: %d; name: %s; value: %s",
157+
i,argnames[i],value)));
158+
}
159+
160+
/*
161+
* Get the required information for input conversion of the return value.
162+
*
163+
* If the function uses VOID as result, it is better to return NULL.
164+
* Anyway, let's be honest. This is just a template, so there is not much
165+
* we can do here. This returns NULL except if the result type is text,
166+
* where the result is the source text of the function.
167+
*/
168+
if (pl_struct->prorettype!=TEXTOID)
169+
PG_RETURN_NULL();
170+
171+
type_tuple=SearchSysCache1(TYPEOID,
172+
ObjectIdGetDatum(pl_struct->prorettype));
173+
if (!HeapTupleIsValid(type_tuple))
174+
elog(ERROR,"cache lookup failed for type %u",pl_struct->prorettype);
175+
pg_type_entry= (Form_pg_type)GETSTRUCT(type_tuple);
176+
result_typioparam=getTypeIOParam(type_tuple);
177+
178+
fmgr_info_cxt(pg_type_entry->typinput,&result_in_func,proc_cxt);
179+
ReleaseSysCache(type_tuple);
180+
181+
ret=InputFunctionCall(&result_in_func,source,result_typioparam,-1);
182+
PG_RETURN_DATUM(ret);
183+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# plsample extension
2+
comment = 'PL/Sample'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/plsample'
5+
relocatable = false
6+
schema = pg_catalog
7+
superuser = false
8+
trusted = true
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CREATE EXTENSION plsample;
2+
-- Create and test some dummy functions
3+
CREATEFUNCTIONplsample_result_text(a1numeric, a2text, a3integer[])
4+
RETURNSTEXT
5+
AS $$
6+
Example of source withtext result.
7+
$$ LANGUAGE plsample;
8+
SELECT plsample_result_text(1.23,'abc','{4, 5, 6}');
9+
10+
CREATEFUNCTIONplsample_result_void(a1text[])
11+
RETURNS VOID
12+
AS $$
13+
Example of source with void result.
14+
$$ LANGUAGE plsample;
15+
SELECT plsample_result_void('{foo, bar, hoge}');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp