Skip to content

Commit deac948

Browse files
committed
Insert conditional SPI_push/SPI_pop calls into InputFunctionCall,
OutputFunctionCall, and friends. This allows SPI-using functions to invoke datatype I/O without concern for the possibility that a SPI-using function will be called (which could be either the I/O function itself, or a function used in a domain check constraint). It's a tad ugly, but not nearly as ugly as what'd be needed to make this work via retail insertion of push/pop operations in all the PLs. This reverts my patch of 2007-01-30 that inserted some retail SPI_push/pop calls into plpgsql; that approach only fixed plpgsql, and not any other PLs. But the other PLs have the issue too, as illustrated by a recent gripe from Christian Schröder. Back-patch to 8.2, which is as far back as this solution will work. It's also as far back as we need to worry about the domain-constraint case, since earlier versions did not attempt to check domain constraints within datatype input. I'm not aware of any old I/O functions that use SPI themselves, so this should be sufficient for a back-patch.
1 parent 6b88393 commit deac948

File tree

4 files changed

+77
-40
lines changed

4 files changed

+77
-40
lines changed

src/backend/executor/spi.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.205 2009/01/07 13:44:36 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.206 2009/01/07 20:38:56 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -304,6 +304,31 @@ SPI_pop(void)
304304
_SPI_curid--;
305305
}
306306

307+
/* Conditional push: push only if we're inside a SPI procedure */
308+
bool
309+
SPI_push_conditional(void)
310+
{
311+
bool pushed = (_SPI_curid != _SPI_connected);
312+
313+
if (pushed)
314+
{
315+
_SPI_curid++;
316+
/* We should now be in a state where SPI_connect would succeed */
317+
Assert(_SPI_curid == _SPI_connected);
318+
}
319+
return pushed;
320+
}
321+
322+
/* Conditional pop: pop only if SPI_push_conditional pushed */
323+
void
324+
SPI_pop_conditional(bool pushed)
325+
{
326+
/* We should be in a state where SPI_connect would succeed */
327+
Assert(_SPI_curid == _SPI_connected);
328+
if (pushed)
329+
_SPI_curid--;
330+
}
331+
307332
/* Restore state of SPI stack after aborting a subtransaction */
308333
void
309334
SPI_restore_connection(void)

src/backend/utils/fmgr/fmgr.c

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.124 2009/01/01 17:23:51 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.125 2009/01/07 20:38:56 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -19,6 +19,7 @@
1919
#include "catalog/pg_language.h"
2020
#include "catalog/pg_proc.h"
2121
#include "executor/functions.h"
22+
#include "executor/spi.h"
2223
#include "lib/stringinfo.h"
2324
#include "miscadmin.h"
2425
#include "nodes/nodeFuncs.h"
@@ -1846,16 +1847,25 @@ OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
18461847
* the caller should assume the result is NULL, but we'll call the input
18471848
* function anyway if it's not strict. So this is almost but not quite
18481849
* the same as FunctionCall3.
1850+
*
1851+
* One important difference from the bare function call is that we will
1852+
* push any active SPI context, allowing SPI-using I/O functions to be
1853+
* called from other SPI functions without extra notation. This is a hack,
1854+
* but the alternative of expecting all SPI functions to do SPI_push/SPI_pop
1855+
* around I/O calls seems worse.
18491856
*/
18501857
Datum
18511858
InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
18521859
{
18531860
FunctionCallInfoData fcinfo;
18541861
Datum result;
1862+
bool pushed;
18551863

18561864
if (str == NULL && flinfo->fn_strict)
18571865
return (Datum) 0; /* just return null result */
18581866

1867+
pushed = SPI_push_conditional();
1868+
18591869
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
18601870

18611871
fcinfo.arg[0] = CStringGetDatum(str);
@@ -1881,6 +1891,8 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
18811891
fcinfo.flinfo->fn_oid);
18821892
}
18831893

1894+
SPI_pop_conditional(pushed);
1895+
18841896
return result;
18851897
}
18861898

@@ -1889,13 +1901,22 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
18891901
*
18901902
* Do not call this on NULL datums.
18911903
*
1892-
* This is mere window dressing for FunctionCall1, but its use is recommended
1893-
* anyway so that code invoking output functions can be identified easily.
1904+
* This is almost just window dressing for FunctionCall1, but it includes
1905+
* SPI context pushing for the same reasons as InputFunctionCall.
18941906
*/
18951907
char *
18961908
OutputFunctionCall(FmgrInfo *flinfo, Datum val)
18971909
{
1898-
return DatumGetCString(FunctionCall1(flinfo, val));
1910+
char *result;
1911+
bool pushed;
1912+
1913+
pushed = SPI_push_conditional();
1914+
1915+
result = DatumGetCString(FunctionCall1(flinfo, val));
1916+
1917+
SPI_pop_conditional(pushed);
1918+
1919+
return result;
18991920
}
19001921

19011922
/*
@@ -1904,18 +1925,22 @@ OutputFunctionCall(FmgrInfo *flinfo, Datum val)
19041925
* "buf" may be NULL to indicate we are reading a NULL. In this case
19051926
* the caller should assume the result is NULL, but we'll call the receive
19061927
* function anyway if it's not strict. So this is almost but not quite
1907-
* the same as FunctionCall3.
1928+
* the same as FunctionCall3. Also, this includes SPI context pushing for
1929+
* the same reasons as InputFunctionCall.
19081930
*/
19091931
Datum
19101932
ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
19111933
Oid typioparam, int32 typmod)
19121934
{
19131935
FunctionCallInfoData fcinfo;
19141936
Datum result;
1937+
bool pushed;
19151938

19161939
if (buf == NULL && flinfo->fn_strict)
19171940
return (Datum) 0; /* just return null result */
19181941

1942+
pushed = SPI_push_conditional();
1943+
19191944
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
19201945

19211946
fcinfo.arg[0] = PointerGetDatum(buf);
@@ -1941,6 +1966,8 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
19411966
fcinfo.flinfo->fn_oid);
19421967
}
19431968

1969+
SPI_pop_conditional(pushed);
1970+
19441971
return result;
19451972
}
19461973

@@ -1949,14 +1976,24 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
19491976
*
19501977
* Do not call this on NULL datums.
19511978
*
1952-
* This is little more than window dressing for FunctionCall1, but its use is
1953-
* recommended anyway so that code invoking output functions can be identified
1954-
* easily. Note however that it does guarantee a non-toasted result.
1979+
* This is little more than window dressing for FunctionCall1, but it does
1980+
* guarantee a non-toasted result, which strictly speaking the underlying
1981+
* function doesn't. Also, this includes SPI context pushing for the same
1982+
* reasons as InputFunctionCall.
19551983
*/
19561984
bytea *
19571985
SendFunctionCall(FmgrInfo *flinfo, Datum val)
19581986
{
1959-
return DatumGetByteaP(FunctionCall1(flinfo, val));
1987+
bytea *result;
1988+
bool pushed;
1989+
1990+
pushed = SPI_push_conditional();
1991+
1992+
result = DatumGetByteaP(FunctionCall1(flinfo, val));
1993+
1994+
SPI_pop_conditional(pushed);
1995+
1996+
return result;
19601997
}
19611998

19621999
/*

src/include/executor/spi.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.69 2009/01/07 13:44:37 tgl Exp $
9+
* $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.70 2009/01/07 20:38:56 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -66,6 +66,8 @@ extern int SPI_connect(void);
6666
extern int SPI_finish(void);
6767
extern void SPI_push(void);
6868
extern void SPI_pop(void);
69+
extern bool SPI_push_conditional(void);
70+
extern void SPI_pop_conditional(bool pushed);
6971
extern void SPI_restore_connection(void);
7072
extern int SPI_execute(const char *src, bool read_only, long tcount);
7173
extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,

src/pl/plpgsql/src/pl_exec.c

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.227 2009/01/07 13:44:37 tgl Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.228 2009/01/07 20:38:56 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -4690,27 +4690,11 @@ make_tuple_from_row(PLpgSQL_execstate *estate,
46904690
static char *
46914691
convert_value_to_string(Datum value, Oid valtype)
46924692
{
4693-
char *str;
46944693
Oid typoutput;
46954694
bool typIsVarlena;
46964695

46974696
getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
4698-
4699-
/*
4700-
* We do SPI_push to allow the datatype output function to use SPI.
4701-
* However we do not mess around with CommandCounterIncrement or advancing
4702-
* the snapshot, which means that a stable output function would not see
4703-
* updates made so far by our own function. The use-case for such
4704-
* scenarios seems too narrow to justify the cycles that would be
4705-
* expended.
4706-
*/
4707-
SPI_push();
4708-
4709-
str = OidOutputFunctionCall(typoutput, value);
4710-
4711-
SPI_pop();
4712-
4713-
return str;
4697+
return OidOutputFunctionCall(typoutput, value);
47144698
}
47154699

47164700
/* ----------
@@ -4736,25 +4720,14 @@ exec_cast_value(Datum value, Oid valtype,
47364720
char *extval;
47374721

47384722
extval = convert_value_to_string(value, valtype);
4739-
4740-
/* Allow input function to use SPI ... see notes above */
4741-
SPI_push();
4742-
47434723
value = InputFunctionCall(reqinput, extval,
47444724
reqtypioparam, reqtypmod);
4745-
4746-
SPI_pop();
4747-
47484725
pfree(extval);
47494726
}
47504727
else
47514728
{
4752-
SPI_push();
4753-
47544729
value = InputFunctionCall(reqinput, NULL,
47554730
reqtypioparam, reqtypmod);
4756-
4757-
SPI_pop();
47584731
}
47594732
}
47604733

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy