On 2019-Dec-09, Tom Lane wrote: > Alvaro Herrera <alvhe...@2ndquadrant.com> writes: > > So rather than mess with stringinfo.c at all I could just create > > stringinfo_server.c and put this function there, compiled only for > > backend ... > > Good point: if we make a separate source file then we don't have > to solve any of the code-movement issues till somebody wants this > functionality in frontend. But we should expect that that day might > come eventually, so I don't much like "stringinfo_server.c" as the > file name. It'll look pretty silly once we start compiling it for > frontend. Perhaps "appendquoted.c" or some such?
Okay, so here are two patches. I had already used the name stringinfo_mb.c, so that's what's v19. (I'm fine with renaming it to appendquoted.c but we might gain other such functions in the future. Other opinions?) The other patch (v18) puts the new function together with moving wchar to pgcommon. The API is different in each case: if we want it available in frontend, we need to pass the encoding as a parameter rather than use GetDatabaseEncoding(). This is pg_waldump with the first patch (src/utils/mb/stringinfo_mb.c): $ nm --print-size /pgsql/install/master/bin/pg_waldump | grep -i stringinfo 000000000000a8f0 0000000000000060 T appendBinaryStringInfo 000000000000a980 0000000000000051 T appendBinaryStringInfoNT 000000000000a770 00000000000000d7 T appendStringInfo 000000000000a850 0000000000000050 T appendStringInfoChar 000000000000a8a0 000000000000004d T appendStringInfoSpaces 000000000000a950 0000000000000027 T appendStringInfoString 000000000000a630 0000000000000083 T appendStringInfoVA 000000000000a6c0 00000000000000af T enlargeStringInfo 000000000000a5e0 000000000000002b T initStringInfo 000000000000a5a0 0000000000000038 T makeStringInfo 000000000000a610 0000000000000015 T resetStringInfo $ ls -l /pgsql/install/master/bin/pg_waldump -rwxr-xr-x 1 alvherre alvherre 647576 dic 9 16:23 /pgsql/install/master/bin/pg_waldump* This is with v18: $ nm --print-size /pgsql/install/master/bin/pg_waldump | grep -i stringinfo 000000000000c8f0 0000000000000060 T appendBinaryStringInfo 000000000000c980 0000000000000051 T appendBinaryStringInfoNT 000000000000c770 00000000000000d7 T appendStringInfo 000000000000c850 0000000000000050 T appendStringInfoChar 000000000000c8a0 000000000000004d T appendStringInfoSpaces 000000000000c950 0000000000000027 T appendStringInfoString 000000000000c9e0 00000000000001b1 T appendStringInfoStringQuoted 000000000000c630 0000000000000083 T appendStringInfoVA 000000000000c6c0 00000000000000af T enlargeStringInfo 000000000000c5e0 000000000000002b T initStringInfo 000000000000c5a0 0000000000000038 T makeStringInfo 000000000000c610 0000000000000015 T resetStringInfo $ ls -l /pgsql/install/master/bin/pg_waldump -rwxr-xr-x 1 alvherre alvherre 704808 dic 9 16:29 /pgsql/install/master/bin/pg_waldump* While the function itself is tiny (though it's the largest of all stringinfo functions, hmm), it has led to a rather huge bloating of the binary. That's because the new binary contains a number of functions from wchar.c, like you said, such as $ nm --print-size /pgsql/install/master/bin/pg_waldump | grep dsplen 000000000000d820 0000000000000026 t pg_ascii_dsplen 000000000000e200 0000000000000005 t pg_big5_dsplen 000000000000eb30 0000000000000030 T pg_encoding_dsplen 000000000000dac0 000000000000002e t pg_euccn_dsplen 000000000000d960 0000000000000036 t pg_eucjp_dsplen 000000000000d9b0 000000000000002e t pg_euckr_dsplen 000000000000dc10 000000000000002e t pg_euctw_dsplen 000000000000e230 0000000000000005 t pg_gb18030_dsplen 000000000000e210 0000000000000005 t pg_gbk_dsplen 000000000000dd10 0000000000000005 t pg_johab_dsplen 000000000000e170 0000000000000026 t pg_latin1_dsplen 000000000000e0f0 0000000000000034 t pg_mule_dsplen 000000000000e1c0 0000000000000036 t pg_sjis_dsplen 000000000000e220 0000000000000005 t pg_uhc_dsplen 000000000000e870 000000000000013e t pg_utf_dsplen and some others. All in all, it seems like v19 is the way to go. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From 36f0dc29c1187c49c5072d48796ccbb3369ed8f7 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Tue, 3 Dec 2019 10:08:35 -0300 Subject: [PATCH v18] Add appendStringInfoStringQuoted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifies some coding that prints parameters, as well as optimize to do it per non-quote chunks instead of per byte. This version of the patch makes the new function available to frontends, and puts wchar.c/encnames.c in libpgport. Author: Alexey Bashtanov and Álvaro Herrera, after a suggestion from Andres Freund Discussion: https://postgr.es/m/20190920203905.xkv5udsd5dxfs...@alap3.anarazel.de --- src/backend/tcop/postgres.c | 11 +---- src/backend/utils/mb/mbutils.c | 31 ------------ src/backend/utils/mb/wchar.c | 47 ++++++++++++++++++ src/common/Makefile | 9 +++- src/common/stringinfo.c | 71 +++++++++++++++++++++++++++ src/include/lib/stringinfo.h | 10 ++++ src/pl/plpgsql/src/pl_exec.c | 39 +++++---------- src/test/regress/expected/plpgsql.out | 14 ++++++ src/test/regress/sql/plpgsql.sql | 13 +++++ 9 files changed, 178 insertions(+), 67 deletions(-) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 3b85e48333..a5e398b2f5 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2348,7 +2348,6 @@ errdetail_params(ParamListInfo params) Oid typoutput; bool typisvarlena; char *pstring; - char *p; appendStringInfo(¶m_str, "%s$%d = ", paramno > 0 ? ", " : "", @@ -2364,14 +2363,8 @@ errdetail_params(ParamListInfo params) pstring = OidOutputFunctionCall(typoutput, prm->value); - appendStringInfoCharMacro(¶m_str, '\''); - for (p = pstring; *p; p++) - { - if (*p == '\'') /* double single quotes */ - appendStringInfoCharMacro(¶m_str, *p); - appendStringInfoCharMacro(¶m_str, *p); - } - appendStringInfoCharMacro(¶m_str, '\''); + appendStringInfoStringQuoted(¶m_str, GetDatabaseEncoding(), + pstring, 0); pfree(pstring); } diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c index 6b08b77717..34e9fd9f2c 100644 --- a/src/backend/utils/mb/mbutils.c +++ b/src/backend/utils/mb/mbutils.c @@ -865,37 +865,6 @@ pg_mbcliplen(const char *mbstr, int len, int limit) len, limit); } -/* - * pg_mbcliplen with specified encoding - */ -int -pg_encoding_mbcliplen(int encoding, const char *mbstr, - int len, int limit) -{ - mblen_converter mblen_fn; - int clen = 0; - int l; - - /* optimization for single byte encoding */ - if (pg_encoding_max_length(encoding) == 1) - return cliplen(mbstr, len, limit); - - mblen_fn = pg_wchar_table[encoding].mblen; - - while (len > 0 && *mbstr) - { - l = (*mblen_fn) ((const unsigned char *) mbstr); - if ((clen + l) > limit) - break; - clen += l; - if (clen == limit) - break; - len -= l; - mbstr += l; - } - return clen; -} - /* * Similar to pg_mbcliplen except the limit parameter specifies the * character length, not the byte length. diff --git a/src/backend/utils/mb/wchar.c b/src/backend/utils/mb/wchar.c index b2d598cbee..f0e57593f7 100644 --- a/src/backend/utils/mb/wchar.c +++ b/src/backend/utils/mb/wchar.c @@ -14,6 +14,10 @@ #include "mb/pg_wchar.h" +/* Internal functions */ +static int cliplen(const char *str, int len, int limit); + + /* * Operations on multi-byte encodings are driven by a table of helper * functions. @@ -1861,6 +1865,49 @@ pg_encoding_verifymb(int encoding, const char *mbstr, int len) pg_wchar_table[PG_SQL_ASCII].mbverify((const unsigned char *) mbstr, len)); } +/* mbcliplen for any single-byte encoding */ +static int +cliplen(const char *str, int len, int limit) +{ + int l = 0; + + len = Min(len, limit); + while (l < len && str[l]) + l++; + return l; +} + +/* + * pg_mbcliplen with specified encoding + */ +int +pg_encoding_mbcliplen(int encoding, const char *mbstr, + int len, int limit) +{ + mblen_converter mblen_fn; + int clen = 0; + int l; + + /* optimization for single byte encoding */ + if (pg_encoding_max_length(encoding) == 1) + return cliplen(mbstr, len, limit); + + mblen_fn = pg_wchar_table[encoding].mblen; + + while (len > 0 && *mbstr) + { + l = (*mblen_fn) ((const unsigned char *) mbstr); + if ((clen + l) > limit) + break; + clen += l; + if (clen == limit) + break; + len -= l; + mbstr += l; + } + return clen; +} + /* * fetch maximum length of a given encoding */ diff --git a/src/common/Makefile b/src/common/Makefile index ffb0f6edff..0146918758 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -78,6 +78,8 @@ else OBJS_COMMON += sha2.o endif +backend_src = $(top_srcdir)/src/backend + # A few files are currently only built for frontend, not server # (Mkvcbuild.pm has a copy of this list, too) OBJS_FRONTEND = \ @@ -85,7 +87,9 @@ OBJS_FRONTEND = \ fe_memutils.o \ file_utils.o \ logging.o \ - restricted_token.o + restricted_token.o \ + wchar.o \ + encnames.o # foo.o, foo_shlib.o, and foo_srv.o are all built from foo.c OBJS_SHLIB = $(OBJS_FRONTEND:%.o=%_shlib.o) @@ -158,6 +162,9 @@ kwlist_d.h: $(top_srcdir)/src/include/parser/kwlist.h $(GEN_KEYWORDLIST_DEPS) # that you don't get broken parsing code, even in a non-enable-depend build. keywords.o keywords_shlib.o keywords_srv.o: kwlist_d.h +encnames.c wchar.c: % : $(backend_src)/utils/mb/% + rm -f $@ && $(LN_S) $< . + # The code imported from Ryu gets a pass on declaration-after-statement, # in order to keep it more closely aligned with its upstream. RYU_FILES = d2s.o f2s.o diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c index a50e587da9..5198ef97ac 100644 --- a/src/common/stringinfo.c +++ b/src/common/stringinfo.c @@ -30,6 +30,7 @@ #endif #include "lib/stringinfo.h" +#include "mb/pg_wchar.h" /* @@ -178,6 +179,76 @@ appendStringInfoString(StringInfo str, const char *s) appendBinaryStringInfo(str, s, strlen(s)); } +/* + * appendStringInfoStringQuoted + * + * Append up to maxlen characters from s (which is in the given encoding) to + * str, or the whole input string if maxlen <= 0, adding single quotes around + * it and doubling all single quotes. Add an ellipsis if the copy is + * incomplete. + */ +void +appendStringInfoStringQuoted(StringInfo str, int encoding, const char *s, + int maxlen) +{ + char *copy = NULL; + const char *chunk_search_start, + *chunk_copy_start, + *chunk_end; + bool ellipsis; + int slen; + + Assert(str != NULL); + + slen = strlen(s); + if (maxlen > 0 && maxlen < slen) + { + int finallen = pg_encoding_mbcliplen(encoding, s, slen, maxlen); + + copy = pnstrdup(s, finallen); + chunk_search_start = copy; + chunk_copy_start = copy; + + ellipsis = true; + } + else + { + chunk_search_start = s; + chunk_copy_start = s; + + ellipsis = false; + } + + appendStringInfoCharMacro(str, '\''); + + while ((chunk_end = strchr(chunk_search_start, '\'')) != NULL) + { + /* copy including the found delimiting ' */ + appendBinaryStringInfoNT(str, + chunk_copy_start, + chunk_end - chunk_copy_start + 1); + + /* in order to double it, include this ' into the next chunk as well */ + chunk_copy_start = chunk_end; + chunk_search_start = chunk_end + 1; + } + + /* copy the last chunk and terminate */ + if (ellipsis) + appendStringInfo(str, "%s...'", chunk_copy_start); + else + { + int len = strlen(chunk_copy_start); + + /* ensure sufficient space for terminators */ + appendBinaryStringInfoNT(str, chunk_copy_start, len); + appendStringInfoCharMacro(str, '\''); + } + + if (copy) + pfree(copy); +} + /* * appendStringInfoChar * diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h index e27942728e..4a2af9e50b 100644 --- a/src/include/lib/stringinfo.h +++ b/src/include/lib/stringinfo.h @@ -113,6 +113,16 @@ extern int appendStringInfoVA(StringInfo str, const char *fmt, va_list args) pg_ */ extern void appendStringInfoString(StringInfo str, const char *s); +/*------------------------ + * appendStringInfoStringQuoted + * Append up to maxlen characters from s (which is in the given encoding) to + * str, or the whole input string if maxlen <= 0, adding single quotes around + * it and doubling all single quotes. Add an ellipsis if the copy is + * incomplete. + */ +extern void appendStringInfoStringQuoted(StringInfo str, int encoding, + const char *s, int maxlen); + /*------------------------ * appendStringInfoChar * Append a single byte to str. diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 4f0de7a811..1ba1783490 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -28,6 +28,7 @@ #include "executor/spi.h" #include "executor/spi_priv.h" #include "funcapi.h" +#include "mb/pg_wchar.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "optimizer/optimizer.h" @@ -8611,19 +8612,12 @@ format_expr_params(PLpgSQL_execstate *estate, if (paramisnull) appendStringInfoString(¶mstr, "NULL"); else - { - char *value = convert_value_to_string(estate, paramdatum, paramtypeid); - char *p; - - appendStringInfoCharMacro(¶mstr, '\''); - for (p = value; *p; p++) - { - if (*p == '\'') /* double single quotes */ - appendStringInfoCharMacro(¶mstr, *p); - appendStringInfoCharMacro(¶mstr, *p); - } - appendStringInfoCharMacro(¶mstr, '\''); - } + appendStringInfoStringQuoted(¶mstr, + GetDatabaseEncoding(), + convert_value_to_string(estate, + paramdatum, + paramtypeid), + 0); paramno++; } @@ -8661,19 +8655,12 @@ format_preparedparamsdata(PLpgSQL_execstate *estate, if (ppd->nulls[paramno] == 'n') appendStringInfoString(¶mstr, "NULL"); else - { - char *value = convert_value_to_string(estate, ppd->values[paramno], ppd->types[paramno]); - char *p; - - appendStringInfoCharMacro(¶mstr, '\''); - for (p = value; *p; p++) - { - if (*p == '\'') /* double single quotes */ - appendStringInfoCharMacro(¶mstr, *p); - appendStringInfoCharMacro(¶mstr, *p); - } - appendStringInfoCharMacro(¶mstr, '\''); - } + appendStringInfoStringQuoted(¶mstr, + GetDatabaseEncoding(), + convert_value_to_string(estate, + ppd->values[paramno], + ppd->types[paramno]), + 0); } MemoryContextSwitchTo(oldcontext); diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index e85b29455e..cd2c79f4d5 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -2656,6 +2656,20 @@ create or replace function stricttest() returns void as $$ declare x record; p1 int := 2; +p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$; +begin + -- no rows + select * from foo where f1 = p1 and f1::text = p3 into strict x; + raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; +end$$ language plpgsql; +select stricttest(); +ERROR: query returned no rows +DETAIL: parameters: p1 = '2', p3 = '''Valame Dios!'' dijo Sancho; ''no le dije yo a vuestra merced que mirase bien lo que hacia?''' +CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement +create or replace function stricttest() returns void as $$ +declare +x record; +p1 int := 2; p3 text := 'foo'; begin -- too many rows diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 70deadfbea..d841d8c0f9 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -2280,6 +2280,19 @@ end$$ language plpgsql; select stricttest(); +create or replace function stricttest() returns void as $$ +declare +x record; +p1 int := 2; +p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$; +begin + -- no rows + select * from foo where f1 = p1 and f1::text = p3 into strict x; + raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; +end$$ language plpgsql; + +select stricttest(); + create or replace function stricttest() returns void as $$ declare x record; -- 2.20.1
>From 817041a46a31ed951d84b6039bd469feea577052 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Tue, 3 Dec 2019 10:08:35 -0300 Subject: [PATCH v19] Add appendStringInfoStringQuoted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifies some coding that prints parameters, as well as optimize to do it per non-quote chunks instead of per byte. Put the new function in a new backend-only file, stringinfo_mb.c. Author: Alexey Bashtanov and Álvaro Herrera, after a suggestion from Andres Freund Discussion: https://postgr.es/m/20190920203905.xkv5udsd5dxfs...@alap3.anarazel.de --- src/backend/tcop/postgres.c | 10 +-- src/backend/utils/mb/Makefile | 1 + src/backend/utils/mb/stringinfo_mb.c | 87 +++++++++++++++++++++++++++ src/common/stringinfo.c | 1 + src/include/lib/stringinfo.h | 14 +++++ src/pl/plpgsql/src/pl_exec.c | 36 +++-------- src/test/regress/expected/plpgsql.out | 14 +++++ src/test/regress/sql/plpgsql.sql | 13 ++++ 8 files changed, 141 insertions(+), 35 deletions(-) create mode 100644 src/backend/utils/mb/stringinfo_mb.c diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 3b85e48333..3d3172e83d 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2348,7 +2348,6 @@ errdetail_params(ParamListInfo params) Oid typoutput; bool typisvarlena; char *pstring; - char *p; appendStringInfo(¶m_str, "%s$%d = ", paramno > 0 ? ", " : "", @@ -2364,14 +2363,7 @@ errdetail_params(ParamListInfo params) pstring = OidOutputFunctionCall(typoutput, prm->value); - appendStringInfoCharMacro(¶m_str, '\''); - for (p = pstring; *p; p++) - { - if (*p == '\'') /* double single quotes */ - appendStringInfoCharMacro(¶m_str, *p); - appendStringInfoCharMacro(¶m_str, *p); - } - appendStringInfoCharMacro(¶m_str, '\''); + appendStringInfoStringQuoted(¶m_str, pstring, 0); pfree(pstring); } diff --git a/src/backend/utils/mb/Makefile b/src/backend/utils/mb/Makefile index 18dd758cfe..cd4a016449 100644 --- a/src/backend/utils/mb/Makefile +++ b/src/backend/utils/mb/Makefile @@ -16,6 +16,7 @@ OBJS = \ conv.o \ encnames.o \ mbutils.o \ + stringinfo_mb.o \ wchar.o \ wstrcmp.o \ wstrncmp.o diff --git a/src/backend/utils/mb/stringinfo_mb.c b/src/backend/utils/mb/stringinfo_mb.c new file mode 100644 index 0000000000..92771431e4 --- /dev/null +++ b/src/backend/utils/mb/stringinfo_mb.c @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------- + * + * stringinfo_mb.c + * + * multibyte-aware additional StringInfo facilites + * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/backend/utils/stringinfo_mb.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "lib/stringinfo.h" +#include "mb/pg_wchar.h" +#include "utils/memutils.h" + + +/* + * appendStringInfoStringQuoted + * + * Append a null-terminated string to str, adding single quotes around it + * and doubling all single quotes. + */ +void +appendStringInfoStringQuoted(StringInfo str, const char *s, int maxlen) +{ + char *copy = NULL; + const char *chunk_search_start, + *chunk_copy_start, + *chunk_end; + bool ellipsis; + int slen; + + Assert(str != NULL); + + slen = strlen(s); + if (maxlen > 0 && maxlen < slen) + { + int finallen = pg_mbcliplen(s, slen, maxlen); + + copy = pnstrdup(s, finallen); + chunk_search_start = copy; + chunk_copy_start = copy; + + ellipsis = true; + } + else + { + chunk_search_start = s; + chunk_copy_start = s; + + ellipsis = false; + } + + appendStringInfoCharMacro(str, '\''); + + while ((chunk_end = strchr(chunk_search_start, '\'')) != NULL) + { + /* copy including the found delimiting ' */ + appendBinaryStringInfoNT(str, + chunk_copy_start, + chunk_end - chunk_copy_start + 1); + + /* in order to double it, include this ' into the next chunk as well */ + chunk_copy_start = chunk_end; + chunk_search_start = chunk_end + 1; + } + + /* copy the last chunk and terminate */ + if (ellipsis) + appendStringInfo(str, "%s...'", chunk_copy_start); + else + { + int len = strlen(chunk_copy_start); + + /* ensure sufficient space for terminators */ + appendBinaryStringInfoNT(str, chunk_copy_start, len); + appendStringInfoCharMacro(str, '\''); + } + + if (copy) + pfree(copy); +} diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c index a50e587da9..90970b54b7 100644 --- a/src/common/stringinfo.c +++ b/src/common/stringinfo.c @@ -30,6 +30,7 @@ #endif #include "lib/stringinfo.h" +#include "mb/pg_wchar.h" /* diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h index e27942728e..aadd00b2fb 100644 --- a/src/include/lib/stringinfo.h +++ b/src/include/lib/stringinfo.h @@ -158,4 +158,18 @@ extern void appendBinaryStringInfoNT(StringInfo str, */ extern void enlargeStringInfo(StringInfo str, int needed); +/* In stringinfo_mb.c */ +#ifndef FRONTEND +/*------------------------ + * appendStringInfoStringQuoted + * Append up to maxlen characters from s (which is in the given encoding) to + * str, or the whole input string if maxlen <= 0, adding single quotes around + * it and doubling all single quotes. Add an ellipsis if the copy is + * incomplete. + */ +extern void appendStringInfoStringQuoted(StringInfo str, + const char *s, int maxlen); +#endif + + #endif /* STRINGINFO_H */ diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 4f0de7a811..c3ae409f39 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -8611,19 +8611,11 @@ format_expr_params(PLpgSQL_execstate *estate, if (paramisnull) appendStringInfoString(¶mstr, "NULL"); else - { - char *value = convert_value_to_string(estate, paramdatum, paramtypeid); - char *p; - - appendStringInfoCharMacro(¶mstr, '\''); - for (p = value; *p; p++) - { - if (*p == '\'') /* double single quotes */ - appendStringInfoCharMacro(¶mstr, *p); - appendStringInfoCharMacro(¶mstr, *p); - } - appendStringInfoCharMacro(¶mstr, '\''); - } + appendStringInfoStringQuoted(¶mstr, + convert_value_to_string(estate, + paramdatum, + paramtypeid), + 0); paramno++; } @@ -8661,19 +8653,11 @@ format_preparedparamsdata(PLpgSQL_execstate *estate, if (ppd->nulls[paramno] == 'n') appendStringInfoString(¶mstr, "NULL"); else - { - char *value = convert_value_to_string(estate, ppd->values[paramno], ppd->types[paramno]); - char *p; - - appendStringInfoCharMacro(¶mstr, '\''); - for (p = value; *p; p++) - { - if (*p == '\'') /* double single quotes */ - appendStringInfoCharMacro(¶mstr, *p); - appendStringInfoCharMacro(¶mstr, *p); - } - appendStringInfoCharMacro(¶mstr, '\''); - } + appendStringInfoStringQuoted(¶mstr, + convert_value_to_string(estate, + ppd->values[paramno], + ppd->types[paramno]), + 0); } MemoryContextSwitchTo(oldcontext); diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index e85b29455e..cd2c79f4d5 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -2656,6 +2656,20 @@ create or replace function stricttest() returns void as $$ declare x record; p1 int := 2; +p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$; +begin + -- no rows + select * from foo where f1 = p1 and f1::text = p3 into strict x; + raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; +end$$ language plpgsql; +select stricttest(); +ERROR: query returned no rows +DETAIL: parameters: p1 = '2', p3 = '''Valame Dios!'' dijo Sancho; ''no le dije yo a vuestra merced que mirase bien lo que hacia?''' +CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement +create or replace function stricttest() returns void as $$ +declare +x record; +p1 int := 2; p3 text := 'foo'; begin -- too many rows diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 70deadfbea..d841d8c0f9 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -2280,6 +2280,19 @@ end$$ language plpgsql; select stricttest(); +create or replace function stricttest() returns void as $$ +declare +x record; +p1 int := 2; +p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$; +begin + -- no rows + select * from foo where f1 = p1 and f1::text = p3 into strict x; + raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2; +end$$ language plpgsql; + +select stricttest(); + create or replace function stricttest() returns void as $$ declare x record; -- 2.20.1