summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2020-11-07 20:03:44 +0000
committerTom Lane2020-11-07 20:03:44 +0000
commit1e3868ab3bef5cfa0f4d44a6937a880be7a3a482 (patch)
treea3066180fe01cf5e800c7323a44ce36acdf0b720
parentbdc4edbea6fc847f806e1e7118d730e159512bfc (diff)
Fix ecpg's mishandling of B'...' and X'...' literals.
These were broken in multiple ways: * The xbstart and xhstart lexer actions neglected to set "state_before_str_start" before transitioning to the xb/xh states, thus possibly resulting in "internal error: unreachable state" later. * The test for valid string contents at the end of xb state was flat out wrong, as it accounted incorrectly for the "b" prefix that the xbstart action had injected. Meanwhile, the xh state had no such check at all. * The generated literal value failed to include any quote marks. * The grammar did the wrong thing anyway, typically ignoring the literal value and emitting something else, since BCONST and XCONST tokens were handled randomly differently from SCONST tokens. The first of these problems is evidently an oversight in commit 7f380c59f, but the others seem to be very ancient. The lack of complaints shows that ECPG users aren't using these syntaxes much (although I do vaguely remember one previous complaint). As written, this patch is dependent on 7f380c59f, so it can't go back further than v13. Given the shortage of complaints, I'm not excited about adapting the patch to prior branches. Report and patch by Shenhao Wang (test case adjusted by me) Discussion: https://postgr.es/m/d6402f1bacb74ecba22ef715dbba17fd@G08CNEXMBPEKD06.g08.fujitsu.local
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.trailer4
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.type2
-rw-r--r--src/interfaces/ecpg/preproc/parse.pl1
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l12
-rw-r--r--src/interfaces/ecpg/test/expected/preproc-strings.c12
-rw-r--r--src/interfaces/ecpg/test/expected/preproc-strings.stderr10
-rw-r--r--src/interfaces/ecpg/test/expected/preproc-strings.stdout1
-rw-r--r--src/interfaces/ecpg/test/preproc/strings.pgc5
8 files changed, 39 insertions, 8 deletions
diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
index 6ccc8ab916..14ad27c359 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -1715,13 +1715,13 @@ cvariable: CVARIABLE
ecpg_param: PARAM { $$ = make_name(); } ;
-ecpg_bconst: BCONST { $$ = make_name(); } ;
+ecpg_bconst: BCONST { $$ = $1; } ;
ecpg_fconst: FCONST { $$ = make_name(); } ;
ecpg_sconst: SCONST { $$ = $1; } ;
-ecpg_xconst: XCONST { $$ = make_name(); } ;
+ecpg_xconst: XCONST { $$ = $1; } ;
ecpg_ident: IDENT { $$ = $1; }
| CSTRING { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); }
diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type
index ffafa82af9..eca298bdb8 100644
--- a/src/interfaces/ecpg/preproc/ecpg.type
+++ b/src/interfaces/ecpg/preproc/ecpg.type
@@ -122,7 +122,9 @@
%type <str> CSTRING
%type <str> CPP_LINE
%type <str> CVARIABLE
+%type <str> BCONST
%type <str> SCONST
+%type <str> XCONST
%type <str> IDENT
%type <struct_union> s_struct_union_symbol
diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl
index 1a76b2d326..52ba7dfa0c 100644
--- a/src/interfaces/ecpg/preproc/parse.pl
+++ b/src/interfaces/ecpg/preproc/parse.pl
@@ -38,6 +38,7 @@ my %replace_token = (
'BCONST' => 'ecpg_bconst',
'FCONST' => 'ecpg_fconst',
'Sconst' => 'ecpg_sconst',
+ 'XCONST' => 'ecpg_xconst',
'IDENT' => 'ecpg_ident',
'PARAM' => 'ecpg_param',);
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 91d8b63578..1aebac89cd 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -505,9 +505,9 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
<SQL>{
{xbstart} {
token_start = yytext;
+ state_before_str_start = YYSTATE;
BEGIN(xb);
startlit();
- addlitchar('b');
}
} /* <SQL> */
@@ -519,9 +519,9 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
<SQL>{xhstart} {
token_start = yytext;
+ state_before_str_start = YYSTATE;
BEGIN(xh);
startlit();
- addlitchar('x');
}
<xh><<EOF>> { mmfatal(PARSE_ERROR, "unterminated hexadecimal string literal"); }
@@ -597,12 +597,14 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
switch (state_before_str_stop)
{
case xb:
- if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
+ if (literalbuf[strspn(literalbuf, "01")] != '\0')
mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string literal");
- base_yylval.str = mm_strdup(literalbuf);
+ base_yylval.str = psprintf("b'%s'", literalbuf);
return BCONST;
case xh:
- base_yylval.str = mm_strdup(literalbuf);
+ if (literalbuf[strspn(literalbuf, "0123456789abcdefABCDEF")] != '\0')
+ mmerror(PARSE_ERROR, ET_ERROR, "invalid hex string literal");
+ base_yylval.str = psprintf("x'%s'", literalbuf);
return XCONST;
case xq:
/* fallthrough */
diff --git a/src/interfaces/ecpg/test/expected/preproc-strings.c b/src/interfaces/ecpg/test/expected/preproc-strings.c
index 1e50cd36c3..87662e0176 100644
--- a/src/interfaces/ecpg/test/expected/preproc-strings.c
+++ b/src/interfaces/ecpg/test/expected/preproc-strings.c
@@ -63,8 +63,18 @@ int main(void)
printf("%s %s %s %s %s %s\n", s1, s2, s3, s4, s5, s6);
+ { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select b'0010' , x'019ABcd'", ECPGt_EOIT,
+ ECPGt_char,&(s1),(long)0,(long)1,(1)*sizeof(char),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
+ ECPGt_char,&(s2),(long)0,(long)1,(1)*sizeof(char),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 26 "strings.pgc"
+
+
+ printf("%s %s\n", s1, s2);
+
{ ECPGdisconnect(__LINE__, "CURRENT");}
-#line 25 "strings.pgc"
+#line 30 "strings.pgc"
return 0;
}
diff --git a/src/interfaces/ecpg/test/expected/preproc-strings.stderr b/src/interfaces/ecpg/test/expected/preproc-strings.stderr
index 4c3a8eee5a..9f10ca0bf3 100644
--- a/src/interfaces/ecpg/test/expected/preproc-strings.stderr
+++ b/src/interfaces/ecpg/test/expected/preproc-strings.stderr
@@ -38,5 +38,15 @@
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_get_data on line 15: RESULT: abc$def offset: -1; array: no
[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: query: select b'0010' , x'019ABcd'; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 25: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 25: RESULT: 0010 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 25: RESULT: 0000000110011010101111001101 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_finish: connection ecpg1_regression closed
[NO_PID]: sqlca: code: 0, state: 00000
diff --git a/src/interfaces/ecpg/test/expected/preproc-strings.stdout b/src/interfaces/ecpg/test/expected/preproc-strings.stdout
index 1456b152d7..5abbe6928d 100644
--- a/src/interfaces/ecpg/test/expected/preproc-strings.stdout
+++ b/src/interfaces/ecpg/test/expected/preproc-strings.stdout
@@ -1 +1,2 @@
abc'd\ef abc'd\ef abc'd\ef data data abc$def
+0010 0000000110011010101111001101
diff --git a/src/interfaces/ecpg/test/preproc/strings.pgc b/src/interfaces/ecpg/test/preproc/strings.pgc
index 25157f136c..ab7eef6896 100644
--- a/src/interfaces/ecpg/test/preproc/strings.pgc
+++ b/src/interfaces/ecpg/test/preproc/strings.pgc
@@ -22,6 +22,11 @@ int main(void)
printf("%s %s %s %s %s %s\n", s1, s2, s3, s4, s5, s6);
+ exec sql select b'0010', X'019ABcd'
+ into :s1, :s2;
+
+ printf("%s %s\n", s1, s2);
+
exec sql disconnect;
return 0;
}