Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6cafde1

Browse files
committed
Add backend-only appendStringInfoStringQuoted
This provides a mechanism to emit literal values in informative messages, such as query parameters. The new code is more complex than what it replaces, primarily because it wants to be more efficient. It also has the (currently unused) additional optional capability of specifying a maximum size to print. The new function lives out of common/stringinfo.c so that frontend users of that file need not pull in unnecessary multibyte-encoding support code. Author: Álvaro Herrera and Alexey Bashtanov, after a suggestion from Andres Freund Reviewed-by: Tom Lane Discussion: https://postgr.es/m/20190920203905.xkv5udsd5dxfs6tr@alap3.anarazel.de
1 parent 0da33c7 commit 6cafde1

File tree

8 files changed

+152
-35
lines changed

8 files changed

+152
-35
lines changed

src/backend/tcop/postgres.c

+2-9
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "libpq/pqformat.h"
4949
#include "libpq/pqsignal.h"
5050
#include "mb/pg_wchar.h"
51+
#include "mb/stringinfo_mb.h"
5152
#include "miscadmin.h"
5253
#include "nodes/print.h"
5354
#include "optimizer/optimizer.h"
@@ -2348,7 +2349,6 @@ errdetail_params(ParamListInfo params)
23482349
Oid typoutput;
23492350
bool typisvarlena;
23502351
char *pstring;
2351-
char *p;
23522352

23532353
appendStringInfo(&param_str, "%s$%d = ",
23542354
paramno > 0 ? ", " : "",
@@ -2364,14 +2364,7 @@ errdetail_params(ParamListInfo params)
23642364

23652365
pstring = OidOutputFunctionCall(typoutput, prm->value);
23662366

2367-
appendStringInfoCharMacro(&param_str, '\'');
2368-
for (p = pstring; *p; p++)
2369-
{
2370-
if (*p == '\'') /* double single quotes */
2371-
appendStringInfoCharMacro(&param_str, *p);
2372-
appendStringInfoCharMacro(&param_str, *p);
2373-
}
2374-
appendStringInfoCharMacro(&param_str, '\'');
2367+
appendStringInfoStringQuoted(&param_str, pstring, 0);
23752368

23762369
pfree(pstring);
23772370
}

src/backend/utils/mb/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ OBJS = \
1616
conv.o \
1717
encnames.o \
1818
mbutils.o \
19+
stringinfo_mb.o \
1920
wchar.o \
2021
wstrcmp.o \
2122
wstrncmp.o

src/backend/utils/mb/README

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ wchar.c: mostly static functions and a public table for mb string and
99
multibyte conversion
1010
mbutils.c: public functions for the backend only.
1111
requires conv.c and wchar.c
12+
stringinfo_mb.c: public backend-only multibyte-aware stringinfo functions
1213
wstrcmp.c: strcmp for mb
1314
wstrncmp.c: strncmp for mb
1415
win866.c: a tool to generate KOI8 <--> CP866 conversion table

src/backend/utils/mb/stringinfo_mb.c

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* stringinfo_mb.c
4+
* Multibyte encoding-aware additional StringInfo facilites
5+
*
6+
* This is separate from common/stringinfo.c so that frontend users
7+
* of that file need not pull in unnecessary multibyte-encoding support
8+
* code.
9+
*
10+
*
11+
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
12+
* Portions Copyright (c) 1994, Regents of the University of California
13+
*
14+
*
15+
* IDENTIFICATION
16+
* src/backend/utils/mb/stringinfo_mb.c
17+
*
18+
*-------------------------------------------------------------------------
19+
*/
20+
#include "postgres.h"
21+
22+
#include "mb/stringinfo_mb.h"
23+
#include "mb/pg_wchar.h"
24+
25+
26+
/*
27+
* appendStringInfoStringQuoted
28+
*
29+
* Append up to maxlen characters from s to str, or the whole input string if
30+
* maxlen <= 0, adding single quotes around it and doubling all single quotes.
31+
* Add an ellipsis if the copy is incomplete.
32+
*/
33+
void
34+
appendStringInfoStringQuoted(StringInfo str, const char *s, int maxlen)
35+
{
36+
char *copy = NULL;
37+
const char *chunk_search_start,
38+
*chunk_copy_start,
39+
*chunk_end;
40+
int slen;
41+
bool ellipsis;
42+
43+
Assert(str != NULL);
44+
45+
slen = strlen(s);
46+
if (maxlen > 0 && maxlen < slen)
47+
{
48+
int finallen = pg_mbcliplen(s, slen, maxlen);
49+
50+
copy = pnstrdup(s, finallen);
51+
chunk_search_start = copy;
52+
chunk_copy_start = copy;
53+
54+
ellipsis = true;
55+
}
56+
else
57+
{
58+
chunk_search_start = s;
59+
chunk_copy_start = s;
60+
61+
ellipsis = false;
62+
}
63+
64+
appendStringInfoCharMacro(str, '\'');
65+
66+
while ((chunk_end = strchr(chunk_search_start, '\'')) != NULL)
67+
{
68+
/* copy including the found delimiting ' */
69+
appendBinaryStringInfoNT(str,
70+
chunk_copy_start,
71+
chunk_end - chunk_copy_start + 1);
72+
73+
/* in order to double it, include this ' into the next chunk as well */
74+
chunk_copy_start = chunk_end;
75+
chunk_search_start = chunk_end + 1;
76+
}
77+
78+
/* copy the last chunk and terminate */
79+
if (ellipsis)
80+
appendStringInfo(str, "%s...'", chunk_copy_start);
81+
else
82+
appendStringInfo(str, "%s'", chunk_copy_start);
83+
84+
if (copy)
85+
pfree(copy);
86+
}

src/include/mb/stringinfo_mb.h

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* stringinfo_mb.h
4+
* multibyte support for StringInfo
5+
*
6+
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* src/include/mb/stringinfo_mb.h
10+
*-------------------------------------------------------------------------
11+
*/
12+
#ifndef STRINGINFO_MB_H
13+
#define STRINGINFO_MB_H
14+
15+
16+
#include "lib/stringinfo.h"
17+
18+
/*
19+
* Multibyte-aware StringInfo support function.
20+
*/
21+
extern void appendStringInfoStringQuoted(StringInfo str,
22+
const char *s, int maxlen);
23+
24+
#endif /* STRINGINFO_MB_H */

src/pl/plpgsql/src/pl_exec.c

+11-26
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "executor/spi.h"
2929
#include "executor/spi_priv.h"
3030
#include "funcapi.h"
31+
#include "mb/stringinfo_mb.h"
3132
#include "miscadmin.h"
3233
#include "nodes/nodeFuncs.h"
3334
#include "optimizer/optimizer.h"
@@ -8611,19 +8612,11 @@ format_expr_params(PLpgSQL_execstate *estate,
86118612
if (paramisnull)
86128613
appendStringInfoString(&paramstr, "NULL");
86138614
else
8614-
{
8615-
char *value = convert_value_to_string(estate, paramdatum, paramtypeid);
8616-
char *p;
8617-
8618-
appendStringInfoCharMacro(&paramstr, '\'');
8619-
for (p = value; *p; p++)
8620-
{
8621-
if (*p == '\'') /* double single quotes */
8622-
appendStringInfoCharMacro(&paramstr, *p);
8623-
appendStringInfoCharMacro(&paramstr, *p);
8624-
}
8625-
appendStringInfoCharMacro(&paramstr, '\'');
8626-
}
8615+
appendStringInfoStringQuoted(&paramstr,
8616+
convert_value_to_string(estate,
8617+
paramdatum,
8618+
paramtypeid),
8619+
0);
86278620

86288621
paramno++;
86298622
}
@@ -8661,19 +8654,11 @@ format_preparedparamsdata(PLpgSQL_execstate *estate,
86618654
if (ppd->nulls[paramno] == 'n')
86628655
appendStringInfoString(&paramstr, "NULL");
86638656
else
8664-
{
8665-
char *value = convert_value_to_string(estate, ppd->values[paramno], ppd->types[paramno]);
8666-
char *p;
8667-
8668-
appendStringInfoCharMacro(&paramstr, '\'');
8669-
for (p = value; *p; p++)
8670-
{
8671-
if (*p == '\'') /* double single quotes */
8672-
appendStringInfoCharMacro(&paramstr, *p);
8673-
appendStringInfoCharMacro(&paramstr, *p);
8674-
}
8675-
appendStringInfoCharMacro(&paramstr, '\'');
8676-
}
8657+
appendStringInfoStringQuoted(&paramstr,
8658+
convert_value_to_string(estate,
8659+
ppd->values[paramno],
8660+
ppd->types[paramno]),
8661+
0);
86778662
}
86788663

86798664
MemoryContextSwitchTo(oldcontext);

src/test/regress/expected/plpgsql.out

+14
Original file line numberDiff line numberDiff line change
@@ -2656,6 +2656,20 @@ create or replace function stricttest() returns void as $$
26562656
declare
26572657
x record;
26582658
p1 int := 2;
2659+
p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$;
2660+
begin
2661+
-- no rows
2662+
select * from foo where f1 = p1 and f1::text = p3 into strict x;
2663+
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
2664+
end$$ language plpgsql;
2665+
select stricttest();
2666+
ERROR: query returned no rows
2667+
DETAIL: parameters: p1 = '2', p3 = '''Valame Dios!'' dijo Sancho; ''no le dije yo a vuestra merced que mirase bien lo que hacia?'''
2668+
CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement
2669+
create or replace function stricttest() returns void as $$
2670+
declare
2671+
x record;
2672+
p1 int := 2;
26592673
p3 text := 'foo';
26602674
begin
26612675
-- too many rows

src/test/regress/sql/plpgsql.sql

+13
Original file line numberDiff line numberDiff line change
@@ -2280,6 +2280,19 @@ end$$ language plpgsql;
22802280

22812281
select stricttest();
22822282

2283+
create or replace function stricttest() returns void as $$
2284+
declare
2285+
x record;
2286+
p1 int := 2;
2287+
p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$;
2288+
begin
2289+
-- no rows
2290+
select * from foo where f1 = p1 and f1::text = p3 into strict x;
2291+
raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
2292+
end$$ language plpgsql;
2293+
2294+
select stricttest();
2295+
22832296
create or replace function stricttest() returns void as $$
22842297
declare
22852298
x record;

0 commit comments

Comments
 (0)