From 16910e44de129ce1ae16b1a97f95a61ec984d2c9 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Thu, 6 Sep 2001 02:56:32 +0000
Subject: [PATCH] Next version of patch. Now with documentation update and
 disabling of UTF conversion for Tcl <=8.0

On Fri, 24 Aug 2001, Vsevolod Lobko wrote:

> On Thu, 23 Aug 2001, Tom Lane wrote:
>
> > > Is this looks better?
> >
> > It does, but one small gripe: the lack of semicolons will probably cause
> > pg_indent to mess up the indentation.  (I know emacs' autoindent mode
> > will not work nicely with it, either.)  Please set up the macros so that
> > you write
> >
> >                         UTF_BEGIN;
> >                         Tcl_DStringAppend(&unknown_src, UTF_E2U(part), -1);
> >                         UTF_END;
> >
> > and then I'll be happy.
>
> Attached revised patch
>
> > Your point about overhead is a good one, so I retract the gripe about
> > using a configure switch.  But please include documentation patches to
> > describe the configure option in the administrator's guide (installation
> > section).
>
> This patch still uses configure switch for enabling feature.
>
> For enabling based on tcl version we have 2 posibilites:
>  1) having feature enabled by default, but in pltcl.c check for tcl
>     version and disable it for old versions
>  2) enable or disable at configure time based on tcl version, but there
>     are problem - current configure don't checks for tcl version at all
>     and my configure skills not enought for adding this
>

Vsevolod Lobko
---
 configure.in                   | 15 +++++++++
 doc/src/sgml/installation.sgml | 13 +++++++-
 src/include/pg_config.h.in     |  5 ++-
 src/pl/tcl/pltcl.c             | 58 +++++++++++++++++++++++++++-------
 4 files changed, 77 insertions(+), 14 deletions(-)

diff --git a/configure.in b/configure.in
index 621f8b018b..cb3d9bd9e8 100644
--- a/configure.in
+++ b/configure.in
@@ -409,6 +409,21 @@ AC_MSG_RESULT([$enable_pltcl_unknown])
 AC_SUBST([enable_pltcl_unknown])
 
 
+#
+# If Tcl is enabled (above) then check for pltcl_utf
+#
+AC_MSG_CHECKING([whether to build with PL/Tcl with UTF support])
+if test "$with_tcl" = yes; then
+  PGAC_ARG_BOOL(enable, pltcl-utf, no,
+                [  --enable-pltcl-utf      build PL/Tcl UTF support (if Tcl is enabled)],
+                [AC_DEFINE([ENABLE_PLTCL_UTF])])
+else
+  enable_pltcl_utf=no
+fi
+AC_MSG_RESULT([$enable_pltcl_utf])
+AC_SUBST([enable_pltcl_utf])
+
+
 #
 # Optionally build Perl modules (Pg.pm and PL/Perl)
 #
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 4a2d34fd23..4225f02429 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/installation.sgml,v 1.51 2001/08/28 14:20:24 petere Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/installation.sgml,v 1.52 2001/09/06 02:56:32 momjian Exp $ -->
 
 <chapter id="installation">
  <title><![%flattext-install-include[<productname>PostgreSQL</>]]>
@@ -683,6 +683,17 @@ su - postgres
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term>--enable-pltcl-utf</term>
+       <listitem>
+        <para>
+         Enables enables PL/Tcl Tcl_UtfToExternal and Tcl_ExternalToUtf
+         conversion support. These functions needed for Tcl versions 8.1
+         and above for proper handling of 8-bit characters.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term>--enable-odbc</term>
        <listitem>
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c0984313e1..8a165be62d 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -8,7 +8,7 @@
  * or in pg_config.h afterwards.  Of course, if you edit pg_config.h, then your
  * changes will be overwritten the next time you run configure.
  *
- * $Id: pg_config.h.in,v 1.1 2001/08/24 14:07:49 petere Exp $
+ * $Id: pg_config.h.in,v 1.2 2001/09/06 02:56:32 momjian Exp $
  */
 
 #ifndef PG_CONFIG_H
@@ -84,6 +84,9 @@
 /* --enable-pltcl-unknown */
 #undef ENABLE_PLTCL_UNKNOWN
 
+/* --enable-pltcl-utf */
+#undef ENABLE_PLTCL_UTF
+
 /* --enable-nls */
 #undef ENABLE_NLS
 
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 3991d9dc1c..8e686eda4f 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -31,7 +31,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.38 2001/08/02 15:45:55 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.39 2001/09/06 02:56:32 momjian Exp $
  *
  **********************************************************************/
 
@@ -59,6 +59,18 @@
 #include "catalog/pg_language.h"
 #include "catalog/pg_type.h"
 
+#if defined(ENABLE_PLTCL_UTF) && TCL_MAJOR_VERSION == 8 \
+	&& TCL_MINOR_VERSION > 0
+#	define UTF_BEGIN	do { Tcl_DString _pltcl_ds_tmp
+#       define UTF_END		Tcl_DStringFree(&_pltcl_ds_tmp); } while (0)
+#       define UTF_U2E(x)	(Tcl_UtfToExternalDString(NULL,(x),-1,&_pltcl_ds_tmp))
+#	define UTF_E2U(x)	(Tcl_ExternalToUtfDString(NULL,(x),-1,&_pltcl_ds_tmp))
+#else /* ENABLE_PLTCL_UTF */
+#	define	UTF_BEGIN
+#	define	UTF_END
+#	define	UTF_U2E(x)	(x)
+#	define	UTF_E2U(x)	(x)
+#endif /* ENABLE_PLTCL_UTF */
 
 /**********************************************************************
  * The information we cache about loaded procedures
@@ -333,7 +345,9 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
 							SPI_tuptable->tupdesc, fno);
 		if (part != NULL)
 		{
-			Tcl_DStringAppend(&unknown_src, part, -1);
+			UTF_BEGIN;
+			Tcl_DStringAppend(&unknown_src, UTF_E2U(part), -1);
+			UTF_END;
 			pfree(part);
 		}
 	}
@@ -613,7 +627,9 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		}
 		proc_source = DatumGetCString(DirectFunctionCall1(textout,
 								  PointerGetDatum(&procStruct->prosrc)));
-		Tcl_DStringAppend(&proc_internal_body, proc_source, -1);
+		UTF_BEGIN;
+		Tcl_DStringAppend(&proc_internal_body, UTF_E2U(proc_source), -1);
+		UTF_END;
 		pfree(proc_source);
 		Tcl_DStringAppendElement(&proc_internal_def,
 								 Tcl_DStringValue(&proc_internal_body));
@@ -715,7 +731,9 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 													fcinfo->arg[i],
 							  ObjectIdGetDatum(prodesc->arg_out_elem[i]),
 								Int32GetDatum(prodesc->arg_out_len[i])));
-				Tcl_DStringAppendElement(&tcl_cmd, tmp);
+				UTF_BEGIN;
+				Tcl_DStringAppendElement(&tcl_cmd, UTF_E2U(tmp));
+				UTF_END;
 				pfree(tmp);
 			}
 		}
@@ -777,13 +795,15 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "pltcl: SPI_finish() failed");
 
+	UTF_BEGIN;
 	if (fcinfo->isnull)
 		retval = (Datum) 0;
 	else
 		retval = FunctionCall3(&prodesc->result_in_func,
-							   PointerGetDatum(interp->result),
+							   PointerGetDatum(UTF_U2E(interp->result)),
 							   ObjectIdGetDatum(prodesc->result_in_elem),
 							   Int32GetDatum(-1));
+	UTF_END;
 
 	/************************************************************
 	 * Finally we may restore normal error handling.
@@ -929,7 +949,9 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 
 		proc_source = DatumGetCString(DirectFunctionCall1(textout,
 								  PointerGetDatum(&procStruct->prosrc)));
-		Tcl_DStringAppend(&proc_internal_body, proc_source, -1);
+		UTF_BEGIN;
+		Tcl_DStringAppend(&proc_internal_body, UTF_E2U(proc_source), -1);
+		UTF_END;
 		pfree(proc_source);
 		Tcl_DStringAppendElement(&proc_internal_def,
 								 Tcl_DStringValue(&proc_internal_body));
@@ -1230,11 +1252,13 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		 ************************************************************/
 		modnulls[attnum - 1] = ' ';
 		fmgr_info(typinput, &finfo);
+		UTF_BEGIN;
 		modvalues[attnum - 1] =
 			FunctionCall3(&finfo,
-						  CStringGetDatum(ret_values[i++]),
+						  CStringGetDatum(UTF_U2E(ret_values[i++])),
 						  ObjectIdGetDatum(typelem),
 				   Int32GetDatum(tupdesc->attrs[attnum - 1]->atttypmod));
+		UTF_END;
 	}
 
 	rettup = SPI_modifytuple(trigdata->tg_relation, rettup, tupdesc->natts,
@@ -1558,7 +1582,9 @@ pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,
 	/************************************************************
 	 * Execute the query and handle return codes
 	 ************************************************************/
-	spi_rc = SPI_exec(argv[query_idx], count);
+	UTF_BEGIN;
+	spi_rc = SPI_exec(UTF_U2E(argv[query_idx]), count);
+	UTF_END;
 	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
 
 	switch (spi_rc)
@@ -1794,7 +1820,9 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 	/************************************************************
 	 * Prepare the plan and check for errors
 	 ************************************************************/
-	plan = SPI_prepare(argv[1], nargs, qdesc->argtypes);
+	UTF_BEGIN;
+	plan = SPI_prepare(UTF_U2E(argv[1]), nargs, qdesc->argtypes);
+	UTF_END;
 
 	if (plan == NULL)
 	{
@@ -2078,11 +2106,13 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
 		 ************************************************************/
 		for (j = 0; j < callnargs; j++)
 		{
+			UTF_BEGIN;
 			qdesc->argvalues[j] =
 				FunctionCall3(&qdesc->arginfuncs[j],
-							  CStringGetDatum(callargs[j]),
+							  CStringGetDatum(UTF_U2E(callargs[j])),
 							  ObjectIdGetDatum(qdesc->argtypelems[j]),
 							  Int32GetDatum(qdesc->arglen[j]));
+			UTF_END;
 		}
 
 		/************************************************************
@@ -2377,7 +2407,9 @@ pltcl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 														 attr,
 											   ObjectIdGetDatum(typelem),
 							  Int32GetDatum(tupdesc->attrs[i]->attlen)));
-			Tcl_SetVar2(interp, *arrptr, *nameptr, outputstr, 0);
+			UTF_BEGIN;
+			Tcl_SetVar2(interp, *arrptr, *nameptr, UTF_E2U(outputstr), 0);
+			UTF_END;
 			pfree(outputstr);
 		}
 		else
@@ -2448,7 +2480,9 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
 											   ObjectIdGetDatum(typelem),
 							  Int32GetDatum(tupdesc->attrs[i]->attlen)));
 			Tcl_DStringAppendElement(retval, attname);
-			Tcl_DStringAppendElement(retval, outputstr);
+			UTF_BEGIN;
+			Tcl_DStringAppendElement(retval, UTF_E2U(outputstr));
+			UTF_END;
 			pfree(outputstr);
 		}
 	}