|
2 | 2 | * pltcl.c - PostgreSQL support for Tcl as
|
3 | 3 | * procedural language (PL)
|
4 | 4 | *
|
5 |
| - * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.112 2007/04/02 03:49:42 tgl Exp $ |
| 5 | + * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.113 2007/09/21 00:30:49 tgl Exp $ |
6 | 6 | *
|
7 | 7 | **********************************************************************/
|
8 | 8 |
|
|
33 | 33 | #include "utils/syscache.h"
|
34 | 34 | #include "utils/typcache.h"
|
35 | 35 |
|
| 36 | +#define HAVE_TCL_VERSION(maj,min) \ |
| 37 | + ((TCL_MAJOR_VERSION > maj) || \ |
| 38 | + (TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min)) |
36 | 39 |
|
37 |
| -#if defined(UNICODE_CONVERSION) && TCL_MAJOR_VERSION == 8 \ |
38 |
| - && TCL_MINOR_VERSION > 0 |
| 40 | +#if defined(UNICODE_CONVERSION) && HAVE_TCL_VERSION(8,1) |
39 | 41 |
|
40 | 42 | #include "mb/pg_wchar.h"
|
41 | 43 |
|
@@ -164,6 +166,68 @@ static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
|
164 | 166 | Tcl_DString *retval);
|
165 | 167 |
|
166 | 168 |
|
| 169 | +/* |
| 170 | + * Hack to override Tcl's builtin Notifier subsystem. This prevents the |
| 171 | + * backend from becoming multithreaded, which breaks all sorts of things. |
| 172 | + * That happens in the default version of Tcl_InitNotifier if the TCL library |
| 173 | + * has been compiled with multithreading support (i.e. when TCL_THREADS is |
| 174 | + * defined under Unix, and in all cases under Windows). |
| 175 | + * It's okay to disable the notifier because we never enter the Tcl event loop |
| 176 | + * from Postgres, so the notifier capabilities are initialized, but never |
| 177 | + * used. Only InitNotifier and DeleteFileHandler ever seem to get called |
| 178 | + * within Postgres, but we implement all the functions for completeness. |
| 179 | + * We can only fix this with Tcl >= 8.2, when Tcl_SetNotifier() appeared. |
| 180 | + */ |
| 181 | +#if HAVE_TCL_VERSION(8,2) |
| 182 | + |
| 183 | +static ClientData |
| 184 | +pltcl_InitNotifier(void) |
| 185 | +{ |
| 186 | + static int fakeThreadKey; /* To give valid address for ClientData */ |
| 187 | + |
| 188 | + return (ClientData) &(fakeThreadKey); |
| 189 | +} |
| 190 | + |
| 191 | +static void |
| 192 | +pltcl_FinalizeNotifier(ClientData clientData) |
| 193 | +{ |
| 194 | +} |
| 195 | + |
| 196 | +static void |
| 197 | +pltcl_SetTimer(Tcl_Time *timePtr) |
| 198 | +{ |
| 199 | +} |
| 200 | + |
| 201 | +static void |
| 202 | +pltcl_AlertNotifier(ClientData clientData) |
| 203 | +{ |
| 204 | +} |
| 205 | + |
| 206 | +static void |
| 207 | +pltcl_CreateFileHandler(int fd, int mask, |
| 208 | + Tcl_FileProc *proc, ClientData clientData) |
| 209 | +{ |
| 210 | +} |
| 211 | + |
| 212 | +static void |
| 213 | +pltcl_DeleteFileHandler(int fd) |
| 214 | +{ |
| 215 | +} |
| 216 | + |
| 217 | +static void |
| 218 | +pltcl_ServiceModeHook(int mode) |
| 219 | +{ |
| 220 | +} |
| 221 | + |
| 222 | +static int |
| 223 | +pltcl_WaitForEvent(Tcl_Time *timePtr) |
| 224 | +{ |
| 225 | + return 0; |
| 226 | +} |
| 227 | + |
| 228 | +#endif /* HAVE_TCL_VERSION(8,2) */ |
| 229 | + |
| 230 | + |
167 | 231 | /*
|
168 | 232 | * This routine is a crock, and so is everyplace that calls it. The problem
|
169 | 233 | * is that the cached form of pltcl functions/queries is allocated permanently
|
@@ -198,6 +262,25 @@ _PG_init(void)
|
198 | 262 | Tcl_FindExecutable("");
|
199 | 263 | #endif
|
200 | 264 |
|
| 265 | +#if HAVE_TCL_VERSION(8,2) |
| 266 | + /* |
| 267 | + * Override the functions in the Notifier subsystem. See comments above. |
| 268 | + */ |
| 269 | + { |
| 270 | + Tcl_NotifierProcs notifier; |
| 271 | + |
| 272 | + notifier.setTimerProc = pltcl_SetTimer; |
| 273 | + notifier.waitForEventProc = pltcl_WaitForEvent; |
| 274 | + notifier.createFileHandlerProc = pltcl_CreateFileHandler; |
| 275 | + notifier.deleteFileHandlerProc = pltcl_DeleteFileHandler; |
| 276 | + notifier.initNotifierProc = pltcl_InitNotifier; |
| 277 | + notifier.finalizeNotifierProc = pltcl_FinalizeNotifier; |
| 278 | + notifier.alertNotifierProc = pltcl_AlertNotifier; |
| 279 | + notifier.serviceModeHookProc = pltcl_ServiceModeHook; |
| 280 | + Tcl_SetNotifier(¬ifier); |
| 281 | + } |
| 282 | +#endif |
| 283 | + |
201 | 284 | /************************************************************
|
202 | 285 | * Create the dummy hold interpreter to prevent close of
|
203 | 286 | * stdout and stderr on DeleteInterp
|
@@ -1808,9 +1891,9 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
|
1808 | 1891 | PG_TRY();
|
1809 | 1892 | {
|
1810 | 1893 | /************************************************************
|
1811 |
| - * Resolve argument type names and then look them up by oid |
1812 |
| - * in the system cache, and remember the required information |
1813 |
| - * for input conversion. |
| 1894 | + * Resolve argument type names and then look them up by oid |
| 1895 | + * in the system cache, and remember the required information |
| 1896 | + * for input conversion. |
1814 | 1897 | ************************************************************/
|
1815 | 1898 | for (i = 0; i < nargs; i++)
|
1816 | 1899 | {
|
|
0 commit comments