From 04cec1a95bc4bbe10a2b9877238d6d86d3494d02 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 25 Jan 2010 01:58:33 +0000 Subject: [PATCH] Apply Tcl_Init() to the "hold" interpreter created by pltcl. You might think this is unnecessary since that interpreter is never used to run code --- but it turns out that's wrong. As of Tcl 8.5, the "clock" command (alone among builtin Tcl commands) is partially implemented by loaded-on-demand Tcl code, which means that it fails if there's not unknown-command support, and also that it's impossible to run it directly in a safe interpreter. The way they get around the latter is that Tcl_CreateSlave() automatically sets up an alias command that forwards any execution of "clock" in a safe slave interpreter to its parent interpreter. Thus, when attempting to execute "clock" in trusted pltcl, the command actually executes in the "hold" interpreter, where it will fail if unknown-command support hasn't been introduced by sourcing the standard init.tcl script, which is done by Tcl_Init(). (This is a pretty dubious design decision on the Tcl boys' part, if you ask me ... but they didn't.) Back-patch all the way. It's not clear that anyone would try to use ancient versions of pltcl with a recent Tcl, but it's not clear they wouldn't, either. Also add a regression test using "clock", in branches that have regression test support for pltcl. Per recent trouble report from Kyle Bateman. --- src/pl/tcl/expected/pltcl_setup.out | 20 ++++++++++++++++++++ src/pl/tcl/pltcl.c | 7 +++++-- src/pl/tcl/sql/pltcl_setup.sql | 11 +++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/pl/tcl/expected/pltcl_setup.out b/src/pl/tcl/expected/pltcl_setup.out index 111d999af2..d7679f7fa7 100644 --- a/src/pl/tcl/expected/pltcl_setup.out +++ b/src/pl/tcl/expected/pltcl_setup.out @@ -439,3 +439,23 @@ create operator @< ( rightarg = int4, procedure = tcl_int4lt ); +-- +-- Test usage of Tcl's "clock" command. In recent Tcl versions this +-- command fails without working "unknown" support, so it's a good canary +-- for initialization problems. +-- +create function tcl_date_week(int4,int4,int4) returns text as ' + return [clock format [clock scan "$2/$3/$1"] -format "%U"] +' language pltcl immutable; +select tcl_date_week(2010,1,24); + tcl_date_week +--------------- + 04 +(1 row) + +select tcl_date_week(2001,10,24); + tcl_date_week +--------------- + 42 +(1 row) + diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 38f0f3eac2..8fc2d41122 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -2,7 +2,7 @@ * pltcl.c - PostgreSQL support for Tcl as * procedural language (PL) * - * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.108.2.1 2008/06/17 00:52:56 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.108.2.2 2010/01/25 01:58:33 tgl Exp $ * **********************************************************************/ @@ -213,9 +213,12 @@ _PG_init(void) ************************************************************/ if ((pltcl_hold_interp = Tcl_CreateInterp()) == NULL) elog(ERROR, "could not create \"hold\" interpreter"); + if (Tcl_Init(pltcl_hold_interp) == TCL_ERROR) + elog(ERROR, "could not initialize \"hold\" interpreter"); /************************************************************ - * Create the two interpreters + * Create the two slave interpreters. Note: Tcl automatically does + * Tcl_Init on the normal slave, and it's not wanted for the safe slave. ************************************************************/ if ((pltcl_norm_interp = Tcl_CreateSlave(pltcl_hold_interp, "norm", 0)) == NULL) diff --git a/src/pl/tcl/sql/pltcl_setup.sql b/src/pl/tcl/sql/pltcl_setup.sql index 062c9f1957..6c352e1fc8 100644 --- a/src/pl/tcl/sql/pltcl_setup.sql +++ b/src/pl/tcl/sql/pltcl_setup.sql @@ -478,3 +478,14 @@ create operator @< ( procedure = tcl_int4lt ); +-- +-- Test usage of Tcl's "clock" command. In recent Tcl versions this +-- command fails without working "unknown" support, so it's a good canary +-- for initialization problems. +-- +create function tcl_date_week(int4,int4,int4) returns text as ' + return [clock format [clock scan "$2/$3/$1"] -format "%U"] +' language pltcl immutable; + +select tcl_date_week(2010,1,24); +select tcl_date_week(2001,10,24);