Patch for Improved Syntax Error Reporting - Mailing list pgsql-patches

From Neil Padgett
Subject Patch for Improved Syntax Error Reporting
Date
Msg-id 3B684355.7E9BD85F@redhat.com
Whole thread Raw
Responses Re: Patch for Improved Syntax Error Reporting
List pgsql-patches
Attached please find a patch to the input parser that yields better
syntax error reporting on parse errors. For example:

test=# SELECT * FRUM bob;
ERROR:  parser: parse error at or near "frum"

becomes:

test=# SELECT * FRUM bob;
ERROR:  parser: parse error at or near 'frum':
SELECT * FRUM bob;
         ^

I've also modified the regression tests accordingly.

I haven't made the corresponding changes to the ecpg grammar -- I'm not
sure whether changes like this are desirable there. Feedback welcome.

Comments?

Neil

--
Neil Padgett
Red Hat Canada Ltd.                       E-Mail:  npadgett@redhat.com
2323 Yonge Street, Suite #300,
Toronto, ON  M4P 2C9

Index: src/backend/parser/scan.l
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/scan.l,v
retrieving revision 1.88
diff -c -p -r1.88 scan.l
*** src/backend/parser/scan.l    2001/03/22 17:41:47    1.88
--- src/backend/parser/scan.l    2001/08/01 17:43:53
***************
*** 37,42 ****
--- 37,43 ----

  extern char *parseString;
  static char *parseCh;
+ static int parseOffset;

  /* some versions of lex define this as a macro */
  #if defined(yywrap)
*************** other            .
*** 254,262 ****
   */

  %%
! {whitespace}    { /* ignore */ }

! {xcstart}        {
                      xcdepth = 0;
                      BEGIN(xc);
                      /* Put back any characters past slash-star; see above */
--- 255,266 ----
   */

  %%
! {whitespace}    { parseOffset += yyleng;
!                   /* ignore */
!                 }

! {xcstart}        {
!                                         parseOffset += 2;
                      xcdepth = 0;
                      BEGIN(xc);
                      /* Put back any characters past slash-star; see above */
*************** other            .
*** 264,293 ****
                  }

  <xc>{xcstart}    {
                      xcdepth++;
                      /* Put back any characters past slash-star; see above */
                      yyless(2);
                  }

  <xc>{xcstop}    {
                      if (xcdepth <= 0)
                          BEGIN(INITIAL);
                      else
                          xcdepth--;
                  }

! <xc>{xcinside}    { /* ignore */ }

! <xc>{op_chars}    { /* ignore */ }

  <xc><<EOF>>        { elog(ERROR, "Unterminated /* comment"); }

! {xbitstart}        {
                      BEGIN(xbit);
                      startlit();
                      addlit("b", 1);
                  }
  <xbit>{xbitstop}    {
                      BEGIN(INITIAL);
                      if (literalbuf[strspn(literalbuf + 1, "01") + 1] != '\0')
                          elog(ERROR, "invalid bit string input: '%s'",
--- 268,303 ----
                  }

  <xc>{xcstart}    {
+                                         parseOffset += 2;
                      xcdepth++;
                      /* Put back any characters past slash-star; see above */
                      yyless(2);
                  }

  <xc>{xcstop}    {
+                                         parseOffset += yyleng;
                      if (xcdepth <= 0)
                          BEGIN(INITIAL);
                      else
                          xcdepth--;
                  }

! <xc>{xcinside}    { parseOffset += yyleng;
!                   /* ignore */ }

! <xc>{op_chars}    { parseOffset += yyleng;
!                   /* ignore */ }

  <xc><<EOF>>        { elog(ERROR, "Unterminated /* comment"); }

! {xbitstart}        {
!                                         parseOffset += yyleng;
                      BEGIN(xbit);
                      startlit();
                      addlit("b", 1);
                  }
  <xbit>{xbitstop}    {
+                                         parseOffset += yyleng;
                      BEGIN(INITIAL);
                      if (literalbuf[strspn(literalbuf + 1, "01") + 1] != '\0')
                          elog(ERROR, "invalid bit string input: '%s'",
*************** other            .
*** 297,311 ****
                  }
  <xh>{xhinside}    |
  <xbit>{xbitinside}    {
                      addlit(yytext, yyleng);
                  }
  <xh>{xhcat}        |
! <xbit>{xbitcat}        {
                      /* ignore */
                  }
  <xbit><<EOF>>        { elog(ERROR, "unterminated bit string literal"); }

  {xhstart}        {
                      BEGIN(xh);
                      startlit();
                  }
--- 307,324 ----
                  }
  <xh>{xhinside}    |
  <xbit>{xbitinside}    {
+                                         parseOffset += yyleng;
                      addlit(yytext, yyleng);
                  }
  <xh>{xhcat}        |
! <xbit>{xbitcat}        {
!                                         parseOffset += yyleng;
                      /* ignore */
                  }
  <xbit><<EOF>>        { elog(ERROR, "unterminated bit string literal"); }

  {xhstart}        {
+                                         parseOffset += yyleng;
                      BEGIN(xh);
                      startlit();
                  }
*************** other            .
*** 313,318 ****
--- 326,332 ----
                      long val;
                      char* endptr;

+                                         parseOffset += yyleng;
                      BEGIN(INITIAL);
                      errno = 0;
                      val = strtol(literalbuf, &endptr, 16);
*************** other            .
*** 330,339 ****
--- 344,355 ----
  <xh><<EOF>>        { elog(ERROR, "Unterminated hexadecimal integer"); }

  {xqstart}        {
+                                         parseOffset += yyleng;
                      BEGIN(xq);
                      startlit();
                  }
  <xq>{xqstop}    {
+                                         parseOffset += yyleng;
                      BEGIN(INITIAL);
                      yylval.str = scanstr(literalbuf);
                      return SCONST;
*************** other            .
*** 341,359 ****
--- 357,379 ----
  <xq>{xqdouble}    |
  <xq>{xqinside}    |
  <xq>{xqliteral} {
+                                         parseOffset += yyleng;
                      addlit(yytext, yyleng);
                  }
  <xq>{xqcat}        {
+                                         parseOffset += yyleng;
                      /* ignore */
                  }
  <xq><<EOF>>        { elog(ERROR, "Unterminated quoted string"); }


  {xdstart}        {
+                                         parseOffset += yyleng;
                      BEGIN(xd);
                      startlit();
                  }
  <xd>{xdstop}    {
+                                         parseOffset += yyleng;
                      BEGIN(INITIAL);
                      if (strlen(literalbuf) == 0)
                          elog(ERROR, "zero-length delimited identifier");
*************** other            .
*** 375,391 ****
                      return IDENT;
                  }
  <xd>{xddouble} {
                      addlit(yytext, yyleng-1);
                  }
! <xd>{xdinside}    {
                      addlit(yytext, yyleng);
                  }
  <xd><<EOF>>        { elog(ERROR, "Unterminated quoted identifier"); }

! {typecast}        { return TYPECAST; }

- {self}            { return yytext[0]; }
-
  {operator}        {
                      /*
                       * Check for embedded slash-star or dash-dash; those
--- 395,417 ----
                      return IDENT;
                  }
  <xd>{xddouble} {
+                                         parseOffset += yyleng;
                      addlit(yytext, yyleng-1);
                  }
! <xd>{xdinside}    {
!                                         parseOffset += yyleng;
                      addlit(yytext, yyleng);
                  }
  <xd><<EOF>>        { elog(ERROR, "Unterminated quoted identifier"); }

! {typecast}        {
!                           parseOffset += yyleng;
!                           return TYPECAST; }
!
! {self}            {
!                           parseOffset += yyleng;
!                           return yytext[0]; }

  {operator}        {
                      /*
                       * Check for embedded slash-star or dash-dash; those
*************** other            .
*** 396,401 ****
--- 422,429 ----
                      int        nchars = yyleng;
                      char   *slashstar = strstr((char*)yytext, "/*");
                      char   *dashdash = strstr((char*)yytext, "--");
+
+                                         parseOffset += yyleng;

                      if (slashstar && dashdash)
                      {
*************** other            .
*** 455,461 ****
                      return Op;
                  }

! {param}            {
                      yylval.ival = atol((char*)&yytext[1]);
                      return PARAM;
                  }
--- 483,490 ----
                      return Op;
                  }

! {param}
{
!                                         parseOffset += yyleng;
                      yylval.ival = atol((char*)&yytext[1]);
                      return PARAM;
                  }
*************** other            .
*** 463,469 ****
  {integer}        {
                      long val;
                      char* endptr;
!
                      errno = 0;
                      val = strtol((char *)yytext, &endptr, 10);
                      if (*endptr != '\0' || errno == ERANGE
--- 492,499 ----
  {integer}        {
                      long val;
                      char* endptr;
!
!                                         parseOffset += yyleng;
                      errno = 0;
                      val = strtol((char *)yytext, &endptr, 10);
                      if (*endptr != '\0' || errno == ERANGE
*************** other            .
*** 480,490 ****
                      yylval.ival = val;
                      return ICONST;
                  }
! {decimal}        {
                      yylval.str = pstrdup((char*)yytext);
                      return FCONST;
                  }
! {real}            {
                      yylval.str = pstrdup((char*)yytext);
                      return FCONST;
                  }
--- 510,522 ----
                      yylval.ival = val;
                      return ICONST;
                  }
! {decimal}
{
!                                         parseOffset += yyleng;
                      yylval.str = pstrdup((char*)yytext);
                      return FCONST;
                  }
! {real}
{
!                                         parseOffset += yyleng;
                      yylval.str = pstrdup((char*)yytext);
                      return FCONST;
                  }
*************** other            .
*** 493,498 ****
--- 525,532 ----
  {identifier}    {
                      ScanKeyword       *keyword;
                      int                i;
+
+                     parseOffset += yyleng;

                      /* Is it a keyword? */
                      keyword = ScanKeywordLookup((char*) yytext);
*************** other            .
*** 530,545 ****
                      return IDENT;
                  }

! {other}            { return yytext[0]; }

  %%

  void
  yyerror(const char *message)
  {
!     elog(ERROR, "parser: %s at or near \"%s\"", message, yytext);
  }

  int
  yywrap(void)
  {
--- 564,634 ----
                      return IDENT;
                  }

! {other}            {
!                           parseOffset += yyleng;
!                           return yytext[0];
!                         }

  %%

  void
  yyerror(const char *message)
  {
!   int errorOffset;
!   char *line;
!   char *endOfLine;
!   char *beginningOfLine;
!   size_t buffSize;
!
!   /* Calculate the error's offset from the beginning of the input */
!
!   errorOffset = parseOffset + 1 - yyleng;
!
!   /* Find the beginning of the input line */
!
!   for(beginningOfLine = parseString + errorOffset;
!       beginningOfLine > parseString;
!       beginningOfLine--)
!     if(*(beginningOfLine - 1) == '\n' ||
!        *(beginningOfLine - 1) == '\r' ||
!        *(beginningOfLine - 1) == '\f')
!       break;
!
!   /* Find the end of the input line */
!
!   for(endOfLine = parseString + errorOffset;
!       *endOfLine != '\0';
!       endOfLine++)
!     if(*endOfLine == '\n' ||
!        *endOfLine == '\r' ||
!        *endOfLine == '\f')
!       break;
!
!   /* Calculate the offset of the error into the input line */
!
!   errorOffset = errorOffset - (int)(beginningOfLine - parseString);
!
!   /* Allocate a buffer for the line */
!
!   buffSize = (endOfLine - beginningOfLine) + 1;
!   line = palloc(buffSize);
!
!   /* Copy the line into the buffer */
!
!   memcpy(line, beginningOfLine, buffSize);
!   *(line + buffSize - 1) = '\0';
!
!   /* Report the error */
!
!   elog(ERROR, "parser: %s at or near \"%s\":\n%s\n%*s",
!        message,
!        yytext,
!        line,
!        errorOffset,
!        "^");
  }

+
  int
  yywrap(void)
  {
*************** scanner_init(void)
*** 557,562 ****
--- 646,655 ----
         because input()/myinput() checks the non-nullness of parseCh
         to know when to pass the string to lex/flex */
      parseCh = NULL;
+
+     /* Initialize the parse input offset -- used by enhanced syntax error
reporting */
+
+     parseOffset = 0;

      /* initialize literal buffer to a reasonable but expansible size */
      literalalloc = 128;
Index: src/test/regress/expected/errors.out
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/test/regress/expected/errors.out,v
retrieving revision 1.26
diff -c -p -r1.26 errors.out
*** src/test/regress/expected/errors.out    2000/11/08 22:10:03    1.26
--- src/test/regress/expected/errors.out    2001/08/01 17:43:56
*************** select 1
*** 19,25 ****
  select
  -- no such relation
  select * from nonesuch;
! ERROR:  parser: parse error at or near "select"
  -- bad name in target list
  select nonesuch from pg_database;
  ERROR:  Attribute 'nonesuch' not found
--- 19,27 ----
  select
  -- no such relation
  select * from nonesuch;
! ERROR:  parser: parse error at or near "select":
! select
! ^
  -- bad name in target list
  select nonesuch from pg_database;
  ERROR:  Attribute 'nonesuch' not found
*************** select * from pg_database where pg_datab
*** 31,37 ****
  ERROR:  Attribute 'nonesuch' not found
  -- bad select distinct on syntax, distinct attribute missing
  select distinct on (foobar) from pg_database;
! ERROR:  parser: parse error at or near "from"
  -- bad select distinct on syntax, distinct attribute not in target
list
  select distinct on (foobar) * from pg_database;
  ERROR:  Attribute 'foobar' not found
--- 33,41 ----
  ERROR:  Attribute 'nonesuch' not found
  -- bad select distinct on syntax, distinct attribute missing
  select distinct on (foobar) from pg_database;
! ERROR:  parser: parse error at or near "from":
! select distinct on (foobar) from pg_database;
!                             ^
  -- bad select distinct on syntax, distinct attribute not in target
list
  select distinct on (foobar) * from pg_database;
  ERROR:  Attribute 'foobar' not found
*************** ERROR:  Attribute 'foobar' not found
*** 39,46 ****
  -- DELETE

  -- missing relation name (this had better not wildcard!)
  delete from;
! ERROR:  parser: parse error at or near ";"
  -- no such relation
  delete from nonesuch;
  ERROR:  Relation 'nonesuch' does not exist
--- 43,52 ----
  -- DELETE

  -- missing relation name (this had better not wildcard!)
+ delete from;
+ ERROR:  parser: parse error at or near ";":
  delete from;
!            ^
  -- no such relation
  delete from nonesuch;
  ERROR:  Relation 'nonesuch' does not exist
*************** ERROR:  Relation 'nonesuch' does not exi
*** 49,55 ****

  -- missing relation name (this had better not wildcard!)
  drop table;
! ERROR:  parser: parse error at or near ";"
  -- no such relation
  drop table nonesuch;
  ERROR:  table "nonesuch" does not exist
--- 55,63 ----

  -- missing relation name (this had better not wildcard!)
  drop table;
! ERROR:  parser: parse error at or near ";":
! drop table;
!           ^
  -- no such relation
  drop table nonesuch;
  ERROR:  table "nonesuch" does not exist
*************** ERROR:  table "nonesuch" does not exist
*** 58,65 ****

  -- relation renaming
  -- missing relation name
  alter table rename;
! ERROR:  parser: parse error at or near ";"
  -- no such relation
  alter table nonesuch rename to newnonesuch;
  ERROR:  Relation "nonesuch" does not exist
--- 66,75 ----

  -- relation renaming
  -- missing relation name
+ alter table rename;
+ ERROR:  parser: parse error at or near ";":
  alter table rename;
!                   ^
  -- no such relation
  alter table nonesuch rename to newnonesuch;
  ERROR:  Relation "nonesuch" does not exist
*************** ERROR:  Define: "basetype" unspecified
*** 116,125 ****

  -- missing index name
  drop index;
! ERROR:  parser: parse error at or near ";"
  -- bad index name
  drop index 314159;
! ERROR:  parser: parse error at or near "314159"
  -- no such index
  drop index nonesuch;
  ERROR:  index "nonesuch" does not exist
--- 126,139 ----

  -- missing index name
  drop index;
! ERROR:  parser: parse error at or near ";":
! drop index;
!           ^
  -- bad index name
+ drop index 314159;
+ ERROR:  parser: parse error at or near "314159":
  drop index 314159;
!            ^
  -- no such index
  drop index nonesuch;
  ERROR:  index "nonesuch" does not exist
*************** ERROR:  index "nonesuch" does not exist
*** 127,143 ****
  -- REMOVE AGGREGATE

  -- missing aggregate name
  drop aggregate;
! ERROR:  parser: parse error at or near ";"
  -- bad aggregate name
  drop aggregate 314159;
! ERROR:  parser: parse error at or near "314159"
  -- no such aggregate
  drop aggregate nonesuch;
! ERROR:  parser: parse error at or near ";"
  -- missing aggregate type
  drop aggregate newcnt1;
! ERROR:  parser: parse error at or near ";"
  -- bad aggregate type
  drop aggregate newcnt nonesuch;
  ERROR:  RemoveAggregate: type 'nonesuch' does not exist
--- 141,165 ----
  -- REMOVE AGGREGATE

  -- missing aggregate name
+ drop aggregate;
+ ERROR:  parser: parse error at or near ";":
  drop aggregate;
!               ^
  -- bad aggregate name
  drop aggregate 314159;
! ERROR:  parser: parse error at or near "314159":
! drop aggregate 314159;
!                      ^
  -- no such aggregate
+ drop aggregate nonesuch;
+ ERROR:  parser: parse error at or near ";":
  drop aggregate nonesuch;
!                        ^
  -- missing aggregate type
  drop aggregate newcnt1;
! ERROR:  parser: parse error at or near ";":
! drop aggregate newcnt1;
!                       ^
  -- bad aggregate type
  drop aggregate newcnt nonesuch;
  ERROR:  RemoveAggregate: type 'nonesuch' does not exist
*************** ERROR:  RemoveAggregate: aggregate 'newc
*** 148,158 ****
  -- REMOVE FUNCTION

  -- missing function name
  drop function ();
! ERROR:  parser: parse error at or near "("
  -- bad function name
  drop function 314159();
! ERROR:  parser: parse error at or near "314159"
  -- no such function
  drop function nonesuch();
  ERROR:  RemoveFunction: function 'nonesuch()' does not exist
--- 170,184 ----
  -- REMOVE FUNCTION

  -- missing function name
+ drop function ();
+ ERROR:  parser: parse error at or near "(":
  drop function ();
!                 ^
  -- bad function name
  drop function 314159();
! ERROR:  parser: parse error at or near "314159":
! drop function 314159();
!                       ^
  -- no such function
  drop function nonesuch();
  ERROR:  RemoveFunction: function 'nonesuch()' does not exist
*************** ERROR:  RemoveFunction: function 'nonesu
*** 160,170 ****
  -- REMOVE TYPE

  -- missing type name
  drop type;
! ERROR:  parser: parse error at or near ";"
  -- bad type name
  drop type 314159;
! ERROR:  parser: parse error at or near "314159"
  -- no such type
  drop type nonesuch;
  ERROR:  RemoveType: type 'nonesuch' does not exist
--- 186,200 ----
  -- REMOVE TYPE

  -- missing type name
+ drop type;
+ ERROR:  parser: parse error at or near ";":
  drop type;
!          ^
  -- bad type name
+ drop type 314159;
+ ERROR:  parser: parse error at or near "314159":
  drop type 314159;
!           ^
  -- no such type
  drop type nonesuch;
  ERROR:  RemoveType: type 'nonesuch' does not exist
*************** ERROR:  RemoveType: type 'nonesuch' does
*** 173,194 ****

  -- missing everything
  drop operator;
! ERROR:  parser: parse error at or near ";"
  -- bad operator name
  drop operator equals;
! ERROR:  parser: parse error at or near "equals"
  -- missing type list
  drop operator ===;
! ERROR:  parser: parse error at or near ";"
  -- missing parentheses
  drop operator int4, int4;
! ERROR:  parser: parse error at or near "int4"
  -- missing operator name
  drop operator (int4, int4);
! ERROR:  parser: parse error at or near "("
  -- missing type list contents
  drop operator === ();
! ERROR:  parser: parse error at or near ")"
  -- no such operator
  drop operator === (int4);
  ERROR:  parser: argument type missing (use NONE for unary operators)
--- 203,236 ----

  -- missing everything
  drop operator;
! ERROR:  parser: parse error at or near ";":
! drop operator;
!              ^
  -- bad operator name
+ drop operator equals;
+ ERROR:  parser: parse error at or near "equals":
  drop operator equals;
!               ^
  -- missing type list
  drop operator ===;
! ERROR:  parser: parse error at or near ";":
! drop operator ===;
!                  ^
  -- missing parentheses
+ drop operator int4, int4;
+ ERROR:  parser: parse error at or near "int4":
  drop operator int4, int4;
!                     ^
  -- missing operator name
  drop operator (int4, int4);
! ERROR:  parser: parse error at or near "(":
! drop operator (int4, int4);
!               ^
  -- missing type list contents
+ drop operator === ();
+ ERROR:  parser: parse error at or near ")":
  drop operator === ();
!                    ^
  -- no such operator
  drop operator === (int4);
  ERROR:  parser: argument type missing (use NONE for unary operators)
*************** ERROR:  RemoveOperator: binary operator
*** 199,206 ****
  drop operator = (nonesuch);
  ERROR:  parser: argument type missing (use NONE for unary operators)
  -- no such type1
  drop operator = ( , int4);
! ERROR:  parser: parse error at or near ","
  -- no such type1
  drop operator = (nonesuch, int4);
  ERROR:  RemoveOperator: type 'nonesuch' does not exist
--- 241,250 ----
  drop operator = (nonesuch);
  ERROR:  parser: argument type missing (use NONE for unary operators)
  -- no such type1
+ drop operator = ( , int4);
+ ERROR:  parser: parse error at or near ",":
  drop operator = ( , int4);
!                   ^
  -- no such type1
  drop operator = (nonesuch, int4);
  ERROR:  RemoveOperator: type 'nonesuch' does not exist
*************** drop operator = (int4, nonesuch);
*** 209,233 ****
  ERROR:  RemoveOperator: type 'nonesuch' does not exist
  -- no such type2
  drop operator = (int4, );
! ERROR:  parser: parse error at or near ")"
  --
  -- DROP RULE

  -- missing rule name
  drop rule;
! ERROR:  parser: parse error at or near ";"
  -- bad rule name
  drop rule 314159;
! ERROR:  parser: parse error at or near "314159"
  -- no such rule
  drop rule nonesuch;
  ERROR:  Rule or view "nonesuch" not found
  -- bad keyword
  drop tuple rule nonesuch;
! ERROR:  parser: parse error at or near "tuple"
  -- no such rule
  drop instance rule nonesuch;
! ERROR:  parser: parse error at or near "instance"
  -- no such rule
  drop rewrite rule nonesuch;
! ERROR:  parser: parse error at or near "rewrite"
--- 253,289 ----
  ERROR:  RemoveOperator: type 'nonesuch' does not exist
  -- no such type2
  drop operator = (int4, );
! ERROR:  parser: parse error at or near ")":
! drop operator = (int4, );
!                        ^
  --
  -- DROP RULE

  -- missing rule name
+ drop rule;
+ ERROR:  parser: parse error at or near ";":
  drop rule;
!          ^
  -- bad rule name
+ drop rule 314159;
+ ERROR:  parser: parse error at or near "314159":
  drop rule 314159;
!           ^
  -- no such rule
  drop rule nonesuch;
  ERROR:  Rule or view "nonesuch" not found
  -- bad keyword
  drop tuple rule nonesuch;
! ERROR:  parser: parse error at or near "tuple":
! drop tuple rule nonesuch;
!      ^
  -- no such rule
+ drop instance rule nonesuch;
+ ERROR:  parser: parse error at or near "instance":
  drop instance rule nonesuch;
!      ^
  -- no such rule
+ drop rewrite rule nonesuch;
+ ERROR:  parser: parse error at or near "rewrite":
  drop rewrite rule nonesuch;
!      ^
\ No newline at end of file
Index: src/test/regress/expected/strings.out
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/test/regress/expected/strings.out,v
retrieving revision 1.10
diff -c -p -r1.10 strings.out
*** src/test/regress/expected/strings.out    2001/06/01 17:49:17    1.10
--- src/test/regress/expected/strings.out    2001/08/01 17:43:56
*************** SELECT 'first line'
*** 17,23 ****
  ' - next line' /* this comment is not allowed here */
  ' - third line'
      AS "Illegal comment within continuation";
! ERROR:  parser: parse error at or near "'"
  --
  -- test conversions between various string types
  --
--- 17,25 ----
  ' - next line' /* this comment is not allowed here */
  ' - third line'
      AS "Illegal comment within continuation";
! ERROR:  parser: parse error at or near "'":
! ' - third line'
!               ^
  --
  -- test conversions between various string types
  --
Index: src/test/regress/output/constraints.source
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/test/regress/output/constraints.source,v
retrieving revision 1.18
diff -c -p -r1.18 constraints.source
*** src/test/regress/output/constraints.source    2001/02/22 05:32:56    1.18
--- src/test/regress/output/constraints.source    2001/08/01 17:43:56
*************** SELECT '' AS four, * FROM DEFAULTEXPR_TB
*** 45,56 ****
  -- syntax errors
  --  test for extraneous comma
  CREATE TABLE error_tbl (i int DEFAULT (100, ));
! ERROR:  parser: parse error at or near ","
  --  this will fail because gram.y uses b_expr not a_expr for defaults,
  --  to avoid a shift/reduce conflict that arises from NOT NULL being
  --  part of the column definition syntax:
  CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
! ERROR:  parser: parse error at or near "IN"
  --  this should work, however:
  CREATE TABLE error_tbl (b1 bool DEFAULT (1 IN (1, 2)));
  DROP TABLE error_tbl;
--- 45,60 ----
  -- syntax errors
  --  test for extraneous comma
  CREATE TABLE error_tbl (i int DEFAULT (100, ));
! ERROR:  parser: parse error at or near ",":
! CREATE TABLE error_tbl (i int DEFAULT (100, ));
!                                           ^
  --  this will fail because gram.y uses b_expr not a_expr for defaults,
  --  to avoid a shift/reduce conflict that arises from NOT NULL being
  --  part of the column definition syntax:
  CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
! ERROR:  parser: parse error at or near "IN":
! CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
!                                           ^
  --  this should work, however:
  CREATE TABLE error_tbl (b1 bool DEFAULT (1 IN (1, 2)));
  DROP TABLE error_tbl;

pgsql-patches by date:

Previous
From: Liam Stewart
Date:
Subject: Re: Patch to add insert of multiple tuples per INSERT statement
Next
From: Bruce Momjian
Date:
Subject: Re: Patch to enable window size detection code of psql for Solaris platform