diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml index 419574e9ea..14dcbdb4e3 100644 --- a/doc/src/sgml/ecpg.sgml +++ b/doc/src/sgml/ecpg.sgml @@ -7066,7 +7066,7 @@ EXECUTE IMMEDIATE string string - A literal C string or a host variable containing the SQL + A literal string or a host variable containing the SQL statement to be executed. @@ -7074,6 +7074,30 @@ EXECUTE IMMEDIATE string + + Notes + + + In typical usage, the string is a host + variable reference to a string containing a dynamically-constructed + SQL statement. The case of a literal string is not very useful; + you might as well just write the SQL statement directly, without + the extra typing of EXECUTE IMMEDIATE. + + + + If you do use a literal string, keep in mind that any double quotes + you might wish to include in the SQL statement must be written as + octal escapes (\042) not the usual C + idiom \". This is because the string is inside + an EXEC SQL section, so the ECPG lexer parses it + according to SQL rules not C rules. Any embedded backslashes will + later be handled according to C rules; but \" + causes an immediate syntax error because it is seen as ending the + literal. + + + Examples @@ -7388,7 +7412,7 @@ EXEC SQL OPEN :curname1; -PREPARE name FROM string +PREPARE prepared_name FROM string @@ -7421,15 +7445,40 @@ PREPARE name FROM string - A literal C string or a host variable containing a preparable - statement, one of the SELECT, INSERT, UPDATE, or - DELETE. + A literal string or a host variable containing a preparable + SQL statement, one of SELECT, INSERT, UPDATE, or DELETE. + Use question marks (?) for parameter values + to be supplied at execution. + + Notes + + + In typical usage, the string is a host + variable reference to a string containing a dynamically-constructed + SQL statement. The case of a literal string is not very useful; + you might as well just write a direct SQL PREPARE + statement. + + + + If you do use a literal string, keep in mind that any double quotes + you might wish to include in the SQL statement must be written as + octal escapes (\042) not the usual C + idiom \". This is because the string is inside + an EXEC SQL section, so the ECPG lexer parses it + according to SQL rules not C rules. Any embedded backslashes will + later be handled according to C rules; but \" + causes an immediate syntax error because it is seen as ending the + literal. + + + Examples diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index e98aa6c486..91d8b63578 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -715,7 +715,14 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(state_before_str_start); if (literallen == 0) mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); - /* The backend will truncate the identifier here. We do not as it does not change the result. */ + /* + * The server will truncate the identifier here. We do + * not, as (1) it does not change the result; (2) we don't + * know what NAMEDATALEN the server might use; (3) this + * code path is also taken for literal query strings in + * PREPARE and EXECUTE IMMEDIATE, which can certainly be + * longer than NAMEDATALEN. + */ base_yylval.str = mm_strdup(literalbuf); return CSTRING; } diff --git a/src/interfaces/ecpg/test/expected/sql-execute.c b/src/interfaces/ecpg/test/expected/sql-execute.c index cac91dc599..10e9ad56b5 100644 --- a/src/interfaces/ecpg/test/expected/sql-execute.c +++ b/src/interfaces/ecpg/test/expected/sql-execute.c @@ -77,8 +77,8 @@ if (sqlca.sqlcode < 0) sqlprint();} #line 26 "execute.pgc" - sprintf(command, "insert into test (name, amount, letter) values ('db: ''r1''', 1, 'f')"); - { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_exec_immediate, command, ECPGt_EOIT, ECPGt_EORT); + /* test handling of embedded quotes in EXECUTE IMMEDIATE "literal" */ + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_exec_immediate, "insert into test (name, \042amount\042, letter) values ('db: ''r1''', 1, 'f')", ECPGt_EOIT, ECPGt_EORT); #line 29 "execute.pgc" if (sqlca.sqlcode < 0) sqlprint();} diff --git a/src/interfaces/ecpg/test/expected/sql-execute.stderr b/src/interfaces/ecpg/test/expected/sql-execute.stderr index 96b46bd158..d8bc3c6524 100644 --- a/src/interfaces/ecpg/test/expected/sql-execute.stderr +++ b/src/interfaces/ecpg/test/expected/sql-execute.stderr @@ -10,7 +10,7 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ECPGtrans on line 26: action "commit"; connection "main" [NO_PID]: sqlca: code: 0, state: 00000 -[NO_PID]: ecpg_execute on line 29: query: insert into test (name, amount, letter) values ('db: ''r1''', 1, 'f'); with 0 parameter(s) on connection main +[NO_PID]: ecpg_execute on line 29: query: insert into test (name, "amount", letter) values ('db: ''r1''', 1, 'f'); with 0 parameter(s) on connection main [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_execute on line 29: using PQexec [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/sql/execute.pgc b/src/interfaces/ecpg/test/sql/execute.pgc index cc9814e9be..43171bb77c 100644 --- a/src/interfaces/ecpg/test/sql/execute.pgc +++ b/src/interfaces/ecpg/test/sql/execute.pgc @@ -25,8 +25,8 @@ exec sql end declare section; exec sql create table test (name char(8), amount int, letter char(1)); exec sql commit; - sprintf(command, "insert into test (name, amount, letter) values ('db: ''r1''', 1, 'f')"); - exec sql execute immediate :command; + /* test handling of embedded quotes in EXECUTE IMMEDIATE "literal" */ + exec sql execute immediate "insert into test (name, \042amount\042, letter) values ('db: ''r1''', 1, 'f')"; sprintf(command, "insert into test (name, amount, letter) values ('db: ''r1''', 2, 't')"); exec sql execute immediate :command;