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

Commit 3dfb194

Browse files
committed
Avoid premature de-doubling of quote marks in ECPG strings.
If you write the literal 'abc''def' in an EXEC SQL command, that will come out the other end as 'abc'def', triggering a syntax error in the backend. Likewise, "abc""def" is reduced to "abc"def" which is wrong syntax for a quoted identifier. The cause is that the lexer thinks it should emit just one quote mark, whereas what it really should do is keep the string as-is. Add some docs and test cases, too. Although this seems clearly a bug, I fear users wouldn't appreciate changing it in minor releases. Some may well be working around it by applying an extra doubling of affected quotes, as for example sql/dyntest.pgc has been doing. Per investigation of a report from 1250kv, although this isn't exactly what he/she was on about. Discussion: https://postgr.es/m/673825.1603223178@sss.pgh.pa.us
1 parent 8bb0c97 commit 3dfb194

File tree

7 files changed

+28
-20
lines changed

7 files changed

+28
-20
lines changed

doc/src/sgml/ecpg.sgml

+14-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
specially marked sections. To build the program, the source code (<filename>*.pgc</filename>)
3232
is first passed through the embedded SQL preprocessor, which converts it
3333
to an ordinary C program (<filename>*.c</filename>), and afterwards it can be processed by a C
34-
compiler. (For details about the compiling and linking see <xref linkend="ecpg-process"/>).
34+
compiler. (For details about the compiling and linking see <xref linkend="ecpg-process"/>.)
3535
Converted ECPG applications call functions in the libpq library
3636
through the embedded SQL library (ecpglib), and communicate with
3737
the PostgreSQL server using the normal frontend-backend protocol.
@@ -63,11 +63,22 @@ EXEC SQL ...;
6363
</programlisting>
6464
These statements syntactically take the place of a C statement.
6565
Depending on the particular statement, they can appear at the
66-
global level or within a function. Embedded
66+
global level or within a function.
67+
</para>
68+
69+
<para>
70+
Embedded
6771
<acronym>SQL</acronym> statements follow the case-sensitivity rules of
6872
normal <acronym>SQL</acronym> code, and not those of C. Also they allow nested
69-
C-style comments that are part of the SQL standard. The C part of the
73+
C-style comments as per the SQL standard. The C part of the
7074
program, however, follows the C standard of not accepting nested comments.
75+
Embedded <acronym>SQL</acronym> statements likewise use SQL rules, not
76+
C rules, for parsing quoted strings and identifiers.
77+
(See <xref linkend="sql-syntax-strings"/> and
78+
<xref linkend="sql-syntax-identifiers"/> respectively. Note that
79+
ECPG assumes that <varname>standard_conforming_strings</varname>
80+
is <literal>on</literal>.)
81+
Of course, the C part of the program follows C quoting rules.
7182
</para>
7283

7384
<para>

src/interfaces/ecpg/preproc/pgc.l

+3-6
Original file line numberDiff line numberDiff line change
@@ -623,11 +623,8 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
623623
}
624624
}
625625

626-
<xq,xe,xn,xus>{xqdouble} { addlitchar('\''); }
627-
<xqc>{xqcquote} {
628-
addlitchar('\\');
629-
addlitchar('\'');
630-
}
626+
<xq,xe,xn,xus>{xqdouble} { addlit(yytext, yyleng); }
627+
<xqc>{xqcquote} { addlit(yytext, yyleng); }
631628
<xq,xqc,xn,xus>{xqinside} { addlit(yytext, yyleng); }
632629
<xe>{xeinside} {
633630
addlit(yytext, yyleng);
@@ -736,7 +733,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
736733
return UIDENT;
737734
}
738735
<xd,xui>{xddouble} {
739-
addlitchar('"');
736+
addlit(yytext, yyleng);
740737
}
741738
<xd,xui>{xdinside} {
742739
addlit(yytext, yyleng);

src/interfaces/ecpg/test/expected/preproc-strings.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ int main(void)
4545
#line 13 "strings.pgc"
4646

4747

48-
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select 'abcdef' , N'abcdef' as foo , E'abc\\bdef' as \"foo\" , U&'d\\0061t\\0061' as U&\"foo\" , U&'d!+000061t!+000061' UESCAPE '!' , $foo$abc$def$foo$", ECPGt_EOIT,
48+
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select 'abc''d\\ef' , N'abc''d\\ef' as foo , E'abc''d\\\\ef' as \"foo\"\"bar\" , U&'d\\0061t\\0061' as U&\"foo\"\"bar\" , U&'d!+000061t!+000061' UESCAPE '!' , $foo$abc$def$foo$", ECPGt_EOIT,
4949
ECPGt_char,&(s1),(long)0,(long)1,(1)*sizeof(char),
5050
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
5151
ECPGt_char,&(s2),(long)0,(long)1,(1)*sizeof(char),

src/interfaces/ecpg/test/expected/preproc-strings.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@
88
[NO_PID]: sqlca: code: 0, state: 00000
99
[NO_PID]: ecpg_process_output on line 13: OK: SET
1010
[NO_PID]: sqlca: code: 0, state: 00000
11-
[NO_PID]: ecpg_execute on line 15: query: select 'abcdef' , N'abcdef' as foo , E'abc\bdef' as "foo" , U&'d\0061t\0061' as U&"foo" , U&'d!+000061t!+000061' UESCAPE '!' , $foo$abc$def$foo$; with 0 parameter(s) on connection ecpg1_regression
11+
[NO_PID]: ecpg_execute on line 15: query: select 'abc''d\ef' , N'abc''d\ef' as foo , E'abc''d\\ef' as "foo""bar" , U&'d\0061t\0061' as U&"foo""bar" , U&'d!+000061t!+000061' UESCAPE '!' , $foo$abc$def$foo$; with 0 parameter(s) on connection ecpg1_regression
1212
[NO_PID]: sqlca: code: 0, state: 00000
1313
[NO_PID]: ecpg_execute on line 15: using PQexec
1414
[NO_PID]: sqlca: code: 0, state: 00000
1515
[NO_PID]: ecpg_process_output on line 15: correctly got 1 tuples with 6 fields
1616
[NO_PID]: sqlca: code: 0, state: 00000
1717
[NO_PID]: ecpg_store_result on line 15: allocating memory for 1 tuples
1818
[NO_PID]: sqlca: code: 0, state: 00000
19-
[NO_PID]: ecpg_get_data on line 15: RESULT: abcdef offset: -1; array: no
19+
[NO_PID]: ecpg_get_data on line 15: RESULT: abc'd\ef offset: -1; array: no
2020
[NO_PID]: sqlca: code: 0, state: 00000
2121
[NO_PID]: ecpg_store_result on line 15: allocating memory for 1 tuples
2222
[NO_PID]: sqlca: code: 0, state: 00000
23-
[NO_PID]: ecpg_get_data on line 15: RESULT: abcdef offset: -1; array: no
23+
[NO_PID]: ecpg_get_data on line 15: RESULT: abc'd\ef offset: -1; array: no
2424
[NO_PID]: sqlca: code: 0, state: 00000
2525
[NO_PID]: ecpg_store_result on line 15: allocating memory for 1 tuples
2626
[NO_PID]: sqlca: code: 0, state: 00000
27-
[NO_PID]: ecpg_get_data on line 15: RESULT: abcdef offset: -1; array: no
27+
[NO_PID]: ecpg_get_data on line 15: RESULT: abc'd\ef offset: -1; array: no
2828
[NO_PID]: sqlca: code: 0, state: 00000
2929
[NO_PID]: ecpg_store_result on line 15: allocating memory for 1 tuples
3030
[NO_PID]: sqlca: code: 0, state: 00000
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
abcdef abcdef abcdef data data abc$def
1+
abc'd\ef abc'd\ef abc'd\ef data data abc$def

src/interfaces/ecpg/test/preproc/strings.pgc

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ int main(void)
1212

1313
exec sql set standard_conforming_strings to on;
1414

15-
exec sql select 'abcdef',
16-
N'abcdef' AS foo,
17-
E'abc\bdef' AS "foo",
18-
U&'d\0061t\0061' AS U&"foo",
15+
exec sql select 'abc''d\ef',
16+
N'abc''d\ef' AS foo,
17+
E'abc''d\\ef' AS "foo""bar",
18+
U&'d\0061t\0061' AS U&"foo""bar",
1919
U&'d!+000061t!+000061' uescape '!',
2020
$foo$abc$def$foo$
2121
into :s1, :s2, :s3, :s4, :s5, :s6;

src/interfaces/ecpg/test/sql/dyntest.pgc

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ main ()
5151
exec sql create table dyntest (name char (14), d float8, i int,
5252
bignumber int8, b boolean, comment text,
5353
day date);
54-
exec sql insert into dyntest values ('first entry', 14.7, 14, 123045607890, true, 'The world''''s most advanced open source database.', '1987-07-14');
54+
exec sql insert into dyntest values ('first entry', 14.7, 14, 123045607890, true, 'The world''s most advanced open source database.', '1987-07-14');
5555
exec sql insert into dyntest values ('second entry', 1407.87, 1407, 987065403210, false, 'The elephant never forgets.', '1999-11-5');
5656

5757
exec sql prepare MYQUERY from :QUERY;

0 commit comments

Comments
 (0)