aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/spi.c27
-rw-r--r--src/backend/utils/fmgr/fmgr.c55
-rw-r--r--src/include/executor/spi.h4
-rw-r--r--src/pl/plpgsql/src/pl_exec.c31
4 files changed, 77 insertions, 40 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 7a99a32b9a4..d20e06a0778 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.188.2.3 2008/10/16 13:23:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.188.2.4 2009/01/07 20:39:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -286,6 +286,31 @@ SPI_pop(void)
_SPI_curid--;
}
+/* Conditional push: push only if we're inside a SPI procedure */
+bool
+SPI_push_conditional(void)
+{
+ bool pushed = (_SPI_curid != _SPI_connected);
+
+ if (pushed)
+ {
+ _SPI_curid++;
+ /* We should now be in a state where SPI_connect would succeed */
+ Assert(_SPI_curid == _SPI_connected);
+ }
+ return pushed;
+}
+
+/* Conditional pop: pop only if SPI_push_conditional pushed */
+void
+SPI_pop_conditional(bool pushed)
+{
+ /* We should be in a state where SPI_connect would succeed */
+ Assert(_SPI_curid == _SPI_connected);
+ if (pushed)
+ _SPI_curid--;
+}
+
/* Restore state of SPI stack after aborting a subtransaction */
void
SPI_restore_connection(void)
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 19216b4381c..62fdfba294e 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.113 2008/01/03 21:23:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.113.2.1 2009/01/07 20:39:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,7 @@
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "executor/functions.h"
+#include "executor/spi.h"
#include "miscadmin.h"
#include "parser/parse_expr.h"
#include "utils/builtins.h"
@@ -1818,16 +1819,25 @@ OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
* the caller should assume the result is NULL, but we'll call the input
* function anyway if it's not strict. So this is almost but not quite
* the same as FunctionCall3.
+ *
+ * One important difference from the bare function call is that we will
+ * push any active SPI context, allowing SPI-using I/O functions to be
+ * called from other SPI functions without extra notation. This is a hack,
+ * but the alternative of expecting all SPI functions to do SPI_push/SPI_pop
+ * around I/O calls seems worse.
*/
Datum
InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
{
FunctionCallInfoData fcinfo;
Datum result;
+ bool pushed;
if (str == NULL && flinfo->fn_strict)
return (Datum) 0; /* just return null result */
+ pushed = SPI_push_conditional();
+
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
fcinfo.arg[0] = CStringGetDatum(str);
@@ -1853,6 +1863,8 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
fcinfo.flinfo->fn_oid);
}
+ SPI_pop_conditional(pushed);
+
return result;
}
@@ -1861,13 +1873,22 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
*
* Do not call this on NULL datums.
*
- * This is mere window dressing for FunctionCall1, but its use is recommended
- * anyway so that code invoking output functions can be identified easily.
+ * This is almost just window dressing for FunctionCall1, but it includes
+ * SPI context pushing for the same reasons as InputFunctionCall.
*/
char *
OutputFunctionCall(FmgrInfo *flinfo, Datum val)
{
- return DatumGetCString(FunctionCall1(flinfo, val));
+ char *result;
+ bool pushed;
+
+ pushed = SPI_push_conditional();
+
+ result = DatumGetCString(FunctionCall1(flinfo, val));
+
+ SPI_pop_conditional(pushed);
+
+ return result;
}
/*
@@ -1876,7 +1897,8 @@ OutputFunctionCall(FmgrInfo *flinfo, Datum val)
* "buf" may be NULL to indicate we are reading a NULL. In this case
* the caller should assume the result is NULL, but we'll call the receive
* function anyway if it's not strict. So this is almost but not quite
- * the same as FunctionCall3.
+ * the same as FunctionCall3. Also, this includes SPI context pushing for
+ * the same reasons as InputFunctionCall.
*/
Datum
ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
@@ -1884,10 +1906,13 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
{
FunctionCallInfoData fcinfo;
Datum result;
+ bool pushed;
if (buf == NULL && flinfo->fn_strict)
return (Datum) 0; /* just return null result */
+ pushed = SPI_push_conditional();
+
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
fcinfo.arg[0] = PointerGetDatum(buf);
@@ -1913,6 +1938,8 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
fcinfo.flinfo->fn_oid);
}
+ SPI_pop_conditional(pushed);
+
return result;
}
@@ -1921,14 +1948,24 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
*
* Do not call this on NULL datums.
*
- * This is little more than window dressing for FunctionCall1, but its use is
- * recommended anyway so that code invoking output functions can be identified
- * easily. Note however that it does guarantee a non-toasted result.
+ * This is little more than window dressing for FunctionCall1, but it does
+ * guarantee a non-toasted result, which strictly speaking the underlying
+ * function doesn't. Also, this includes SPI context pushing for the same
+ * reasons as InputFunctionCall.
*/
bytea *
SendFunctionCall(FmgrInfo *flinfo, Datum val)
{
- return DatumGetByteaP(FunctionCall1(flinfo, val));
+ bytea *result;
+ bool pushed;
+
+ pushed = SPI_push_conditional();
+
+ result = DatumGetByteaP(FunctionCall1(flinfo, val));
+
+ SPI_pop_conditional(pushed);
+
+ return result;
}
/*
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 32d9488a667..39644a93ce1 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.65.2.1 2008/09/15 23:37:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.65.2.2 2009/01/07 20:39:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -93,6 +93,8 @@ extern int SPI_connect(void);
extern int SPI_finish(void);
extern void SPI_push(void);
extern void SPI_pop(void);
+extern bool SPI_push_conditional(void);
+extern void SPI_pop_conditional(bool pushed);
extern void SPI_restore_connection(void);
extern int SPI_execute(const char *src, bool read_only, long tcount);
extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 6c9062f9888..c9a1fbeff4b 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.202.2.1 2008/09/01 22:30:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.202.2.2 2009/01/07 20:39:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4481,27 +4481,11 @@ make_tuple_from_row(PLpgSQL_execstate *estate,
static char *
convert_value_to_string(Datum value, Oid valtype)
{
- char *str;
Oid typoutput;
bool typIsVarlena;
getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
-
- /*
- * We do SPI_push to allow the datatype output function to use SPI.
- * However we do not mess around with CommandCounterIncrement or advancing
- * the snapshot, which means that a stable output function would not see
- * updates made so far by our own function. The use-case for such
- * scenarios seems too narrow to justify the cycles that would be
- * expended.
- */
- SPI_push();
-
- str = OidOutputFunctionCall(typoutput, value);
-
- SPI_pop();
-
- return str;
+ return OidOutputFunctionCall(typoutput, value);
}
/* ----------
@@ -4527,25 +4511,14 @@ exec_cast_value(Datum value, Oid valtype,
char *extval;
extval = convert_value_to_string(value, valtype);
-
- /* Allow input function to use SPI ... see notes above */
- SPI_push();
-
value = InputFunctionCall(reqinput, extval,
reqtypioparam, reqtypmod);
-
- SPI_pop();
-
pfree(extval);
}
else
{
- SPI_push();
-
value = InputFunctionCall(reqinput, NULL,
reqtypioparam, reqtypmod);
-
- SPI_pop();
}
}