I have researched your report, and you are right, there are two ecpg bugs here. First, dollar quoting uses single-quotes internally to do the quoting, but it does not double any single-quotes in the dollar-quoted string.
Second, when a dollar quoted string or single-quoted string spans multiple lines, ecpg does not escape the newline that is part of the string. Some compilers will accept an unescaped newline in a string, while others will not: $ gcc -pedantic -c -g -Wall tst1.c tst1.c:5: warning: string constant runs past end of line It isn't standard so I think we need to replace newline in a string with "\n\". Attached is a patch which fixes both of these issues. This changes ecpg behavior so I am thinking this patch would only appear in 8.2. I am unclear if I fixed the \r case properly. --------------------------------------------------------------------------- [EMAIL PROTECTED] wrote: > > The following bug has been logged online: > > Bug reference: 2171 > Logged by: > Email address: [EMAIL PROTECTED] > PostgreSQL version: 8.1.2 > Operating system: Linux (Debian) > Description: Differences compiling plpgsql in ecpg and psql > Details: > > There appear to be parsing problems with ecpg. The following example > program shows code snippets that allow for the successful creation of a > function (CREATE FUNCTION) only using two different syntaxes: one when > entered through psql, and another when compiling with ecpg. > > The expectation (and hints from the documentation) indicate that the exact > same method of defining a function should succeed in both cases, but such is > not the case. > > Different quoting and line-wrap behavior is observed between psql and ecpg. > > (Thanks for the attention, I hope this is useful!) > > BEGIN CODE--------------- > /* This file is bug.pgc. */ > /* Compile as shown: > ecpg bug.pgc -o bug.c > gcc -c -g -std=c99 -I/usr/local/pgsql/include -L/usr/local/pgsql/lib > bug.c -o bug.o > gcc -I/usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg bug.o -o bug > */ > /* Run as: ./bug */ > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > > int main(int argc, char* argv[]) { > > EXEC SQL CONNECT TO DEFAULT; > > EXEC SQL SET AUTOCOMMIT TO ON; > EXEC SQL WHENEVER SQLWARNING SQLPRINT; > EXEC SQL WHENEVER SQLERROR SQLPRINT; > > EXEC SQL CREATE TABLE My_Table ( Item1 int, Item2 text ); > > /* Documentation appears to indicate that only single quotes (') are > needed, but this will not ecpg-compile without double-single ('') > quotes. When entered through psql, only the single quotes (') > are needed. */ > /* doc/html/sql-syntax.html#SQL-SYNTAX-DOLLAR-QUOTING: "It is > particularly useful when representing string constants inside > other constants, as is often needed in procedural function > definitions." */ > /* doc/html/sql-createfunction.html: "Without dollar quoting, any > single quotes or backslashes in the function definition must be > escaped by doubling them." */ > > /* Documentation appears to indicate that the body of the funtion > can be extended across multiple lines in the input file (this > file) but it will not compile (ecpg) without keeping the function > body on one line. Multiple line input works through psql, but > not here.*/ > //bad ecpg,good psql: EXEC SQL CREATE FUNCTION My_Table_Check() RETURNS > trigger > //bad ecpg,good psql: AS $My_Table_Check$ > //bad ecpg,good psql: BEGIN RAISE NOTICE 'TG_NAME=%, TG WHEN=%', TG_NAME, > TG_WHEN; > //bad ecpg,good psql: RETURN NEW; > //bad ecpg,good psql: END; > //bad ecpg,good psql: $My_Table_Check$ > //bad ecpg,good psql: LANGUAGE 'plpgsql'; > EXEC SQL CREATE FUNCTION My_Table_Check() RETURNS trigger > AS $My_Table_Check$ BEGIN RAISE NOTICE ''TG_NAME=%, TG WHEN=%'', > TG_NAME, TG_WHEN; RETURN NEW; END; $My_Table_Check$ > LANGUAGE 'plpgsql'; > > EXEC SQL CREATE TRIGGER My_Table_Check_Trigger > BEFORE INSERT > ON My_Table > FOR EACH ROW > EXECUTE PROCEDURE My_Table_Check(); > > EXEC SQL INSERT INTO My_Table VALUES (1234, 'Some random text'); > EXEC SQL INSERT INTO My_Table VALUES (5678, 'The Quick Brown'); > > EXEC SQL DROP TRIGGER My_Table_Check_Trigger ON My_Table; > EXEC SQL DROP FUNCTION My_Table_Check(); > EXEC SQL DROP TABLE My_Table; > > EXEC SQL DISCONNECT ALL; > > return 0; > } > > END CODE------------------ > > ---------------------------(end of broadcast)--------------------------- > TIP 9: In versions below 8.0, the planner will ignore your desire to > choose an index scan if your joining column's datatypes do not > match > -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Index: src/interfaces/ecpg/preproc/pgc.l =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v retrieving revision 1.140 diff -c -c -r1.140 pgc.l *** src/interfaces/ecpg/preproc/pgc.l 2 Feb 2006 03:51:41 -0000 1.140 --- src/interfaces/ecpg/preproc/pgc.l 2 Feb 2006 04:38:28 -0000 *************** *** 134,140 **** */ xqstart {quote} xqdouble {quote}{quote} ! xqinside [^\\']+ xqescape [\\][^0-7] xqoctesc [\\][0-7]{1,3} xqhexesc [\\]x[0-9A-Fa-f]{1,2} --- 134,140 ---- */ xqstart {quote} xqdouble {quote}{quote} ! xqinside [^\\'{newline}] xqescape [\\][^0-7] xqoctesc [\\][0-7]{1,3} xqhexesc [\\]x[0-9A-Fa-f]{1,2} *************** *** 152,158 **** dolq_cont [A-Za-z\200-\377_0-9] dolqdelim \$({dolq_start}{dolq_cont}*)?\$ dolqfailed \${dolq_start}{dolq_cont}* ! dolqinside [^$]+ /* Double quote * Allows embedded spaces and other special characters into identifiers. --- 152,158 ---- dolq_cont [A-Za-z\200-\377_0-9] dolqdelim \$({dolq_start}{dolq_cont}*)?\$ dolqfailed \${dolq_start}{dolq_cont}* ! dolqinside [^$'{newline}] /* Double quote * Allows embedded spaces and other special characters into identifiers. *************** *** 161,167 **** xdstart {dquote} xdstop {dquote} xddouble {dquote}{dquote} ! xdinside [^"]+ /* special stuff for C strings */ xdcqq \\\\ --- 161,167 ---- xdstart {dquote} xdstop {dquote} xddouble {dquote}{dquote} ! xdinside [^"] /* special stuff for C strings */ xdcqq \\\\ *************** *** 423,429 **** return SCONST; } <xq>{xqdouble} { addlitchar('\''); } ! <xq>{xqinside} { addlit(yytext, yyleng); } <xq>{xqescape} { check_escape_warning(); addlit(yytext, yyleng); --- 423,433 ---- return SCONST; } <xq>{xqdouble} { addlitchar('\''); } ! <xq>{xqinside} { ! if (yytext[0] == '\r' || yytext[0] == '\n') ! addlitchar('\\'); /* C string continuation */ ! addlitchar(yytext[0]); ! } <xq>{xqescape} { check_escape_warning(); addlit(yytext, yyleng); *************** *** 473,482 **** yyless(yyleng-1); } } ! <xdolq>{dolqinside} { addlit(yytext, yyleng); } <xdolq>{dolqfailed} { addlit(yytext, yyleng); } <xdolq>. { ! /* This is only needed for $ inside the quoted text */ addlitchar(yytext[0]); } <xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); } --- 477,493 ---- yyless(yyleng-1); } } ! <xdolq>{dolqinside} { ! if (yytext[0] == '\r' || yytext[0] == '\n') ! addlitchar('\\'); /* C string continuation */ ! addlitchar(yytext[0]); ! } <xdolq>{dolqfailed} { addlit(yytext, yyleng); } <xdolq>. { ! /* $$ is implemented as a single-quoted string, so double it? */ ! if (yytext[0] == '\'') ! addlitchar(yytext[0]); ! /* single quote or dollar sign */ addlitchar(yytext[0]); } <xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); }
---------------------------(end of broadcast)--------------------------- TIP 9: In versions below 8.0, the planner will ignore your desire to choose an index scan if your joining column's datatypes do not match