2121#include "commands/trigger.h"
2222#include "executor/spi.h"
2323#include "fmgr.h"
24+ #include "mb/pg_wchar.h"
2425#include "miscadmin.h"
2526#include "nodes/makefuncs.h"
2627#include "parser/parse_type.h"
3334#include "utils/typcache.h"
3435
3536
37+ PG_MODULE_MAGIC ;
38+
3639#define HAVE_TCL_VERSION (maj ,min ) \
3740 ((TCL_MAJOR_VERSION > maj) || \
3841 (TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min))
5154#undef TEXTDOMAIN
5255#define TEXTDOMAIN PG_TEXTDOMAIN("pltcl")
5356
54- #if defined(UNICODE_CONVERSION )
5557
56- #include "mb/pg_wchar.h"
58+ /*
59+ * Support for converting between UTF8 (which is what all strings going into
60+ * or out of Tcl should be) and the database encoding.
61+ *
62+ * If you just use utf_u2e() or utf_e2u() directly, they will leak some
63+ * palloc'd space when doing a conversion. This is not worth worrying about
64+ * if it only happens, say, once per PL/Tcl function call. If it does seem
65+ * worth worrying about, use the wrapper macros.
66+ */
5767
58- static unsigned char *
59- utf_u2e (unsigned char * src )
68+ static inline char *
69+ utf_u2e (const char * src )
6070{
61- return (unsigned char * ) pg_any_to_server ((char * ) src ,
62- strlen (src ),
63- PG_UTF8 );
71+ return pg_any_to_server (src , strlen (src ), PG_UTF8 );
6472}
6573
66- static unsigned char *
67- utf_e2u (unsigned char * src )
74+ static inline char *
75+ utf_e2u (const char * src )
6876{
69- return (unsigned char * ) pg_server_to_any ((char * ) src ,
70- strlen (src ),
71- PG_UTF8 );
77+ return pg_server_to_any (src , strlen (src ), PG_UTF8 );
7278}
7379
74- #define PLTCL_UTF
75- #define UTF_BEGIN do { \
76- unsigned char *_pltcl_utf_src; \
77- unsigned char *_pltcl_utf_dst
78- #define UTF_END if (_pltcl_utf_src!=_pltcl_utf_dst) \
79- pfree(_pltcl_utf_dst); } while (0)
80- #define UTF_U2E (x ) (_pltcl_utf_dst=utf_u2e(_pltcl_utf_src=(x)))
81- #define UTF_E2U (x ) (_pltcl_utf_dst=utf_e2u(_pltcl_utf_src=(x)))
82- #else /* !PLTCL_UTF */
83-
84- #define UTF_BEGIN
85- #define UTF_END
86- #define UTF_U2E (x ) (x)
87- #define UTF_E2U (x ) (x)
88- #endif /* PLTCL_UTF */
80+ #define UTF_BEGIN \
81+ do { \
82+ const char *_pltcl_utf_src = NULL; \
83+ char *_pltcl_utf_dst = NULL
8984
90- PG_MODULE_MAGIC ;
85+ #define UTF_END \
86+ if (_pltcl_utf_src != (const char *) _pltcl_utf_dst) \
87+ pfree(_pltcl_utf_dst); \
88+ } while (0)
89+
90+ #define UTF_U2E (x ) \
91+ (_pltcl_utf_dst = utf_u2e(_pltcl_utf_src = (x)))
92+
93+ #define UTF_E2U (x ) \
94+ (_pltcl_utf_dst = utf_e2u(_pltcl_utf_src = (x)))
9195
9296
9397/**********************************************************************
@@ -572,14 +576,10 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
572576 SPI_freetuptable (SPI_tuptable );
573577
574578 if (tcl_rc != TCL_OK )
575- {
576- UTF_BEGIN ;
577579 ereport (ERROR ,
578580 (errcode (ERRCODE_EXTERNAL_ROUTINE_EXCEPTION ),
579581 errmsg ("could not load module \"unknown\": %s" ,
580- UTF_U2E (Tcl_GetStringResult (interp )))));
581- UTF_END ;
582- }
582+ utf_u2e (Tcl_GetStringResult (interp )))));
583583
584584 relation_close (pmrel , AccessShareLock );
585585}
@@ -804,14 +804,10 @@ pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted)
804804 prodesc -> result_typioparam ,
805805 -1 );
806806 else
807- {
808- UTF_BEGIN ;
809807 retval = InputFunctionCall (& prodesc -> result_in_func ,
810- UTF_U2E (( char * ) Tcl_GetStringResult (interp )),
808+ utf_u2e ( Tcl_GetStringResult (interp )),
811809 prodesc -> result_typioparam ,
812810 -1 );
813- UTF_END ;
814- }
815811
816812 return retval ;
817813}
@@ -866,13 +862,13 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
866862
867863 PG_TRY ();
868864 {
869- /* The procedure name */
865+ /* The procedure name (note this is all ASCII, so no utf_e2u) */
870866 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
871867 Tcl_NewStringObj (prodesc -> internal_proname , -1 ));
872868
873869 /* The trigger name for argument TG_name */
874870 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
875- Tcl_NewStringObj (trigdata -> tg_trigger -> tgname , -1 ));
871+ Tcl_NewStringObj (utf_e2u ( trigdata -> tg_trigger -> tgname ) , -1 ));
876872
877873 /* The oid of the trigger relation for argument TG_relid */
878874 /* Consider not converting to a string for more performance? */
@@ -885,13 +881,13 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
885881 /* The name of the table the trigger is acting on: TG_table_name */
886882 stroid = SPI_getrelname (trigdata -> tg_relation );
887883 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
888- Tcl_NewStringObj (stroid , -1 ));
884+ Tcl_NewStringObj (utf_e2u ( stroid ) , -1 ));
889885 pfree (stroid );
890886
891887 /* The schema of the table the trigger is acting on: TG_table_schema */
892888 stroid = SPI_getnspname (trigdata -> tg_relation );
893889 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
894- Tcl_NewStringObj (stroid , -1 ));
890+ Tcl_NewStringObj (utf_e2u ( stroid ) , -1 ));
895891 pfree (stroid );
896892
897893 /* A list of attribute names for argument TG_relatts */
@@ -903,7 +899,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
903899 Tcl_ListObjAppendElement (NULL , tcl_trigtup , Tcl_NewObj ());
904900 else
905901 Tcl_ListObjAppendElement (NULL , tcl_trigtup ,
906- Tcl_NewStringObj (NameStr (tupdesc -> attrs [i ]-> attname ), -1 ));
902+ Tcl_NewStringObj (utf_e2u ( NameStr (tupdesc -> attrs [i ]-> attname ) ), -1 ));
907903 }
908904 Tcl_ListObjAppendElement (NULL , tcl_cmd , tcl_trigtup );
909905
@@ -1001,7 +997,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
1001997 /* Finally append the arguments from CREATE TRIGGER */
1002998 for (i = 0 ; i < trigdata -> tg_trigger -> tgnargs ; i ++ )
1003999 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
1004- Tcl_NewStringObj (trigdata -> tg_trigger -> tgargs [i ], -1 ));
1000+ Tcl_NewStringObj (utf_e2u ( trigdata -> tg_trigger -> tgargs [i ]) , -1 ));
10051001
10061002 }
10071003 PG_CATCH ();
@@ -1048,14 +1044,10 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
10481044 ************************************************************/
10491045 if (Tcl_SplitList (interp , result ,
10501046 & ret_numvals , & ret_values ) != TCL_OK )
1051- {
1052- UTF_BEGIN ;
10531047 ereport (ERROR ,
10541048 (errcode (ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED ),
10551049 errmsg ("could not split return value from trigger: %s" ,
1056- UTF_U2E (Tcl_GetStringResult (interp )))));
1057- UTF_END ;
1058- }
1050+ utf_u2e (Tcl_GetStringResult (interp )))));
10591051
10601052 /* Use a TRY to ensure ret_values will get freed */
10611053 PG_TRY ();
@@ -1078,8 +1070,8 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
10781070
10791071 for (i = 0 ; i < ret_numvals ; i += 2 )
10801072 {
1081- const char * ret_name = ret_values [i ];
1082- const char * ret_value = ret_values [i + 1 ];
1073+ char * ret_name = utf_u2e ( ret_values [i ]) ;
1074+ char * ret_value = utf_u2e ( ret_values [i + 1 ]) ;
10831075 int attnum ;
10841076 Oid typinput ;
10851077 Oid typioparam ;
@@ -1123,13 +1115,11 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
11231115 /************************************************************
11241116 * Set the attribute to NOT NULL and convert the contents
11251117 ************************************************************/
1126- modnulls [attnum - 1 ] = ' ' ;
1127- UTF_BEGIN ;
11281118 modvalues [attnum - 1 ] = InputFunctionCall (& finfo ,
1129- ( char * ) UTF_U2E ( ret_value ) ,
1119+ ret_value ,
11301120 typioparam ,
11311121 tupdesc -> attrs [attnum - 1 ]-> atttypmod );
1132- UTF_END ;
1122+ modnulls [ attnum - 1 ] = ' ' ;
11331123 }
11341124
11351125 rettup = SPI_modifytuple (trigdata -> tg_relation , rettup , tupdesc -> natts ,
@@ -1183,9 +1173,9 @@ pltcl_event_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
11831173 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
11841174 Tcl_NewStringObj (prodesc -> internal_proname , -1 ));
11851175 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
1186- Tcl_NewStringObj (tdata -> event , -1 ));
1176+ Tcl_NewStringObj (utf_e2u ( tdata -> event ) , -1 ));
11871177 Tcl_ListObjAppendElement (NULL , tcl_cmd ,
1188- Tcl_NewStringObj (tdata -> tag , -1 ));
1178+ Tcl_NewStringObj (utf_e2u ( tdata -> tag ) , -1 ));
11891179
11901180 tcl_rc = Tcl_EvalObjEx (interp , tcl_cmd , (TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL ));
11911181
@@ -1217,18 +1207,13 @@ throw_tcl_error(Tcl_Interp *interp, const char *proname)
12171207 char * emsg ;
12181208 char * econtext ;
12191209
1220- UTF_BEGIN ;
1221- emsg = pstrdup (UTF_U2E (Tcl_GetStringResult (interp )));
1222- UTF_END ;
1223- UTF_BEGIN ;
1224- econtext = UTF_U2E ((char * ) Tcl_GetVar (interp , "errorInfo" ,
1225- TCL_GLOBAL_ONLY ));
1210+ emsg = pstrdup (utf_u2e (Tcl_GetStringResult (interp )));
1211+ econtext = utf_u2e (Tcl_GetVar (interp , "errorInfo" , TCL_GLOBAL_ONLY ));
12261212 ereport (ERROR ,
12271213 (errcode (ERRCODE_EXTERNAL_ROUTINE_EXCEPTION ),
12281214 errmsg ("%s" , emsg ),
12291215 errcontext ("%s\nin PL/Tcl function \"%s\"" ,
12301216 econtext , proname )));
1231- UTF_END ;
12321217}
12331218
12341219
@@ -1315,7 +1300,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid,
13151300 /************************************************************
13161301 * Build our internal proc name from the function's Oid. Append
13171302 * "_trigger" when appropriate to ensure the normal and trigger
1318- * cases are kept separate.
1303+ * cases are kept separate. Note name must be all-ASCII.
13191304 ************************************************************/
13201305 if (!is_trigger && !is_event_trigger )
13211306 snprintf (internal_proname , sizeof (internal_proname ),
@@ -1570,13 +1555,11 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid,
15701555 free (prodesc -> user_proname );
15711556 free (prodesc -> internal_proname );
15721557 free (prodesc );
1573- UTF_BEGIN ;
15741558 ereport (ERROR ,
15751559 (errcode (ERRCODE_EXTERNAL_ROUTINE_EXCEPTION ),
15761560 errmsg ("could not create internal procedure \"%s\": %s" ,
15771561 internal_proname ,
1578- UTF_U2E (Tcl_GetStringResult (interp )))));
1579- UTF_END ;
1562+ utf_u2e (Tcl_GetStringResult (interp )))));
15801563 }
15811564
15821565 /************************************************************
@@ -2212,7 +2195,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
22122195 * Prepare the plan and check for errors
22132196 ************************************************************/
22142197 UTF_BEGIN ;
2215- qdesc -> plan = SPI_prepare (UTF_U2E (Tcl_GetString (objv [1 ])), nargs , qdesc -> argtypes );
2198+ qdesc -> plan = SPI_prepare (UTF_U2E (Tcl_GetString (objv [1 ])),
2199+ nargs , qdesc -> argtypes );
22162200 UTF_END ;
22172201
22182202 if (qdesc -> plan == NULL )
@@ -2434,7 +2418,7 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
24342418 {
24352419 UTF_BEGIN ;
24362420 argvalues [j ] = InputFunctionCall (& qdesc -> arginfuncs [j ],
2437- ( char * ) UTF_U2E (Tcl_GetString (callObjv [j ])),
2421+ UTF_U2E (Tcl_GetString (callObjv [j ])),
24382422 qdesc -> argtypioparams [j ],
24392423 -1 );
24402424 UTF_END ;
@@ -2483,6 +2467,8 @@ pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,
24832467/**********************************************************************
24842468 * pltcl_set_tuple_values() - Set variables for all attributes
24852469 * of a given tuple
2470+ *
2471+ * Note: arrayname is presumed to be UTF8; it usually came from Tcl
24862472 **********************************************************************/
24872473static void
24882474pltcl_set_tuple_values (Tcl_Interp * interp , const char * arrayname ,
@@ -2524,7 +2510,9 @@ pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname,
25242510 /************************************************************
25252511 * Get the attribute name
25262512 ************************************************************/
2527- attname = NameStr (tupdesc -> attrs [i ]-> attname );
2513+ UTF_BEGIN ;
2514+ attname = pstrdup (UTF_E2U (NameStr (tupdesc -> attrs [i ]-> attname )));
2515+ UTF_END ;
25282516
25292517 /************************************************************
25302518 * Get the attributes value
@@ -2552,6 +2540,8 @@ pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname,
25522540 }
25532541 else
25542542 Tcl_UnsetVar2 (interp , * arrptr , * nameptr , 0 );
2543+
2544+ pfree ((char * ) attname );
25552545 }
25562546}
25572547
0 commit comments