summaryrefslogtreecommitdiff
path: root/src/pl/tcl/pltcl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/tcl/pltcl.c')
-rw-r--r--src/pl/tcl/pltcl.c110
1 files changed, 74 insertions, 36 deletions
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index a59cef23f91..f344d4ad676 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -31,7 +31,7 @@
* ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.91 2004/08/30 02:54:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.92 2004/09/13 20:09:39 tgl Exp $
*
**********************************************************************/
@@ -87,13 +87,17 @@ utf_e2u(unsigned char *src)
pfree(_pltcl_utf_dst); } while (0)
#define UTF_U2E(x) (_pltcl_utf_dst=utf_u2e(_pltcl_utf_src=(x)))
#define UTF_E2U(x) (_pltcl_utf_dst=utf_e2u(_pltcl_utf_src=(x)))
-#else /* PLTCL_UTF */
+
+#else /* !PLTCL_UTF */
+
#define UTF_BEGIN
#define UTF_END
#define UTF_U2E(x) (x)
#define UTF_E2U(x) (x)
+
#endif /* PLTCL_UTF */
+
/**********************************************************************
* The information we cache about loaded procedures
**********************************************************************/
@@ -102,6 +106,7 @@ typedef struct pltcl_proc_desc
char *proname;
TransactionId fn_xmin;
CommandId fn_cmin;
+ bool fn_readonly;
bool lanpltrusted;
FmgrInfo result_in_func;
Oid result_typioparam;
@@ -137,7 +142,10 @@ static Tcl_Interp *pltcl_safe_interp = NULL;
static Tcl_HashTable *pltcl_proc_hash = NULL;
static Tcl_HashTable *pltcl_norm_query_hash = NULL;
static Tcl_HashTable *pltcl_safe_query_hash = NULL;
+
+/* these are saved and restored by pltcl_call_handler */
static FunctionCallInfo pltcl_current_fcinfo = NULL;
+static pltcl_proc_desc *pltcl_current_prodesc = NULL;
/*
* When a callback from Tcl into PG incurs an error, we temporarily store
@@ -179,11 +187,11 @@ static int pltcl_argisnull(ClientData cdata, Tcl_Interp *interp,
static int pltcl_returnnull(ClientData cdata, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
-static int pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,
+static int pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
-static int pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
+static int pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
static int pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
@@ -307,11 +315,11 @@ pltcl_init_interp(Tcl_Interp *interp)
pltcl_returnnull, NULL, NULL);
Tcl_CreateCommand(interp, "spi_exec",
- pltcl_SPI_exec, NULL, NULL);
+ pltcl_SPI_execute, NULL, NULL);
Tcl_CreateCommand(interp, "spi_prepare",
pltcl_SPI_prepare, NULL, NULL);
Tcl_CreateCommand(interp, "spi_execp",
- pltcl_SPI_execp, NULL, NULL);
+ pltcl_SPI_execute_plan, NULL, NULL);
Tcl_CreateCommand(interp, "spi_lastoid",
pltcl_SPI_lastoid, NULL, NULL);
}
@@ -334,8 +342,9 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
/************************************************************
* Check if table pltcl_modules exists
************************************************************/
- spi_rc = SPI_exec("select 1 from pg_catalog.pg_class "
- "where relname = 'pltcl_modules'", 1);
+ spi_rc = SPI_execute("select 1 from pg_catalog.pg_class "
+ "where relname = 'pltcl_modules'",
+ false, 1);
SPI_freetuptable(SPI_tuptable);
if (spi_rc != SPI_OK_SELECT)
elog(ERROR, "select from pg_class failed");
@@ -348,9 +357,10 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
************************************************************/
Tcl_DStringInit(&unknown_src);
- spi_rc = SPI_exec("select modseq, modsrc from pltcl_modules "
- "where modname = 'unknown' "
- "order by modseq", 0);
+ spi_rc = SPI_execute("select modseq, modsrc from pltcl_modules "
+ "where modname = 'unknown' "
+ "order by modseq",
+ false, 0);
if (spi_rc != SPI_OK_SELECT)
elog(ERROR, "select from pltcl_modules failed");
@@ -405,30 +415,46 @@ pltcl_call_handler(PG_FUNCTION_ARGS)
{
Datum retval;
FunctionCallInfo save_fcinfo;
+ pltcl_proc_desc *save_prodesc;
- /************************************************************
+ /*
* Initialize interpreters if first time through
- ************************************************************/
+ */
pltcl_init_all();
- /************************************************************
- * Determine if called as function or trigger and
- * call appropriate subhandler
- ************************************************************/
+ /*
+ * Ensure that static pointers are saved/restored properly
+ */
save_fcinfo = pltcl_current_fcinfo;
+ save_prodesc = pltcl_current_prodesc;
- if (CALLED_AS_TRIGGER(fcinfo))
+ PG_TRY();
{
- pltcl_current_fcinfo = NULL;
- retval = PointerGetDatum(pltcl_trigger_handler(fcinfo));
+ /*
+ * Determine if called as function or trigger and
+ * call appropriate subhandler
+ */
+ if (CALLED_AS_TRIGGER(fcinfo))
+ {
+ pltcl_current_fcinfo = NULL;
+ retval = PointerGetDatum(pltcl_trigger_handler(fcinfo));
+ }
+ else
+ {
+ pltcl_current_fcinfo = fcinfo;
+ retval = pltcl_func_handler(fcinfo);
+ }
}
- else
+ PG_CATCH();
{
- pltcl_current_fcinfo = fcinfo;
- retval = pltcl_func_handler(fcinfo);
+ pltcl_current_fcinfo = save_fcinfo;
+ pltcl_current_prodesc = save_prodesc;
+ PG_RE_THROW();
}
+ PG_END_TRY();
pltcl_current_fcinfo = save_fcinfo;
+ pltcl_current_prodesc = save_prodesc;
return retval;
}
@@ -467,6 +493,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
/* Find or compile the function */
prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, InvalidOid);
+ pltcl_current_prodesc = prodesc;
+
if (prodesc->lanpltrusted)
interp = pltcl_safe_interp;
else
@@ -643,6 +671,8 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid,
RelationGetRelid(trigdata->tg_relation));
+ pltcl_current_prodesc = prodesc;
+
if (prodesc->lanpltrusted)
interp = pltcl_safe_interp;
else
@@ -1030,6 +1060,10 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
+ /* Remember if function is STABLE/IMMUTABLE */
+ prodesc->fn_readonly =
+ (procStruct->provolatile != PROVOLATILE_VOLATILE);
+
/************************************************************
* Lookup the pg_language tuple by Oid
************************************************************/
@@ -1336,7 +1370,7 @@ pltcl_elog(ClientData cdata, Tcl_Interp *interp,
/**********************************************************************
* pltcl_quote() - quote literal strings that are to
- * be used in SPI_exec query strings
+ * be used in SPI_execute query strings
**********************************************************************/
static int
pltcl_quote(ClientData cdata, Tcl_Interp *interp,
@@ -1484,12 +1518,12 @@ pltcl_returnnull(ClientData cdata, Tcl_Interp *interp,
/**********************************************************************
- * pltcl_SPI_exec() - The builtin SPI_exec command
+ * pltcl_SPI_execute() - The builtin SPI_execute command
* for the Tcl interpreter
**********************************************************************/
static int
-pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,
- int argc, CONST84 char *argv[])
+pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp,
+ int argc, CONST84 char *argv[])
{
volatile int my_rc;
int spi_rc;
@@ -1570,7 +1604,8 @@ pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,
PG_TRY();
{
UTF_BEGIN;
- spi_rc = SPI_exec(UTF_U2E(argv[query_idx]), count);
+ spi_rc = SPI_execute(UTF_U2E(argv[query_idx]),
+ pltcl_current_prodesc->fn_readonly, count);
UTF_END;
}
PG_CATCH();
@@ -1603,7 +1638,7 @@ pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,
break;
default:
- Tcl_AppendResult(interp, "pltcl: SPI_exec failed: ",
+ Tcl_AppendResult(interp, "pltcl: SPI_execute failed: ",
SPI_result_code_string(spi_rc), NULL);
SPI_freetuptable(SPI_tuptable);
return TCL_ERROR;
@@ -1840,11 +1875,11 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
/**********************************************************************
- * pltcl_SPI_execp() - Execute a prepared plan
+ * pltcl_SPI_execute_plan() - Execute a prepared plan
**********************************************************************/
static int
-pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
- int argc, CONST84 char *argv[])
+pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
+ int argc, CONST84 char *argv[])
{
volatile int my_rc;
int spi_rc;
@@ -1992,7 +2027,7 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
}
/************************************************************
- * Setup the value array for the SPI_execp() using
+ * Setup the value array for SPI_execute_plan() using
* the type specific input functions
************************************************************/
oldcontext = CurrentMemoryContext;
@@ -2046,7 +2081,10 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
************************************************************/
oldcontext = CurrentMemoryContext;
PG_TRY();
- spi_rc = SPI_execp(qdesc->plan, argvalues, nulls, count);
+ {
+ spi_rc = SPI_execute_plan(qdesc->plan, argvalues, nulls,
+ pltcl_current_prodesc->fn_readonly, count);
+ }
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
@@ -2058,7 +2096,7 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
PG_END_TRY();
/************************************************************
- * Check the return code from SPI_execp()
+ * Check the return code from SPI_execute_plan()
************************************************************/
switch (spi_rc)
{
@@ -2080,7 +2118,7 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
break;
default:
- Tcl_AppendResult(interp, "pltcl: SPI_execp failed: ",
+ Tcl_AppendResult(interp, "pltcl: SPI_execute_plan failed: ",
SPI_result_code_string(spi_rc), NULL);
SPI_freetuptable(SPI_tuptable);
return TCL_ERROR;