Tom Lane wrote:



I think plpgsql's lexer also needs to be taught about dollar-quoting.





The attached patch appears to do the trick:



floobl=# create or replace function testme() returns text language plpgsql as $$
floobl$# begin return $foo$a'\b$bar$foo$; end;
floobl$# $$;
CREATE FUNCTION
floobl=# select testme();
testme ----------
a'\b$bar
(1 row)


floobl=#



cheers

andrew
Index: src/pl/plpgsql/src/scan.l
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/pl/plpgsql/src/scan.l,v
retrieving revision 1.31
diff -c -r1.31 scan.l
*** src/pl/plpgsql/src/scan.l   24 Feb 2004 22:06:32 -0000      1.31
--- src/pl/plpgsql/src/scan.l   25 Feb 2004 16:32:28 -0000
***************
*** 57,62 ****
--- 57,63 ----
  static bool have_lookahead_token;
  static const char *cur_line_start;
  static int    cur_line_num;
+ static char    *dolqstart;      /* current $foo$ quote start string */
  
  int   plpgsql_SpaceScanned = 0;
  %}
***************
*** 70,76 ****
  %option case-insensitive
  
  
! %x    IN_STRING IN_COMMENT
  
  digit                 [0-9]
  ident_start           [A-Za-z\200-\377_]
--- 71,77 ----
  %option case-insensitive
  
  
! %x    IN_STRING IN_COMMENT IN_DOLLARQUOTE
  
  digit                 [0-9]
  ident_start           [A-Za-z\200-\377_]
***************
*** 84,89 ****
--- 85,98 ----
  
  space                 [ \t\n\r\f]
  
+ /* $foo$ style quotes ("dollar quoting")
+  * copied stright from the backend SQL parser
+  */
+ dolq_start            [A-Za-z\200-\377_]
+ dolq_cont             [A-Za-z\200-\377_0-9]
+ dolqdelim             \$({dolq_start}{dolq_cont}*)?\$
+ dolqinside            [^$]+
+ 
  %%
      /* ----------
       * Local variables in scanner to remember where
***************
*** 288,293 ****
--- 297,336 ----
                                                (errcode(ERRCODE_DATATYPE_MISMATCH),
                                                 errmsg("unterminated string")));
                        }
+ 
+ {dolqdelim}           {
+                         start_lineno = plpgsql_scanner_lineno();
+                         start_charpos = yytext;
+                         dolqstart = pstrdup(yytext);
+                         BEGIN(IN_DOLLARQUOTE);
+                               }
+ <IN_DOLLARQUOTE>{dolqdelim} {
+                                       if (strcmp(yytext, dolqstart) == 0)
+                                       {
+                                               pfree(dolqstart);
+                                               yyleng -= (yytext - start_charpos);
+                                               yytext = start_charpos;
+                                               BEGIN INITIAL;
+                                               return T_STRING;
+                                       }
+                                       else
+                                       {
+                                               /*
+                                                * When we fail to match $...$ to 
dolqstart, transfer
+                                                * the $... part to the output, but 
put back the final
+                                                * $ for rescanning.  Consider 
$delim$...$junk$delim$
+                                                */
+                                               yyless(yyleng-1);
+                                       }
+                               }
+ <IN_DOLLARQUOTE>{dolqinside} { }
+ <IN_DOLLARQUOTE>.     { /* needed for $ inside the quoted text */ }
+ <IN_DOLLARQUOTE><<EOF>>       { 
+                               plpgsql_error_lineno = start_lineno;
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                                errmsg("unterminated dollar quoted 
string")));
+                   }
  
      /* ----------
       * Any unmatched character is returned as is

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])

Reply via email to