Index: doc/TODO
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/TODO,v
retrieving revision 1.1696
diff -c -r1.1696 TODO
*** doc/TODO	27 Oct 2005 14:16:02 -0000	1.1696
--- doc/TODO	13 Feb 2006 18:22:38 -0000
***************
*** 391,397 ****
  * Allow EXPLAIN to identify tables that were skipped because of 
    constraint_exclusion
  * Allow EXPLAIN output to be more easily processed by scripts
- * Eventually enable escape_string_warning and standard_conforming_strings
  * Simplify dropping roles that have objects in several databases
  
  
--- 391,396 ----
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.36.2.2
diff -c -r1.36.2.2 config.sgml
*** doc/src/sgml/config.sgml	12 Feb 2006 19:19:37 -0000	1.36.2.2
--- doc/src/sgml/config.sgml	13 Feb 2006 18:22:38 -0000
***************
*** 3728,3737 ****
         </para>
         <para>
          Escape string syntax (<literal>E'...'</>) should be used for
!         escapes, because in future versions of
!         <productname>PostgreSQL</productname> ordinary strings will have
          the standard-conforming behavior of treating backslashes
!         literally.
         </para>
        </listitem>
       </varlistentry>
--- 3728,3755 ----
         </para>
         <para>
          Escape string syntax (<literal>E'...'</>) should be used for
!         backslash escape sequences, because ordinary strings have
          the standard-conforming behavior of treating backslashes
!         literally when the <literal>standard-conforming-strings</>
!         option is set <literal>on</>.
!        </para>
!       </listitem>
!      </varlistentry>
! 
!      <varlistentry id="guc-standard-conforming-strings" xreflabel="standard_conforming_strings">
!       <term><varname>standard_conforming_strings</varname> (<type>boolean</type>)</term>
!       <indexterm><primary>strings</><secondary>escape</></>
!       <indexterm>
!        <primary><varname>standard_conforming_strings</> configuration parameter</primary>
!       </indexterm>
!       <listitem>
!        <para>
!         Controls whether ordinary string literals
!         (<literal>'...'</>) treat backslashes literally, as specified in
!         the SQL standard.  Applications may check this
!         parameter to determine how string literals will be processed.
!         The presence of this parameter can also be taken as an indication
!         that the escape string syntax (<literal>E'...'</>) is supported.
         </para>
        </listitem>
       </varlistentry>
***************
*** 3944,3971 ****
        </listitem>
       </varlistentry>
  
-      <varlistentry id="guc-standard-conforming-strings" xreflabel="standard_conforming_strings">
-       <term><varname>standard_conforming_strings</varname> (<type>boolean</type>)</term>
-       <indexterm><primary>strings</><secondary>escape</></>
-       <indexterm>
-        <primary><varname>standard_conforming_strings</> configuration parameter</primary>
-       </indexterm>
-       <listitem>
-        <para>
-         Reports whether ordinary string literals
-         (<literal>'...'</>) treat backslashes literally, as specified in
-         the SQL standard.  The value is currently always <literal>off</>,
-         indicating that backslashes are treated as escapes.  It is planned
-         that this will change to <literal>on</> in a future
-         <productname>PostgreSQL</productname> release when string literal
-         syntax changes to meet the standard.  Applications may check this
-         parameter to determine how string literals will be processed.
-         The presence of this parameter can also be taken as an indication
-         that the escape string syntax (<literal>E'...'</>) is supported.
-        </para>
-       </listitem>
-      </varlistentry>
- 
      </variablelist>
     </sect1>
  
--- 3962,3967 ----
Index: src/backend/parser/scan.l
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/scan.l,v
retrieving revision 1.128
diff -c -r1.128 scan.l
*** src/backend/parser/scan.l	16 Aug 2005 00:48:12 -0000	1.128
--- src/backend/parser/scan.l	13 Feb 2006 18:22:38 -0000
***************
*** 51,63 ****
  static char    *dolqstart;      /* current $foo$ quote start string */
  
  /*
!  * GUC variable.  This is a DIRECT violation of the warning given at the
   * head of gram.y, ie flex/bison code must not depend on any GUC variables;
   * as such, changing its value can induce very unintuitive behavior.
   * But we shall have to live with it as a short-term thing until the switch
   * to SQL-standard string syntax is complete.
   */
  bool			escape_string_warning;
  
  static bool		warn_on_first_escape;
  
--- 51,64 ----
  static char    *dolqstart;      /* current $foo$ quote start string */
  
  /*
!  * GUC variables.  This is a DIRECT violation of the warning given at the
   * head of gram.y, ie flex/bison code must not depend on any GUC variables;
   * as such, changing its value can induce very unintuitive behavior.
   * But we shall have to live with it as a short-term thing until the switch
   * to SQL-standard string syntax is complete.
   */
  bool			escape_string_warning;
+ bool			standard_conforming_strings;
  
  static bool		warn_on_first_escape;
  
***************
*** 77,82 ****
--- 78,84 ----
  static char *litbufdup(void);
  static int	pg_err_position(void);
  static void check_escape_warning(void);
+ static void check_string_escape_warning(unsigned char ychar);
  
  /*
   * When we parse a token that requires multiple lexer rules to process,
***************
*** 119,125 ****
   *  <xc> extended C-style comments
   *  <xd> delimited identifiers (double-quoted identifiers)
   *  <xh> hexadecimal numeric string
!  *  <xq> quoted strings
   *  <xdolq> $foo$ quoted strings
   */
  
--- 121,128 ----
   *  <xc> extended C-style comments
   *  <xd> delimited identifiers (double-quoted identifiers)
   *  <xh> hexadecimal numeric string
!  *  <xq> standard quoted strings
!  *  <xe> extended quoted strings (support backslash escape sequences)
   *  <xdolq> $foo$ quoted strings
   */
  
***************
*** 127,132 ****
--- 130,136 ----
  %x xc
  %x xd
  %x xh
+ %x xe
  %x xq
  %x xdolq
  
***************
*** 200,205 ****
--- 204,213 ----
  
  /* Quoted string that allows backslash escapes */
  xestart			[eE]{quote}
+ xeinside		[^\\']+
+ xeescape		[\\][^0-7]
+ xeoctesc		[\\][0-7]{1,3}
+ xehexesc		[\\]x[0-9A-Fa-f]{1,2}
  
  /* Extended quote
   * xqdouble implements embedded quote, ''''
***************
*** 207,215 ****
  xqstart			{quote}
  xqdouble		{quote}{quote}
  xqinside		[^\\']+
! xqescape		[\\][^0-7]
! xqoctesc		[\\][0-7]{1,3}
! xqhexesc		[\\]x[0-9A-Fa-f]{1,2}
  
  /* $foo$ style quotes ("dollar quoting")
   * The quoted string starts with $foo$ where "foo" is an optional string
--- 215,221 ----
  xqstart			{quote}
  xqdouble		{quote}{quote}
  xqinside		[^\\']+
! xqbackslash	[\\]
  
  /* $foo$ style quotes ("dollar quoting")
   * The quoted string starts with $foo$ where "foo" is an optional string
***************
*** 428,500 ****
  {xqstart}		{
  					warn_on_first_escape = true;
  					token_start = yytext;
! 					BEGIN(xq);
  					startlit();
  				}
  {xestart}		{
  					warn_on_first_escape = false;
  					token_start = yytext;
! 					BEGIN(xq);
  					startlit();
  				}
! <xq>{quotestop}	|
! <xq>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval.str = litbufdup();
  					return SCONST;
  				}
! <xq>{xqdouble}  {
  					addlitchar('\'');
  				}
  <xq>{xqinside}  {
  					addlit(yytext, yyleng);
  				}
! <xq>{xqescape}  {
! 					if (yytext[1] == '\'')
! 					{
! 						if (warn_on_first_escape && escape_string_warning)
! 							ereport(WARNING,
! 									(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
! 									 errmsg("nonstandard use of \\' in a string literal"),
! 									 errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."),
! 									 errposition(pg_err_position())));
! 						warn_on_first_escape = false;	/* warn only once per string */
! 					}
! 					else if (yytext[1] == '\\')
! 					{
! 						if (warn_on_first_escape && escape_string_warning)
! 							ereport(WARNING,
! 									(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
! 									 errmsg("nonstandard use of \\\\ in a string literal"),
! 									 errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."),
! 									 errposition(pg_err_position())));
! 						warn_on_first_escape = false;	/* warn only once per string */
! 					}
! 					else
! 						check_escape_warning();
  					addlitchar(unescape_single_char(yytext[1]));
  				}
! <xq>{xqoctesc}  {
  					unsigned char c = strtoul(yytext+1, NULL, 8);
  
  					check_escape_warning();
  					addlitchar(c);
  				}
! <xq>{xqhexesc}  {
  					unsigned char c = strtoul(yytext+2, NULL, 16);
  
  					check_escape_warning();
  					addlitchar(c);
  				}
! <xq>{quotecontinue} {
  					/* ignore */
  				}
! <xq>.			{
  					/* This is only needed for \ just before EOF */
  					addlitchar(yytext[0]);
  				}
! <xq><<EOF>>		{ yyerror("unterminated quoted string"); }
  
  {dolqdelim}		{
  					token_start = yytext;
--- 434,495 ----
  {xqstart}		{
  					warn_on_first_escape = true;
  					token_start = yytext;
! 					if (standard_conforming_strings)
! 						BEGIN(xq);
! 					else
! 						BEGIN(xe);
  					startlit();
  				}
  {xestart}		{
  					warn_on_first_escape = false;
  					token_start = yytext;
! 					BEGIN(xe);
  					startlit();
  				}
! <xq,xe>{quotestop}	|
! <xq,xe>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval.str = litbufdup();
  					return SCONST;
  				}
! <xq,xe>{xqdouble}  {
  					addlitchar('\'');
  				}
  <xq>{xqinside}  {
  					addlit(yytext, yyleng);
  				}
! <xe>{xeinside}  {
! 					addlit(yytext, yyleng);
! 				}
! <xq>{xqbackslash} {
! 					check_string_escape_warning(yytext[1]);
! 					addlitchar('\\');
!                 }
! <xe>{xeescape}  {
! 					check_string_escape_warning(yytext[1]);
  					addlitchar(unescape_single_char(yytext[1]));
  				}
! <xe>{xeoctesc}  {
  					unsigned char c = strtoul(yytext+1, NULL, 8);
  
  					check_escape_warning();
  					addlitchar(c);
  				}
! <xe>{xehexesc}  {
  					unsigned char c = strtoul(yytext+2, NULL, 16);
  
  					check_escape_warning();
  					addlitchar(c);
  				}
! <xq,xe>{quotecontinue} {
  					/* ignore */
  				}
! <xe>.			{
  					/* This is only needed for \ just before EOF */
  					addlitchar(yytext[0]);
  				}
! <xq,xe><<EOF>>		{ yyerror("unterminated quoted string"); }
  
  {dolqdelim}		{
  					token_start = yytext;
***************
*** 876,881 ****
--- 871,903 ----
  }
  
  static void
+ check_string_escape_warning(unsigned char ychar)
+ {
+ 	if (ychar == '\'')
+ 	{
+ 		if (warn_on_first_escape && escape_string_warning)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
+ 					 errmsg("nonstandard use of \\' in a string literal"),
+ 					 errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."),
+ 					 errposition(pg_err_position())));
+ 		warn_on_first_escape = false;	/* warn only once per string */
+ 	}
+ 	else if (ychar == '\\')
+ 	{
+ 		if (warn_on_first_escape && escape_string_warning)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
+ 					 errmsg("nonstandard use of \\\\ in a string literal"),
+ 					 errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."),
+ 					 errposition(pg_err_position())));
+ 		warn_on_first_escape = false;	/* warn only once per string */
+ 	}
+ 	else
+ 		check_escape_warning();
+ }
+ 
+ static void
  check_escape_warning(void)
  {
  	if (warn_on_first_escape && escape_string_warning)
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.299.2.2
diff -c -r1.299.2.2 guc.c
*** src/backend/utils/misc/guc.c	12 Feb 2006 22:32:57 -0000	1.299.2.2
--- src/backend/utils/misc/guc.c	13 Feb 2006 18:22:39 -0000
***************
*** 220,226 ****
  static int	max_identifier_length;
  static int	block_size;
  static bool integer_datetimes;
- static bool standard_conforming_strings;
  
  /* should be static, but commands/variable.c needs to get at these */
  char	   *role_string;
--- 220,225 ----
***************
*** 959,968 ****
  	},
  
  	{
! 		{"standard_conforming_strings", PGC_INTERNAL, PRESET_OPTIONS,
  			gettext_noop("'...' strings treat backslashes literally."),
  			NULL,
! 			GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
  		},
  		&standard_conforming_strings,
  		false, NULL, NULL
--- 958,967 ----
  	},
  
  	{
! 		{"standard_conforming_strings", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
  			gettext_noop("'...' strings treat backslashes literally."),
  			NULL,
! 			GUC_REPORT
  		},
  		&standard_conforming_strings,
  		false, NULL, NULL
Index: src/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.168.2.2
diff -c -r1.168.2.2 postgresql.conf.sample
*** src/backend/utils/misc/postgresql.conf.sample	10 Nov 2005 14:02:59 -0000	1.168.2.2
--- src/backend/utils/misc/postgresql.conf.sample	13 Feb 2006 18:22:39 -0000
***************
*** 416,422 ****
  #regex_flavor = advanced		# advanced, extended, or basic
  #sql_inheritance = on
  #default_with_oids = off
! #escape_string_warning = off
  
  # - Other Platforms & Clients -
  
--- 416,423 ----
  #regex_flavor = advanced		# advanced, extended, or basic
  #sql_inheritance = on
  #default_with_oids = off
! #escape_string_warning = off		# warn about backslashes in string literals
! #standard_conforming_strings = off	# interpret string literals according to ANSI/ISO standards
  
  # - Other Platforms & Clients -
  
Index: src/bin/psql/common.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/common.c,v
retrieving revision 1.110.2.1
diff -c -r1.110.2.1 common.c
*** src/bin/psql/common.c	22 Nov 2005 18:23:27 -0000	1.110.2.1
--- src/bin/psql/common.c	13 Feb 2006 18:22:39 -0000
***************
*** 1312,1317 ****
--- 1312,1340 ----
  
  
  /*
+  * Test if the current session uses standard string literals.
+  *
+  * Note: this will correctly detect the setting only with a protocol-3.0
+  * or newer backend; otherwise it will always say "false".
+  */
+ bool
+ standard_strings(void)
+ {
+ 	const char *val;
+ 
+ 	if (!pset.db)
+ 		return false;
+ 
+ 	val = PQparameterStatus(pset.db, "standard_conforming_strings");
+ 
+ 	if (val && strcmp(val, "on") == 0)
+ 		return true;
+ 
+ 	return false;
+ }
+ 
+ 
+ /*
   * Return the session user of the current connection.
   *
   * Note: this will correctly detect the session user only with a
Index: src/bin/psql/common.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/common.h,v
retrieving revision 1.45
diff -c -r1.45 common.h
*** src/bin/psql/common.h	15 Oct 2005 02:49:40 -0000	1.45
--- src/bin/psql/common.h	13 Feb 2006 18:22:39 -0000
***************
*** 57,62 ****
--- 57,63 ----
  extern bool SendQuery(const char *query);
  
  extern bool is_superuser(void);
+ extern bool standard_strings(void);
  extern const char *session_username(void);
  
  extern char *expand_tilde(char **filename);
Index: src/bin/psql/psqlscan.l
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/psqlscan.l,v
retrieving revision 1.15
diff -c -r1.15 psqlscan.l
*** src/bin/psql/psqlscan.l	26 Jun 2005 19:16:06 -0000	1.15
--- src/bin/psql/psqlscan.l	13 Feb 2006 18:22:39 -0000
***************
*** 154,160 ****
   *  <xc> extended C-style comments
   *  <xd> delimited identifiers (double-quoted identifiers)
   *  <xh> hexadecimal numeric string
!  *  <xq> quoted strings
   *  <xdolq> $foo$ quoted strings
   */
  
--- 154,161 ----
   *  <xc> extended C-style comments
   *  <xd> delimited identifiers (double-quoted identifiers)
   *  <xh> hexadecimal numeric string
!  *  <xq> standard quoted strings
!  *  <xe> extended quoted strings (support backslash escape sequences)
   *  <xdolq> $foo$ quoted strings
   */
  
***************
*** 162,167 ****
--- 163,169 ----
  %x xc
  %x xd
  %x xh
+ %x xe
  %x xq
  %x xdolq
  /* Additional exclusive states for psql only: lex backslash commands */
***************
*** 244,259 ****
  
  /* Quoted string that allows backslash escapes */
  xestart			[eE]{quote}
  
  /* Extended quote
   * xqdouble implements embedded quote, ''''
   */
  xqstart			{quote}
  xqdouble		{quote}{quote}
! xqinside		[^\\']+
! xqescape		[\\][^0-7]
! xqoctesc		[\\][0-7]{1,3}
! xqhexesc		[\\]x[0-9A-Fa-f]{1,2}
  
  /* $foo$ style quotes ("dollar quoting")
   * The quoted string starts with $foo$ where "foo" is an optional string
--- 246,262 ----
  
  /* Quoted string that allows backslash escapes */
  xestart			[eE]{quote}
+ xeinside		[^\\']+
+ xeescape		[\\][^0-7]
+ xeoctesc		[\\][0-7]{1,3}
+ xehexesc		[\\]x[0-9A-Fa-f]{1,2}
  
  /* Extended quote
   * xqdouble implements embedded quote, ''''
   */
  xqstart			{quote}
  xqdouble		{quote}{quote}
! xqinside		[^']+
  
  /* $foo$ style quotes ("dollar quoting")
   * The quoted string starts with $foo$ where "foo" is an optional string
***************
*** 448,485 ****
  				}
  
  {xqstart}		{
! 					BEGIN(xq);
  					ECHO;
  				}
  {xestart}		{
! 					BEGIN(xq);
  					ECHO;
  				}
! <xq>{quotestop}	|
! <xq>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					ECHO;
  				}
! <xq>{xqdouble}  {
  					ECHO;
  				}
  <xq>{xqinside}  {
  					ECHO;
  				}
! <xq>{xqescape}  {
  					ECHO;
  				}
! <xq>{xqoctesc}  {
  					ECHO;
  				}
! <xq>{xqhexesc}  {
  					ECHO;
  				}
! <xq>{quotecontinue} {
  					ECHO;
  				}
! <xq>.			{
  					/* This is only needed for \ just before EOF */
  					ECHO;
  				}
--- 451,494 ----
  				}
  
  {xqstart}		{
! 					if (standard_strings())
! 						BEGIN(xq);
! 					else
! 						BEGIN(xe);
  					ECHO;
  				}
  {xestart}		{
! 					BEGIN(xe);
  					ECHO;
  				}
! <xq,xe>{quotestop}	|
! <xq,xe>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					ECHO;
  				}
! <xq,xe>{xqdouble}  {
  					ECHO;
  				}
  <xq>{xqinside}  {
  					ECHO;
  				}
! <xe>{xeinside}  {
! 					ECHO;
! 				}
! <xe>{xeescape}  {
  					ECHO;
  				}
! <xe>{xeoctesc}  {
  					ECHO;
  				}
! <xe>{xehexesc}  {
  					ECHO;
  				}
! <xq,xe>{quotecontinue} {
  					ECHO;
  				}
! <xe>.			{
  					/* This is only needed for \ just before EOF */
  					ECHO;
  				}
***************
*** 858,870 ****
  "\\r"			{ appendPQExpBufferChar(output_buf, '\r'); }
  "\\f"			{ appendPQExpBufferChar(output_buf, '\f'); }
  
! {xqoctesc}		{
  					/* octal case */
  					appendPQExpBufferChar(output_buf,
  										  (char) strtol(yytext + 1, NULL, 8));
  				}
  
! {xqhexesc}		{
  					/* hex case */
  					appendPQExpBufferChar(output_buf,
  										  (char) strtol(yytext + 2, NULL, 16));
--- 867,879 ----
  "\\r"			{ appendPQExpBufferChar(output_buf, '\r'); }
  "\\f"			{ appendPQExpBufferChar(output_buf, '\f'); }
  
! {xeoctesc}		{
  					/* octal case */
  					appendPQExpBufferChar(output_buf,
  										  (char) strtol(yytext + 1, NULL, 8));
  				}
  
! {xehexesc}		{
  					/* hex case */
  					appendPQExpBufferChar(output_buf,
  										  (char) strtol(yytext + 2, NULL, 16));
***************
*** 1128,1133 ****
--- 1137,1146 ----
  					result = PSCAN_INCOMPLETE;
  					*prompt = PROMPT_SINGLEQUOTE;
  					break;
+ 				case xe:
+ 					result = PSCAN_INCOMPLETE;
+ 					*prompt = PROMPT_SINGLEQUOTE;
+ 					break;
  				case xdolq:
  					result = PSCAN_INCOMPLETE;
  					*prompt = PROMPT_DOLLARQUOTE;
Index: src/include/utils/guc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/guc.h,v
retrieving revision 1.63
diff -c -r1.63 guc.h
*** src/include/utils/guc.h	15 Oct 2005 02:49:46 -0000	1.63
--- src/include/utils/guc.h	13 Feb 2006 18:22:40 -0000
***************
*** 121,126 ****
--- 121,127 ----
  
  extern bool default_with_oids;
  extern bool escape_string_warning;
+ extern bool standard_conforming_strings;
  
  extern int	log_min_error_statement;
  extern int	log_min_messages;
Index: src/interfaces/ecpg/preproc/pgc.l
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v
retrieving revision 1.137
diff -c -r1.137 pgc.l
*** src/interfaces/ecpg/preproc/pgc.l	5 Oct 2005 14:58:36 -0000	1.137
--- src/interfaces/ecpg/preproc/pgc.l	13 Feb 2006 18:22:40 -0000
***************
*** 30,35 ****
--- 30,36 ----
  static int		xcdepth = 0;	/* depth of nesting in slash-star comments */
  static char    *dolqstart;      /* current $foo$ quote start string */
  bool                    escape_string_warning;
+ bool                    standard_conforming_strings;
  static bool             warn_on_first_escape;
  
  /*
***************
*** 96,102 ****
   *	<xc> extended C-style comments - thomas 1997-07-12
   *	<xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
   *	<xh> hexadecimal numeric string - thomas 1997-11-16
!  *	<xq> quoted strings - thomas 1997-07-30
   *  	<xdolq> $foo$ quoted strings
   */
  
--- 97,104 ----
   *	<xc> extended C-style comments - thomas 1997-07-12
   *	<xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
   *	<xh> hexadecimal numeric string - thomas 1997-11-16
!  *	<xq> standard quoted strings - thomas 1997-07-30
!  *	<xe> extended quoted strings (support backslash escape sequences)
   *  	<xdolq> $foo$ quoted strings
   */
  
***************
*** 105,110 ****
--- 107,113 ----
  %x xd
  %x xdc
  %x xh
+ %x xe
  %x xq
  %x xdolq
  %x xpre
***************
*** 125,130 ****
--- 128,137 ----
  
  /* Quoted string that allows backslash escapes */
  xestart                 [eE]{quote}
+ xeinside                [^\\']+
+ xeescape	                [\\][^0-7]
+ xeoctesc	                [\\][0-7]{1,3}
+ xehexesc	                [\\]x[0-9A-Fa-f]{1,2}
  
  /* C version of hex number */
  xch			0[xX][0-9A-Fa-f]*
***************
*** 135,143 ****
  xqstart			{quote}
  xqdouble		{quote}{quote}
  xqinside		[^\\']+
! xqescape		[\\][^0-7]
! xqoctesc		[\\][0-7]{1,3}
! xqhexesc		[\\]x[0-9A-Fa-f]{1,2}
  
  /* $foo$ style quotes ("dollar quoting")
   * The quoted string starts with $foo$ where "foo" is an optional string
--- 142,148 ----
  xqstart			{quote}
  xqdouble		{quote}{quote}
  xqinside		[^\\']+
! xqbackslash	[\\]
  
  /* $foo$ style quotes ("dollar quoting")
   * The quoted string starts with $foo$ where "foo" is an optional string
***************
*** 405,447 ****
  				warn_on_first_escape = true;
  				token_start = yytext;
  				state_before = YYSTATE;
! 				BEGIN(xq);
  				startlit();
  			}
  <C,SQL>{xestart}	{
  				warn_on_first_escape = false;
  				token_start = yytext;
  				state_before = YYSTATE;
! 				BEGIN(xq);
  				startlit();
  			}
! <xq>{quotestop} |
! <xq>{quotefail}		{
  				yyless(1);
  				BEGIN(state_before);
  				yylval.str = mm_strdup(literalbuf);
  				return SCONST;
  			}
! <xq>{xqdouble}		{ addlitchar('\''); }
  <xq>{xqinside}		{ addlit(yytext, yyleng); }
! <xq>{xqescape}  	{ 
  				check_escape_warning();
  				addlit(yytext, yyleng);
  			}
! <xq>{xqoctesc}		{ 
  				check_escape_warning();
  				addlit(yytext, yyleng);
  			}
! <xq>{xqhexesc}		{ 
  				check_escape_warning();
  				addlit(yytext, yyleng);
  			}
! <xq>{quotecontinue}	{ /* ignore */ }
! <xq>.                   {
                                         /* This is only needed for \ just before EOF */
                                         addlitchar(yytext[0]);
                          }
! <xq><<EOF>>		{ mmerror(PARSE_ERROR, ET_FATAL, "Unterminated quoted string"); }
  <SQL>{dolqfailed}	{
  				/* throw back all but the initial "$" */
  				yyless(1);
--- 410,460 ----
  				warn_on_first_escape = true;
  				token_start = yytext;
  				state_before = YYSTATE;
! 				if (standard_conforming_strings)
! 					BEGIN(xq);
! 				else
! 					BEGIN(xe);
  				startlit();
  			}
  <C,SQL>{xestart}	{
  				warn_on_first_escape = false;
  				token_start = yytext;
  				state_before = YYSTATE;
! 				BEGIN(xe);
  				startlit();
  			}
! <xq,xe>{quotestop} |
! <xq,xe>{quotefail} {
  				yyless(1);
  				BEGIN(state_before);
  				yylval.str = mm_strdup(literalbuf);
  				return SCONST;
  			}
! <xq,xe>{xqdouble}		{ addlitchar('\''); }
  <xq>{xqinside}		{ addlit(yytext, yyleng); }
! <xe>{xeinside}		{ addlit(yytext, yyleng); }
! <xq>{xqbackslash} {
! 					check_escape_warning();
! 					addlitchar('\\');
!                 }
! <xe>{xeescape}  	{ 
  				check_escape_warning();
  				addlit(yytext, yyleng);
  			}
! <xe>{xeoctesc}		{ 
  				check_escape_warning();
  				addlit(yytext, yyleng);
  			}
! <xe>{xehexesc}		{ 
  				check_escape_warning();
  				addlit(yytext, yyleng);
  			}
! <xq,xe>{quotecontinue}	{ /* ignore */ }
! <xe>.                   {
                                         /* This is only needed for \ just before EOF */
                                         addlitchar(yytext[0]);
                          }
! <xq,xe><<EOF>>		{ mmerror(PARSE_ERROR, ET_FATAL, "Unterminated quoted string"); }
  <SQL>{dolqfailed}	{
  				/* throw back all but the initial "$" */
  				yyless(1);
Index: src/test/regress/expected/strings.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/strings.out,v
retrieving revision 1.26
diff -c -r1.26 strings.out
*** src/test/regress/expected/strings.out	10 Jul 2005 04:54:33 -0000	1.26
--- src/test/regress/expected/strings.out	13 Feb 2006 18:22:41 -0000
***************
*** 193,205 ****
  (1 row)
  
  -- PostgreSQL extension to allow using back reference in replace string;
! SELECT regexp_replace('1112223333', '(\\d{3})(\\d{3})(\\d{4})', '(\\1) \\2-\\3');
   regexp_replace 
  ----------------
   (111) 222-3333
  (1 row)
  
! SELECT regexp_replace('AAA   BBB   CCC   ', '\\s+', ' ', 'g');
   regexp_replace 
  ----------------
   AAA BBB CCC 
--- 193,205 ----
  (1 row)
  
  -- PostgreSQL extension to allow using back reference in replace string;
! SELECT regexp_replace('1112223333', E'(\\d{3})(\\d{3})(\\d{4})', E'(\\1) \\2-\\3');
   regexp_replace 
  ----------------
   (111) 222-3333
  (1 row)
  
! SELECT regexp_replace('AAA   BBB   CCC   ', E'\\s+', ' ', 'g');
   regexp_replace 
  ----------------
   AAA BBB CCC 
***************
*** 895,897 ****
--- 895,980 ----
   t
  (1 row)
  
+ --
+ -- test behavior of escape_string_warning and standard_conforming_strings options
+ --
+ set escape_string_warning = off;
+ set standard_conforming_strings = off;
+ show escape_string_warning;
+  escape_string_warning 
+ -----------------------
+  off
+ (1 row)
+ 
+ show standard_conforming_strings;
+  standard_conforming_strings 
+ -----------------------------
+  off
+ (1 row)
+ 
+ set escape_string_warning = on;
+ set standard_conforming_strings = on;
+ show escape_string_warning;
+  escape_string_warning 
+ -----------------------
+  on
+ (1 row)
+ 
+ show standard_conforming_strings;
+  standard_conforming_strings 
+ -----------------------------
+  on
+ (1 row)
+ 
+ select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' as f5, '\\' as f6;
+ WARNING:  nonstandard use of escape in a string literal at character 8
+ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
+ WARNING:  nonstandard use of escape in a string literal at character 23
+ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
+ WARNING:  nonstandard use of escape in a string literal at character 40
+ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
+ WARNING:  nonstandard use of escape in a string literal at character 59
+ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
+ WARNING:  nonstandard use of escape in a string literal at character 76
+ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
+ WARNING:  nonstandard use of escape in a string literal at character 93
+ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
+   f1   |   f2   |   f3    |  f4   |   f5   | f6 
+ -------+--------+---------+-------+--------+----
+  a\bcd | a\b'cd | a\b''cd | abcd\ | ab\'cd | \\
+ (1 row)
+ 
+ set standard_conforming_strings = off;
+ select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd' as f5, '\\\\' as f6;
+ WARNING:  nonstandard use of \\ in a string literal at character 8
+ HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
+ WARNING:  nonstandard use of \\ in a string literal at character 24
+ HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
+ WARNING:  nonstandard use of \\ in a string literal at character 42
+ HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
+ WARNING:  nonstandard use of \\ in a string literal at character 62
+ HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
+ WARNING:  nonstandard use of \\ in a string literal at character 80
+ HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
+ WARNING:  nonstandard use of \\ in a string literal at character 98
+ HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
+   f1   |   f2   |   f3    |  f4   |   f5   | f6 
+ -------+--------+---------+-------+--------+----
+  a\bcd | a\b'cd | a\b''cd | abcd\ | ab\'cd | \\
+ (1 row)
+ 
+ set escape_string_warning = off;
+ set standard_conforming_strings = on;
+ select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' as f5, '\\' as f6;
+   f1   |   f2   |   f3    |  f4   |   f5   | f6 
+ -------+--------+---------+-------+--------+----
+  a\bcd | a\b'cd | a\b''cd | abcd\ | ab\'cd | \\
+ (1 row)
+ 
+ set standard_conforming_strings = off;
+ select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd' as f5, '\\\\' as f6;
+   f1   |   f2   |   f3    |  f4   |   f5   | f6 
+ -------+--------+---------+-------+--------+----
+  a\bcd | a\b'cd | a\b''cd | abcd\ | ab\'cd | \\
+ (1 row)
+ 
Index: src/test/regress/sql/strings.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/strings.sql,v
retrieving revision 1.17
diff -c -r1.17 strings.sql
*** src/test/regress/sql/strings.sql	10 Jul 2005 04:54:33 -0000	1.17
--- src/test/regress/sql/strings.sql	13 Feb 2006 18:22:41 -0000
***************
*** 81,88 ****
  SELECT SUBSTRING('abcdefg' FROM 'b(.*)f') AS "cde";
  
  -- PostgreSQL extension to allow using back reference in replace string;
! SELECT regexp_replace('1112223333', '(\\d{3})(\\d{3})(\\d{4})', '(\\1) \\2-\\3');
! SELECT regexp_replace('AAA   BBB   CCC   ', '\\s+', ' ', 'g');
  SELECT regexp_replace('AAA', '^|$', 'Z', 'g');
  SELECT regexp_replace('AAA aaa', 'A+', 'Z', 'gi');
  -- invalid option of REGEXP_REPLACE
--- 81,88 ----
  SELECT SUBSTRING('abcdefg' FROM 'b(.*)f') AS "cde";
  
  -- PostgreSQL extension to allow using back reference in replace string;
! SELECT regexp_replace('1112223333', E'(\\d{3})(\\d{3})(\\d{4})', E'(\\1) \\2-\\3');
! SELECT regexp_replace('AAA   BBB   CCC   ', E'\\s+', ' ', 'g');
  SELECT regexp_replace('AAA', '^|$', 'Z', 'g');
  SELECT regexp_replace('AAA aaa', 'A+', 'Z', 'gi');
  -- invalid option of REGEXP_REPLACE
***************
*** 352,354 ****
--- 352,384 ----
  select md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'::bytea) = 'd174ab98d277d9f5a5611c2c9f419d9f' AS "TRUE";
  
  select md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890'::bytea) = '57edf4a22be3c955ac49da2e2107b67a' AS "TRUE";
+ 
+ --
+ -- test behavior of escape_string_warning and standard_conforming_strings options
+ --
+ set escape_string_warning = off;
+ set standard_conforming_strings = off;
+ 
+ show escape_string_warning;
+ show standard_conforming_strings;
+ 
+ set escape_string_warning = on;
+ set standard_conforming_strings = on;
+ 
+ show escape_string_warning;
+ show standard_conforming_strings;
+ 
+ select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' as f5, '\\' as f6;
+ 
+ set standard_conforming_strings = off;
+ 
+ select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd' as f5, '\\\\' as f6;
+ 
+ set escape_string_warning = off;
+ set standard_conforming_strings = on;
+ 
+ select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' as f5, '\\' as f6;
+ 
+ set standard_conforming_strings = off;
+ 
+ select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd' as f5, '\\\\' as f6;
