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

Commite418676

Browse files
committed
Adjust nodeFunctionscan.c to reset transient memory context between calls
to the table function, thus preventing memory leakage accumulation acrosscalls. This means that SRFs need to be careful to distinguish permanentand local storage; adjust code and documentation accordingly. Patch byJoe Conway, very minor tweaks by Tom Lane.
1 parent0201dac commite418676

File tree

10 files changed

+154
-134
lines changed

10 files changed

+154
-134
lines changed

‎contrib/pgstattuple/README.pgstattuple

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pgstattuple README2002/08/22 Tatsuo Ishii
1+
pgstattuple README2002/08/29 Tatsuo Ishii
22

33
1. What is pgstattuple?
44

@@ -40,15 +40,15 @@ free_percent-- free space in %
4040

4141
3. Using pgstattuple
4242

43-
pgstattuple may be called as aSRF (set returningfunction) and is
43+
pgstattuple may be called as atablefunction and is
4444
defined as follows:
4545

46-
CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNSSETOF pgstattuple_view
46+
CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNSpgstattuple_type
4747
AS 'MODULE_PATHNAME', 'pgstattuple'
4848
LANGUAGE 'c' WITH (isstrict);
4949

50-
The argument is the table name. Note that pgstattuplenever
51-
returns more than 1 tuple.
50+
The argument is the table name. Note that pgstattupleonly returns
51+
one row.
5252

5353
4. Notes
5454

‎contrib/pgstattuple/pgstattuple.c

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.7 2002/08/23 08:19:49 ishii Exp $
2+
* $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.8 2002/08/29 17:14:31 tgl Exp $
33
*
44
* Copyright (c) 2001,2002 Tatsuo Ishii
55
*
@@ -25,10 +25,10 @@
2525
#include"postgres.h"
2626

2727
#include"fmgr.h"
28+
#include"funcapi.h"
2829
#include"access/heapam.h"
2930
#include"access/transam.h"
3031
#include"catalog/namespace.h"
31-
#include"funcapi.h"
3232
#include"utils/builtins.h"
3333

3434

@@ -41,19 +41,19 @@ extern Datum pgstattuple(PG_FUNCTION_ARGS);
4141
* returns live/dead tuples info
4242
*
4343
* C FUNCTION definition
44-
* pgstattuple(TEXT) returnssetof pgstattuple_view
45-
* see pgstattuple.sql forpgstattuple_view
44+
* pgstattuple(text) returnspgstattuple_type
45+
* see pgstattuple.sql forpgstattuple_type
4646
* ----------
4747
*/
4848

49-
#defineDUMMY_TUPLE "pgstattuple_view"
49+
#defineDUMMY_TUPLE "pgstattuple_type"
5050
#defineNCOLUMNS 9
5151
#defineNCHARS 32
5252

5353
Datum
5454
pgstattuple(PG_FUNCTION_ARGS)
5555
{
56-
text*relname;
56+
text*relname=PG_GETARG_TEXT_P(0);
5757
RangeVar*relrv;
5858
Relationrel;
5959
HeapScanDescscan;
@@ -71,62 +71,30 @@ pgstattuple(PG_FUNCTION_ARGS)
7171
doubledead_tuple_percent;
7272
uint64free_space=0;/* free/reusable space in bytes */
7373
doublefree_percent;/* free/reusable space in % */
74-
75-
FuncCallContext*funcctx;
76-
intcall_cntr;
77-
intmax_calls;
7874
TupleDesctupdesc;
7975
TupleTableSlot*slot;
8076
AttInMetadata*attinmeta;
77+
char**values;
78+
inti;
79+
Datumresult;
8180

82-
char**values;
83-
inti;
84-
Datumresult;
85-
86-
/* stuff done only on the first call of the function */
87-
if(SRF_IS_FIRSTCALL())
88-
{
89-
/* create a function context for cross-call persistence */
90-
funcctx=SRF_FIRSTCALL_INIT();
91-
92-
/* total number of tuples to be returned */
93-
funcctx->max_calls=1;
94-
95-
/*
96-
* Build a tuple description for a pgstattupe_view tuple
97-
*/
98-
tupdesc=RelationNameGetTupleDesc(DUMMY_TUPLE);
99-
100-
/* allocate a slot for a tuple with this tupdesc */
101-
slot=TupleDescGetSlot(tupdesc);
102-
103-
/* assign slot to function context */
104-
funcctx->slot=slot;
105-
106-
/*
107-
* Generate attribute metadata needed later to produce tuples from raw
108-
* C strings
109-
*/
110-
attinmeta=TupleDescGetAttInMetadata(tupdesc);
111-
funcctx->attinmeta=attinmeta;
112-
}
81+
/*
82+
* Build a tuple description for a pgstattupe_type tuple
83+
*/
84+
tupdesc=RelationNameGetTupleDesc(DUMMY_TUPLE);
11385

114-
/* stuff done on every call of the function */
115-
funcctx=SRF_PERCALL_SETUP();
116-
call_cntr=funcctx->call_cntr;
117-
max_calls=funcctx->max_calls;
118-
slot=funcctx->slot;
119-
attinmeta=funcctx->attinmeta;
86+
/* allocate a slot for a tuple with this tupdesc */
87+
slot=TupleDescGetSlot(tupdesc);
12088

121-
/* Are we done? */
122-
if (call_cntr >=max_calls)
123-
{
124-
SRF_RETURN_DONE(funcctx);
125-
}
89+
/*
90+
* Generate attribute metadata needed later to produce tuples from raw
91+
* C strings
92+
*/
93+
attinmeta=TupleDescGetAttInMetadata(tupdesc);
12694

12795
/* open relation */
128-
relname=PG_GETARG_TEXT_P(0);
129-
relrv=makeRangeVarFromNameList(textToQualifiedNameList(relname,"pgstattuple"));
96+
relrv=makeRangeVarFromNameList(textToQualifiedNameList(relname,
97+
"pgstattuple"));
13098
rel=heap_openrv(relrv,AccessShareLock);
13199

132100
nblocks=RelationGetNumberOfBlocks(rel);
@@ -223,5 +191,5 @@ pgstattuple(PG_FUNCTION_ARGS)
223191
}
224192
pfree(values);
225193

226-
SRF_RETURN_NEXT(funcctx,result);
194+
PG_RETURN_DATUM(result);
227195
}
Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
DROPVIEW pgstattuple_view CASCADE;
2-
CREATEVIEW pgstattuple_view AS
3-
SELECT
4-
0::BIGINT AS table_len,--physical table length in bytes
5-
0::BIGINT AS tuple_count,--number of live tuples
6-
0::BIGINT AS tuple_len,--total tupleslengthinbytes
7-
0.0::FLOAT AS tuple_percent,--live tuples in %
8-
0::BIGINT AS dead_tuple_count,--number ofdead tuples
9-
0::BIGINT AS dead_tuple_len,--totaldead tupleslengthinbytes
10-
0.0::FLOAT AS dead_tuple_percent,--dead tuples in%
11-
0::BIGINT AS free_space,-- free space inbytes
12-
0.0::FLOAT AS free_percent;-- free space in %
1+
DROPTYPE pgstattuple_type CASCADE;
2+
CREATETYPE pgstattuple_type AS (
3+
table_len BIGINT,-- physical table length in bytes
4+
tuple_count BIGINT,--number of live tuples
5+
tuple_len BIGINT,--total tuples length in bytes
6+
tuple_percent FLOAT,--live tuples in%
7+
dead_tuple_count BIGINT,--number of dead tuples
8+
dead_tuple_len BIGINT,--totaldead tuples length in bytes
9+
dead_tuple_percent FLOAT,-- dead tuples in%
10+
free_space BIGINT,--free space inbytes
11+
free_percent FLOAT-- free space in%
12+
);
1313

14-
CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNSSETOF pgstattuple_view
14+
CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNSpgstattuple_type
1515
AS 'MODULE_PATHNAME', 'pgstattuple'
1616
LANGUAGE 'c' WITH (isstrict);

‎contrib/tablefunc/tablefunc.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,17 @@ normal_rand(PG_FUNCTION_ARGS)
8787
float8stddev;
8888
float8carry_val;
8989
booluse_carry;
90+
MemoryContextoldcontext;
9091

9192
/* stuff done only on the first call of the function */
9293
if(SRF_IS_FIRSTCALL())
9394
{
9495
/* create a function context for cross-call persistence */
9596
funcctx=SRF_FIRSTCALL_INIT();
9697

98+
/* switch to memory context appropriate for multiple function calls */
99+
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
100+
97101
/* total number of tuples to be returned */
98102
funcctx->max_calls=PG_GETARG_UINT32(0);
99103

@@ -119,6 +123,8 @@ normal_rand(PG_FUNCTION_ARGS)
119123
* purpose it doesn't matter, just cast it as an unsigned value
120124
*/
121125
srandom(PG_GETARG_UINT32(3));
126+
127+
MemoryContextSwitchTo(oldcontext);
122128
}
123129

124130
/* stuff done on every call of the function */
@@ -260,10 +266,11 @@ crosstab(PG_FUNCTION_ARGS)
260266
AttInMetadata*attinmeta;
261267
SPITupleTable*spi_tuptable=NULL;
262268
TupleDescspi_tupdesc;
263-
char*lastrowid;
269+
char*lastrowid=NULL;
264270
crosstab_fctx*fctx;
265271
inti;
266272
intnum_categories;
273+
MemoryContextoldcontext;
267274

268275
/* stuff done only on the first call of the function */
269276
if(SRF_IS_FIRSTCALL())
@@ -275,13 +282,12 @@ crosstab(PG_FUNCTION_ARGS)
275282
TupleDesctupdesc=NULL;
276283
intret;
277284
intproc;
278-
MemoryContextoldcontext;
279285

280286
/* create a function context for cross-call persistence */
281287
funcctx=SRF_FIRSTCALL_INIT();
282288

283-
/*SPI switchescontexton us, so save it first */
284-
oldcontext=CurrentMemoryContext;
289+
/*switch to memorycontextappropriate for multiple function calls */
290+
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
285291

286292
/* Connect to SPI manager */
287293
if ((ret=SPI_connect())<0)
@@ -317,8 +323,8 @@ crosstab(PG_FUNCTION_ARGS)
317323
SRF_RETURN_DONE(funcctx);
318324
}
319325

320-
/*back to the original memory context */
321-
MemoryContextSwitchTo(oldcontext);
326+
/*SPI switches context on us, so reset it */
327+
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
322328

323329
/* get the typeid that represents our return type */
324330
functypeid=get_func_rettype(funcid);
@@ -381,6 +387,8 @@ crosstab(PG_FUNCTION_ARGS)
381387

382388
/* total number of tuples to be returned */
383389
funcctx->max_calls=proc;
390+
391+
MemoryContextSwitchTo(oldcontext);
384392
}
385393

386394
/* stuff done on every call of the function */
@@ -432,7 +440,7 @@ crosstab(PG_FUNCTION_ARGS)
432440
for (i=0;i<num_categories;i++)
433441
{
434442
HeapTuplespi_tuple;
435-
char*rowid;
443+
char*rowid=NULL;
436444

437445
/* see if we've gone too far already */
438446
if (call_cntr >=max_calls)
@@ -496,7 +504,13 @@ crosstab(PG_FUNCTION_ARGS)
496504
xpfree(fctx->lastrowid);
497505

498506
if (values[0]!=NULL)
507+
{
508+
/* switch to memory context appropriate for multiple function calls */
509+
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
510+
499511
lastrowid=fctx->lastrowid=pstrdup(values[0]);
512+
MemoryContextSwitchTo(oldcontext);
513+
}
500514

501515
if (!allnulls)
502516
{

‎doc/src/sgml/xfunc.sgml

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.57 2002/08/2900:17:02 tgl Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.58 2002/08/29 17:14:32 tgl Exp $
33
-->
44

55
<chapter id="xfunc">
@@ -1670,13 +1670,14 @@ typedef struct
16701670
AttInMetadata *attinmeta;
16711671

16721672
/*
1673-
* memory context usedto initialize structure
1673+
* memory context usedfor structures which must live for multiple calls
16741674
*
1675-
* fmctx is set by SRF_FIRSTCALL_INIT() for you, and used by
1676-
* SRF_RETURN_DONE() for cleanup. It is primarily for internal use
1677-
* by the API.
1675+
* multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
1676+
* by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
1677+
* context for any memory that is to be re-used across multiple calls
1678+
* of the SRF.
16781679
*/
1679-
MemoryContextfmctx;
1680+
MemoryContextmulti_call_memory_ctx;
16801681

16811682
}FuncCallContext;
16821683
</programlisting>
@@ -1714,27 +1715,43 @@ SRF_RETURN_DONE(funcctx)
17141715
to clean up and end the SRF.
17151716
</para>
17161717

1718+
<para>
1719+
The palloc memory context that is current when the SRF is called is
1720+
a transient context that will be cleared between calls. This means
1721+
that you do not need to be careful about pfree'ing everything
1722+
you palloc; it will go away anyway. However, if you want to allocate
1723+
any data structures to live across calls, you need to put them somewhere
1724+
else. The memory context referenced by
1725+
<structfield>multi_call_memory_ctx</> is a suitable location for any
1726+
data that needs to survive until the SRF is finished running. In most
1727+
cases, this means that you should switch into
1728+
<structfield>multi_call_memory_ctx</> while doing the first-call setup.
1729+
</para>
1730+
17171731
<para>
17181732
A complete pseudo-code example looks like the following:
17191733
<programlisting>
17201734
Datum
17211735
my_Set_Returning_Function(PG_FUNCTION_ARGS)
17221736
{
1723-
FuncCallContext *funcctx;
1724-
Datum result;
1737+
FuncCallContext *funcctx;
1738+
Datum result;
1739+
MemoryContext oldcontext;
17251740
[user defined declarations]
17261741

17271742
if (SRF_IS_FIRSTCALL())
17281743
{
1744+
funcctx = SRF_FIRSTCALL_INIT();
1745+
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
17291746
/* one-time setup code appears here: */
17301747
[user defined code]
1731-
funcctx = SRF_FIRSTCALL_INIT();
17321748
[if returning composite]
17331749
[build TupleDesc, and perhaps AttInMetadata]
17341750
[obtain slot]
17351751
funcctx-&gt;slot = slot;
17361752
[endif returning composite]
17371753
[user defined code]
1754+
MemoryContextSwitchTo(oldcontext);
17381755
}
17391756

17401757
/* each-time setup code appears here: */
@@ -1777,8 +1794,13 @@ testpassbyval(PG_FUNCTION_ARGS)
17771794
/* stuff done only on the first call of the function */
17781795
if (SRF_IS_FIRSTCALL())
17791796
{
1797+
MemoryContextoldcontext;
1798+
17801799
/* create a function context for cross-call persistence */
1781-
funcctx = SRF_FIRSTCALL_INIT();
1800+
funcctx = SRF_FIRSTCALL_INIT();
1801+
1802+
/* switch to memory context appropriate for multiple function calls */
1803+
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
17821804

17831805
/* total number of tuples to be returned */
17841806
funcctx-&gt;max_calls = PG_GETARG_UINT32(0);
@@ -1800,6 +1822,8 @@ testpassbyval(PG_FUNCTION_ARGS)
18001822
*/
18011823
attinmeta = TupleDescGetAttInMetadata(tupdesc);
18021824
funcctx-&gt;attinmeta = attinmeta;
1825+
1826+
MemoryContextSwitchTo(oldcontext);
18031827
}
18041828

18051829
/* stuff done on every call of the function */
@@ -1836,7 +1860,7 @@ testpassbyval(PG_FUNCTION_ARGS)
18361860
/* make the tuple into a datum */
18371861
result = TupleGetDatum(slot, tuple);
18381862

1839-
/* Clean up */
1863+
/* Clean up(this is not actually necessary)*/
18401864
pfree(values[0]);
18411865
pfree(values[1]);
18421866
pfree(values[2]);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp