From 869fc004ca6816d26bab288a16b55205e42c9d4f Mon Sep 17 00:00:00 2001
From: David Geier <geidav.pg@gmail.com>
Date: Wed, 7 Oct 2026 16:59:25 +0200
Subject: [PATCH v1] Avoid string copy in char2wchar()

---
 src/backend/utils/adt/pg_locale_libc.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c
index 02c419aa62a..e568e1088ee 100644
--- a/src/backend/utils/adt/pg_locale_libc.c
+++ b/src/backend/utils/adt/pg_locale_libc.c
@@ -13,6 +13,7 @@
 
 #include <limits.h>
 #include <wctype.h>
+#include <wchar.h>
 
 #include "access/htup_details.h"
 #include "catalog/pg_database.h"
@@ -1332,21 +1333,28 @@ char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen,
 	else
 #endif							/* WIN32 */
 	{
-		/* mbstowcs requires ending '\0' */
-		char	   *str = pnstrdup(from, fromlen);
+		const char *src_ptr = from;
+		mbstate_t st = {0};
 
 		if (loc == (locale_t) 0)
 		{
-			/* Use mbstowcs directly for the default locale */
-			result = mbstowcs(to, str, tolen);
+			/* Use mbsnrtowcs directly for the default locale */
+			result = mbsnrtowcs(to, &src_ptr, fromlen, tolen - 1, &st);
 		}
 		else
 		{
-			/* Use mbstowcs_l for nondefault locales */
-			result = mbstowcs_l(to, str, tolen, loc);
+			/* For nondefault locales, we need to use mbsnrtowcs via uselocale */
+			locale_t	save_locale = uselocale(loc);
+			result = mbsnrtowcs(to, &src_ptr, fromlen, tolen - 1, &st);
+			uselocale(save_locale);
 		}
 
-		pfree(str);
+		if (result != (size_t) -1)
+		{
+			Assert(result < tolen);
+			/* Append trailing null wchar (mbsnrtowcs() does not) */
+			to[result] = 0;
+		}
 	}
 
 	if (result == -1)
-- 
2.53.0

