errors when there is a bit literal in ecpg
Hi, hacker
I met an error as below when I use ecpg
a.pgc:5: ERROR: invalid bit string literal
a.pgc:5: ERROR: internal error: unreachable state; please report this to <pgsql-bugs@lists.postgresql.org>
the test source is attached.
After investigating the code, I think the process of pgc.l is:
Step 1: <SQL>{xbstart}, addlitchar('b') is called, literalbuf contains a char 'b';
Step 2: <xb>{xbinside}, the rest of char is added in literalbuf
Step 3: <xqs>{other}, the condition literalbuf[strspn(literalbuf, "01") + 1] != '\0' will always be true;
error is occurred here
I try to fix this bug by deleting 'addlitchar('b');' from source I also add a test case to test all const str in ecpg.
The patch is also attached.
Best regards, Shenhao Wang
Attachments:
0001-Fix-error-when-handle-bit-string.patchapplication/octet-stream; name=0001-Fix-error-when-handle-bit-string.patchDownload
From 8736ca4925b83433fc723333b7a11f98e306e4cc Mon Sep 17 00:00:00 2001
From: Shenhao Wang <wangsh.fnst@cn.fujitsu.com>
Date: Fri, 6 Nov 2020 11:08:35 +0800
Subject: [PATCH] Fix error when handle bit string
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/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index 1e67d2b162..68016e32de 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -34,6 +34,7 @@ test: sql/array
test: sql/binary
test: sql/bytea
test: sql/code100
+test: sql/const
test: sql/copystdout
test: sql/createtableas
test: sql/define
diff --git a/src/interfaces/ecpg/test/expected/sql-const.c b/src/interfaces/ecpg/test/expected/sql-const.c
new file mode 100644
index 0000000000..d2591d3d52
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/sql-const.c
@@ -0,0 +1,193 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "const.pgc"
+#include <stdio.h>
+
+/* exec sql whenever sqlerror sqlprint ; */
+#line 3 "const.pgc"
+
+
+
+#line 1 "sqlca.h"
+#ifndef POSTGRES_SQLCA_H
+#define POSTGRES_SQLCA_H
+
+#ifndef PGDLLIMPORT
+#if defined(WIN32) || defined(__CYGWIN__)
+#define PGDLLIMPORT __declspec (dllimport)
+#else
+#define PGDLLIMPORT
+#endif /* __CYGWIN__ */
+#endif /* PGDLLIMPORT */
+
+#define SQLERRMC_LEN 150
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct sqlca_t
+{
+ char sqlcaid[8];
+ long sqlabc;
+ long sqlcode;
+ struct
+ {
+ int sqlerrml;
+ char sqlerrmc[SQLERRMC_LEN];
+ } sqlerrm;
+ char sqlerrp[8];
+ long sqlerrd[6];
+ /* Element 0: empty */
+ /* 1: OID of processed tuple if applicable */
+ /* 2: number of rows processed */
+ /* after an INSERT, UPDATE or */
+ /* DELETE statement */
+ /* 3: empty */
+ /* 4: empty */
+ /* 5: empty */
+ char sqlwarn[8];
+ /* Element 0: set to 'W' if at least one other is 'W' */
+ /* 1: if 'W' at least one character string */
+ /* value was truncated when it was */
+ /* stored into a host variable. */
+
+ /*
+ * 2: if 'W' a (hopefully) non-fatal notice occurred
+ */ /* 3: empty */
+ /* 4: empty */
+ /* 5: empty */
+ /* 6: empty */
+ /* 7: empty */
+
+ char sqlstate[5];
+};
+
+struct sqlca_t *ECPGget_sqlca(void);
+
+#ifndef POSTGRES_ECPG_INTERNAL
+#define sqlca (*ECPGget_sqlca())
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#line 5 "const.pgc"
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 6 "const.pgc"
+
+
+int
+main (void)
+{
+/* exec sql begin declare section */
+
+
+
+#line 12 "const.pgc"
+ int b , hb ;
+
+#line 13 "const.pgc"
+ char s [ 100 ] , es [ 100 ] , ns [ 100 ] , us [ 100 ] ;
+/* exec sql end declare section */
+#line 14 "const.pgc"
+
+
+ ECPGdebug(1, stderr);
+
+ { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0);
+#line 18 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 18 "const.pgc"
+
+
+ { ECPGtrans(__LINE__, NULL, "begin work");
+#line 20 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 20 "const.pgc"
+
+
+ { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test ( b bit ( 4 ) , hb bit ( 12 ) , s text , es text , ns text , us text )", ECPGt_EOIT, ECPGt_EORT);
+#line 22 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 22 "const.pgc"
+
+
+ { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test values ( b'1010' , x'9aE' , 'test' , E'test\\\\ab' , N'test' , U&'\\0047bc' )", ECPGt_EOIT, ECPGt_EORT);
+#line 25 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 25 "const.pgc"
+
+
+ { ECPGtrans(__LINE__, NULL, "commit");
+#line 27 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 27 "const.pgc"
+
+
+ { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select b :: int , hb :: int , s , es , ns , us from test limit 1", ECPGt_EOIT,
+ ECPGt_int,&(b),(long)1,(long)1,sizeof(int),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
+ ECPGt_int,&(hb),(long)1,(long)1,sizeof(int),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
+ ECPGt_char,(s),(long)100,(long)1,(100)*sizeof(char),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
+ ECPGt_char,(es),(long)100,(long)1,(100)*sizeof(char),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
+ ECPGt_char,(ns),(long)100,(long)1,(100)*sizeof(char),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
+ ECPGt_char,(us),(long)100,(long)1,(100)*sizeof(char),
+ ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 30 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 30 "const.pgc"
+
+
+ printf("b=%d, hb=%d, s=%s, es=%s, ns=%s, us=%s\n",
+ b, hb, s, es, ns, us);
+
+ { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test", ECPGt_EOIT, ECPGt_EORT);
+#line 35 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 35 "const.pgc"
+
+ { ECPGtrans(__LINE__, NULL, "commit");
+#line 36 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 36 "const.pgc"
+
+ { ECPGdisconnect(__LINE__, "CURRENT");
+#line 37 "const.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 37 "const.pgc"
+
+
+ return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/sql-const.stderr b/src/interfaces/ecpg/test/expected/sql-const.stderr
new file mode 100644
index 0000000000..8b85c7dfb7
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/sql-const.stderr
@@ -0,0 +1,48 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 20: action "begin work"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 22: query: create table test ( b bit ( 4 ) , hb bit ( 12 ) , s text , es text , ns text , us text ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 22: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 22: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 24: query: insert into test values ( b'1010' , x'9aE' , 'test' , E'test\\ab' , N'test' , U&'\0047bc' ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 24: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 24: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 27: action "commit"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 29: query: select b :: int , hb :: int , s , es , ns , us from test limit 1; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 29: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 29: correctly got 1 tuples with 6 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 29: RESULT: 10 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 29: RESULT: 2478 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 29: RESULT: test offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 29: RESULT: test\ab offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 29: RESULT: test offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 29: RESULT: Gbc offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 35: query: drop table test; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 35: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 35: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 36: action "commit"; connection "ecpg1_regression"
+[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/sql-const.stdout b/src/interfaces/ecpg/test/expected/sql-const.stdout
new file mode 100644
index 0000000000..85d542ded7
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/sql-const.stdout
@@ -0,0 +1 @@
+b=10, hb=2478, s=test, es=test\ab, ns=test, us=Gbc
diff --git a/src/interfaces/ecpg/test/sql/.gitignore b/src/interfaces/ecpg/test/sql/.gitignore
index 613bdebc96..9715b27a8b 100644
--- a/src/interfaces/ecpg/test/sql/.gitignore
+++ b/src/interfaces/ecpg/test/sql/.gitignore
@@ -6,6 +6,8 @@
/bytea.c
/code100
/code100.c
+/const
+/const.c
/copystdout
/copystdout.c
/createtableas
diff --git a/src/interfaces/ecpg/test/sql/Makefile b/src/interfaces/ecpg/test/sql/Makefile
index 170bcd72c4..0e6cfdd164 100644
--- a/src/interfaces/ecpg/test/sql/Makefile
+++ b/src/interfaces/ecpg/test/sql/Makefile
@@ -6,7 +6,8 @@ include $(top_srcdir)/$(subdir)/../Makefile.regress
TESTS = array array.c \
binary binary.c \
code100 code100.c \
- copystdout copystdout.c \
+ const const.c \
+ copystdout copystdout.c \
createtableas createtableas.c \
define define.c \
desc desc.c \
diff --git a/src/interfaces/ecpg/test/sql/const.pgc b/src/interfaces/ecpg/test/sql/const.pgc
new file mode 100644
index 0000000000..c16ee11dc4
--- /dev/null
+++ b/src/interfaces/ecpg/test/sql/const.pgc
@@ -0,0 +1,40 @@
+#include <stdio.h>
+
+exec sql whenever sqlerror sqlprint;
+
+exec sql include sqlca;
+exec sql include ../regression;
+
+int
+main (void)
+{
+EXEC SQL BEGIN DECLARE SECTION;
+ int b,hb;
+ char s[100],es[100],ns[100],us[100];
+EXEC SQL END DECLARE SECTION;
+
+ ECPGdebug(1, stderr);
+
+ EXEC SQL CONNECT TO REGRESSDB1;
+
+ EXEC SQL BEGIN WORK;
+
+ EXEC SQL CREATE TABLE test(b bit(4), hb bit(12), s text, es text, ns text, us text);
+
+ EXEC SQL INSERT INTO test VALUES(b'1010', x'9aE', 'test', e'test\\ab',
+ n'test', u&'\0047bc');
+
+ EXEC SQL COMMIT;
+
+ EXEC SQL SELECT b::int, hb::int, s, es, ns, us INTO
+ :b, :hb, :s, :es, :ns, :us FROM test LIMIT 1;
+
+ printf("b=%d, hb=%d, s=%s, es=%s, ns=%s, us=%s\n",
+ b, hb, s, es, ns, us);
+
+ EXEC SQL DROP TABLE test;
+ EXEC SQL COMMIT;
+ EXEC SQL DISCONNECT;
+
+ return 0;
+}
--
2.26.2
"Wang, Shenhao" <wangsh.fnst@cn.fujitsu.com> writes:
I met an error as below when I use ecpg
a.pgc:5: ERROR: invalid bit string literal
a.pgc:5: ERROR: internal error: unreachable state; please report this to <pgsql-bugs@lists.postgresql.org>
Indeed. This has apparently been broken for a very long time (though
the "unreachable state" part is fairly new).
I try to fix this bug by deleting 'addlitchar('b');' from source I also add a test case to test all const str in ecpg.
I thought that a whole new test case was overkill when we could just add a
couple of lines to an existing test. Other than that, looks good, pushed.
regards, tom lane