Dear patchers,

Please find enclosed a new patch submission which take into account
comments by Tom Lane about version 1.

(1) the function is renamed as "localisation" does not mean what I meant.

(2) three dots "..." appear after and before the line when truncated.

However, I still put the line number that I found useful.

The new version validates for me against current cvs head.

Same comment as with version one, I don't know how to test the multi-byte
part.

Have a nice day,

-- 
Fabien Coelho - [EMAIL PROTECTED]
*** ./src/bin/psql/common.c.orig        Thu Mar 11 15:42:17 2004
--- ./src/bin/psql/common.c     Thu Mar 11 18:05:22 2004
***************
*** 345,350 ****
--- 345,506 ----
  }
  
  
+ #define DISPLAY_SIZE (60)
+ #define MIN_RIGHT_CUT (10)
+ 
+ /* on errors, print syntax error position if available.
+  * the query is expected to be in the client encoding.
+  */
+ static void
+ ReportSyntaxErrorPosition(const PGresult *result, const char *query)
+ {
+       int loc = 0;
+       char * sp = PQresultErrorField(result, PG_DIAG_STATEMENT_POSITION);
+ 
+       if (sp && sscanf(sp, "%d", &loc)!=1)
+       {
+               psql_error("INTERNAL ERROR: unexpected statement position '%s'\n", sp);
+               return;
+       }
+       
+       /* do we have something to show? */
+       if (query!=NULL && loc>0)
+       {
+               int clen, slen, i, * qidx, ibeg, iend, last_nl, loc_line;
+               char *wquery, *cursor;
+               bool beg_trunc, end_trunc;
+ 
+               /* (1) let us first compute a character index for the query. */
+ 
+               /* we need a safe allocation size... */
+               slen = strlen(query); 
+ 
+               /* the last one is needed to store last char mb length */
+               qidx = (int*) palloc(sizeof(int)*(slen+1));
+ 
+               qidx[0] = 0;
+               for (i=1; query[qidx[i-1]]!='\0' && i<slen+1; i++)
+                       qidx[i] = qidx[i-1] + PQmblen(&query[qidx[i-1]], 
pset.encoding);
+               
+               clen = i-1;
+ 
+               /* we must be at the end! */
+               psql_assert(query[qidx[clen]] == '\0');
+ 
+               /* our localisation index start at 0! it must be in the query! */
+               loc--; 
+               psql_assert(loc>=0 && loc<clen);
+ 
+               /* (2) now we build a working copy of the query. */
+               wquery = (char*) palloc(sizeof(char)*(strlen(query)+1));
+               strcpy(wquery, query);
+ 
+               /* the character number of the last newline. */
+               last_nl = -1;
+                /* input line number of our syntax error. */
+               loc_line = 1;
+               /* first included char of extract. */
+               ibeg = 0; 
+               /* last not-included char of extract. */
+               iend = clen; 
+ 
+               /* (3) we clean wquery string from tabs, carriage return and new lines.
+                * extract error line number and begin and end indexes.
+                */
+               for (i=0; i<clen; i++)
+               {
+                       /* how to find a '\t', a '\r' or a '\n'? 
+                        * I assume here that all encodings must be ascii compatible...
+                        */
+                       if ((qidx[i+1]-qidx[i]) == 1)
+                       {
+                               if (wquery[qidx[i]] == '\t') 
+                                       wquery[qidx[i]] = ' ';
+                               if (wquery[qidx[i]] == '\r' || wquery[qidx[i]] == '\n')
+                               {
+                                       /* count lines */
+                                       if (wquery[qidx[i]]=='\n' && i<loc) 
+                                               loc_line++;
+ 
+                                       /* set extract end. */
+                                       if (iend==clen && i>loc)
+                                               iend = i;
+ 
+                                       wquery[qidx[i]] = ' ';
+                                       last_nl = i;
+                               }
+                       }
+                       /* set extract beginning. */
+                       if (i==loc && last_nl!=-1)
+                               ibeg = last_nl+1;
+               }
+ 
+               /* (4) if the line extracted is too long, we truncate it. */
+               beg_trunc = false;
+               end_trunc = false;
+               if (iend-ibeg > DISPLAY_SIZE)
+               {
+                       /* we first truncate right if it is enough. */
+                       if (ibeg+DISPLAY_SIZE > loc+MIN_RIGHT_CUT)
+                       {
+                               iend = ibeg+DISPLAY_SIZE;
+                               end_trunc = true;
+                       }
+                       else
+                       {
+                               /* we truncate right. */
+                               if (loc+MIN_RIGHT_CUT < iend)
+                               {
+                                       iend = loc+MIN_RIGHT_CUT;
+                                       end_trunc = true;
+                               }
+ 
+                               /* still too long? 
+                                * we know that loc is at the end 
+                                * (loc+MIN_RIGHT_CUT>=iend from above)
+                                * now we truncate left.
+                                */
+                               if (iend-ibeg > DISPLAY_SIZE)
+                               {
+                                       ibeg = iend-DISPLAY_SIZE;
+                                       beg_trunc = true;
+                               }
+                       }
+               }
+               
+               /* (5) if the line is too short, we could fix it here. */
+ 
+               /* the extract MUST contain the localisation! */
+               psql_assert(ibeg<=loc && loc<iend);
+ 
+               /* (6) string to show cursor position under the extract. */
+               cursor = (char *) palloc(loc-ibeg+2);
+               for (i=0; i<loc-ibeg; i++)
+                       cursor[i] = ' ';
+               cursor[i++] = '^';
+               cursor[i++] = '\0';
+ 
+               /* (7) now we show the resulting message. */
+ 
+               /* fix extract length for fprintf. */
+               wquery[qidx[iend]] = '\0';
+ 
+               /* translator: %s%s%s is a query extract as 'id INTEGER NOT NUL ...' */
+               psql_error("QUERY: %s%s%s\n", 
+                                  beg_trunc? "...": "", &wquery[qidx[ibeg]],
+                                  end_trunc? "...": "");
+ 
+               /* translator: %s%s is a cursor such as      '              ^' */
+               psql_error("QUERY: %s%s on line %d\n", 
+                                  beg_trunc? "   ": "",cursor, loc_line);
+ 
+               /* clean */
+               pfree(wquery);
+               pfree(qidx);
+               pfree(cursor);
+       }
+ }
+ 
  /*
   * AcceptResult
   *
***************
*** 355,361 ****
   * Returns true for valid result, false for error state.
   */
  static bool
! AcceptResult(const PGresult *result)
  {
        bool            OK = true;
  
--- 511,517 ----
   * Returns true for valid result, false for error state.
   */
  static bool
! AcceptResult(const PGresult *result, const char * query)
  {
        bool            OK = true;
  
***************
*** 386,391 ****
--- 542,548 ----
        if (!OK)
        {
                psql_error("%s", PQerrorMessage(pset.db));
+               ReportSyntaxErrorPosition(result, query);
                CheckConnection();
        }
  
***************
*** 449,455 ****
  
        res = PQexec(pset.db, query);
  
!       if (!AcceptResult(res) && res)
        {
                PQclear(res);
                res = NULL;
--- 606,612 ----
  
        res = PQexec(pset.db, query);
  
!       if (!AcceptResult(res, query) && res)
        {
                PQclear(res);
                res = NULL;
***************
*** 695,701 ****
        results = PQexec(pset.db, query);
  
        /* these operations are included in the timing result: */
!       OK = (AcceptResult(results) && ProcessCopyResult(results));
  
        if (pset.timing)
                GETTIMEOFDAY(&after);
--- 852,858 ----
        results = PQexec(pset.db, query);
  
        /* these operations are included in the timing result: */
!       OK = (AcceptResult(results, query) && ProcessCopyResult(results));
  
        if (pset.timing)
                GETTIMEOFDAY(&after);
*** ./src/test/regress/expected/constraints.out.orig    Thu Mar 11 16:08:12 2004
--- ./src/test/regress/expected/constraints.out Thu Mar 11 16:08:20 2004
***************
*** 46,56 ****
--- 46,60 ----
  --  test for extraneous comma
  CREATE TABLE error_tbl (i int DEFAULT (100, ));
  ERROR:  syntax error at or near "," at character 43
+ QUERY: CREATE TABLE error_tbl (i int DEFAULT (100, ));
+ QUERY:                                           ^ on line 1
  --  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:  syntax error at or near "IN" at character 43
+ QUERY: CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
+ QUERY:                                           ^ on line 1
  --  this should work, however:
  CREATE TABLE error_tbl (b1 bool DEFAULT (1 IN (1, 2)));
  DROP TABLE error_tbl;
*** ./src/test/regress/expected/errors.out.orig Thu Mar 11 16:08:29 2004
--- ./src/test/regress/expected/errors.out      Thu Mar 11 17:51:41 2004
***************
*** 23,34 ****
--- 23,38 ----
  -- missing relation name 
  select;
  ERROR:  syntax error at or near ";" at character 7
+ QUERY: select;
+ QUERY:       ^ on line 1
  -- no such relation 
  select * from nonesuch;
  ERROR:  relation "nonesuch" does not exist
  -- missing target list
  select from pg_database;
  ERROR:  syntax error at or near "from" at character 8
+ QUERY: select from pg_database;
+ QUERY:        ^ on line 1
  -- bad name in target list
  select nonesuch from pg_database;
  ERROR:  column "nonesuch" does not exist
***************
*** 41,46 ****
--- 45,52 ----
  -- bad select distinct on syntax, distinct attribute missing
  select distinct on (foobar) from pg_database;
  ERROR:  syntax error at or near "from" at character 29
+ QUERY: select distinct on (foobar) from pg_database;
+ QUERY:                             ^ on line 1
  -- bad select distinct on syntax, distinct attribute not in target list
  select distinct on (foobar) * from pg_database;
  ERROR:  column "foobar" does not exist
***************
*** 50,55 ****
--- 56,63 ----
  -- missing relation name (this had better not wildcard!) 
  delete from;
  ERROR:  syntax error at or near ";" at character 12
+ QUERY: delete from;
+ QUERY:            ^ on line 1
  -- no such relation 
  delete from nonesuch;
  ERROR:  relation "nonesuch" does not exist
***************
*** 59,64 ****
--- 67,74 ----
  -- missing relation name (this had better not wildcard!) 
  drop table;
  ERROR:  syntax error at or near ";" at character 11
+ QUERY: drop table;
+ QUERY:           ^ on line 1
  -- no such relation 
  drop table nonesuch;
  ERROR:  table "nonesuch" does not exist
***************
*** 69,74 ****
--- 79,86 ----
  -- missing relation name 
  alter table rename;
  ERROR:  syntax error at or near ";" at character 19
+ QUERY: alter table rename;
+ QUERY:                   ^ on line 1
  -- no such relation 
  alter table nonesuch rename to newnonesuch;
  ERROR:  relation "nonesuch" does not exist
***************
*** 123,131 ****
--- 135,147 ----
  -- missing index name 
  drop index;
  ERROR:  syntax error at or near ";" at character 11
+ QUERY: drop index;
+ QUERY:           ^ on line 1
  -- bad index name 
  drop index 314159;
  ERROR:  syntax error at or near "314159" at character 12
+ QUERY: drop index 314159;
+ QUERY:            ^ on line 1
  -- no such index 
  drop index nonesuch;
  ERROR:  index "nonesuch" does not exist
***************
*** 135,146 ****
--- 151,168 ----
  -- missing aggregate name 
  drop aggregate;
  ERROR:  syntax error at or near ";" at character 15
+ QUERY: drop aggregate;
+ QUERY:               ^ on line 1
  -- missing aggregate type
  drop aggregate newcnt1;
  ERROR:  syntax error at or near ";" at character 23
+ QUERY: drop aggregate newcnt1;
+ QUERY:                       ^ on line 1
  -- bad aggregate name 
  drop aggregate 314159 (int);
  ERROR:  syntax error at or near "314159" at character 16
+ QUERY: drop aggregate 314159 (int);
+ QUERY:                ^ on line 1
  -- bad aggregate type
  drop aggregate newcnt (nonesuch);
  ERROR:  type "nonesuch" does not exist
***************
*** 156,164 ****
--- 178,190 ----
  -- missing function name 
  drop function ();
  ERROR:  syntax error at or near "(" at character 15
+ QUERY: drop function ();
+ QUERY:               ^ on line 1
  -- bad function name 
  drop function 314159();
  ERROR:  syntax error at or near "314159" at character 15
+ QUERY: drop function 314159();
+ QUERY:               ^ on line 1
  -- no such function 
  drop function nonesuch();
  ERROR:  function nonesuch() does not exist
***************
*** 168,176 ****
--- 194,206 ----
  -- missing type name 
  drop type;
  ERROR:  syntax error at or near ";" at character 10
+ QUERY: drop type;
+ QUERY:          ^ on line 1
  -- bad type name 
  drop type 314159;
  ERROR:  syntax error at or near "314159" at character 11
+ QUERY: drop type 314159;
+ QUERY:           ^ on line 1
  -- no such type 
  drop type nonesuch;
  ERROR:  type "nonesuch" does not exist
***************
*** 180,200 ****
--- 210,242 ----
  -- missing everything 
  drop operator;
  ERROR:  syntax error at or near ";" at character 14
+ QUERY: drop operator;
+ QUERY:              ^ on line 1
  -- bad operator name 
  drop operator equals;
  ERROR:  syntax error at or near ";" at character 21
+ QUERY: drop operator equals;
+ QUERY:                     ^ on line 1
  -- missing type list 
  drop operator ===;
  ERROR:  syntax error at or near ";" at character 18
+ QUERY: drop operator ===;
+ QUERY:                  ^ on line 1
  -- missing parentheses 
  drop operator int4, int4;
  ERROR:  syntax error at or near "," at character 19
+ QUERY: drop operator int4, int4;
+ QUERY:                   ^ on line 1
  -- missing operator name 
  drop operator (int4, int4);
  ERROR:  syntax error at or near "(" at character 15
+ QUERY: drop operator (int4, int4);
+ QUERY:               ^ on line 1
  -- missing type list contents 
  drop operator === ();
  ERROR:  syntax error at or near ")" at character 20
+ QUERY: drop operator === ();
+ QUERY:                    ^ on line 1
  -- no such operator 
  drop operator === (int4);
  ERROR:  missing argument
***************
*** 209,214 ****
--- 251,258 ----
  -- no such type1 
  drop operator = ( , int4);
  ERROR:  syntax error at or near "," at character 19
+ QUERY: drop operator = ( , int4);
+ QUERY:                   ^ on line 1
  -- no such type1 
  drop operator = (nonesuch, int4);
  ERROR:  type nonesuch does not exist
***************
*** 218,244 ****
--- 262,300 ----
  -- no such type2 
  drop operator = (int4, );
  ERROR:  syntax error at or near ")" at character 24
+ QUERY: drop operator = (int4, );
+ QUERY:                        ^ on line 1
  --
  -- DROP RULE
   
  -- missing rule name 
  drop rule;
  ERROR:  syntax error at or near ";" at character 10
+ QUERY: drop rule;
+ QUERY:          ^ on line 1
  -- bad rule name 
  drop rule 314159;
  ERROR:  syntax error at or near "314159" at character 11
+ QUERY: drop rule 314159;
+ QUERY:           ^ on line 1
  -- no such rule 
  drop rule nonesuch on noplace;
  ERROR:  relation "noplace" does not exist
  -- bad keyword 
  drop tuple rule nonesuch;
  ERROR:  syntax error at or near "tuple" at character 6
+ QUERY: drop tuple rule nonesuch;
+ QUERY:      ^ on line 1
  -- no such rule 
  drop instance rule nonesuch on noplace;
  ERROR:  syntax error at or near "instance" at character 6
+ QUERY: drop instance rule nonesuch on noplace;
+ QUERY:      ^ on line 1
  -- no such rule 
  drop rewrite rule nonesuch;
  ERROR:  syntax error at or near "rewrite" at character 6
+ QUERY: drop rewrite rule nonesuch;
+ QUERY:      ^ on line 1
  --
  -- Check that division-by-zero is properly caught.
  --
***************
*** 264,266 ****
--- 320,378 ----
  ERROR:  division by zero
  select 1/0::float4;
  ERROR:  division by zero
+ --
+ -- Error Localisation
+ --
+ ;
+ xxx;
+ ERROR:  syntax error at or near "xxx" at character 1
+ QUERY: xxx;
+ QUERY: ^ on line 1
+ CREATE foo;
+ ERROR:  syntax error at or near "foo" at character 8
+ QUERY: CREATE foo;
+ QUERY:        ^ on line 1
+ CREATE TABLE ;
+ ERROR:  syntax error at or near ";" at character 14
+ QUERY: CREATE TABLE ;
+ QUERY:              ^ on line 1
+ INSERT INTO foo VALUES(123) foo;
+ ERROR:  syntax error at or near "foo" at character 29
+ QUERY: INSERT INTO foo VALUES(123) foo;
+ QUERY:                             ^ on line 1
+ INSERT INTO 123
+ VALUES(123);
+ ERROR:  syntax error at or near "123" at character 13
+ QUERY: INSERT INTO 123
+ QUERY:             ^ on line 1
+ INSERT INTO foo 
+ VALUES(123) 123
+ ;
+ ERROR:  syntax error at or near "123" at character 30
+ QUERY: VALUES(123) 123
+ QUERY:             ^ on line 2
+ -- with a tab
+ CREATE TABLE foo
+   (id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY,
+       id3 INTEGER NOT NUL,
+    id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
+ ERROR:  syntax error at or near "NUL" at character 94
+ QUERY:  id3 INTEGER NOT NUL,
+ QUERY:                  ^ on line 3
+ -- long line to be truncated on the left
+ CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER 
NOT NUL, 
+ id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
+ ERROR:  syntax error at or near "NUL" at character 90
+ QUERY: ...T NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, 
+ QUERY:                                                           ^ on line 1
+ -- long line to be truncated on the right
+ CREATE TABLE foo(
+ id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, id INT4 
UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY);
+ ERROR:  syntax error at or near "NUL" at character 35
+ QUERY: id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQ...
+ QUERY:                 ^ on line 2
+ -- long line to be truncated both ways
+ CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER 
NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
+ ERROR:  syntax error at or near "NUL" at character 90
+ QUERY: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I...
+ QUERY:                                                      ^ on line 1
*** ./src/test/regress/expected/strings.out.orig        Thu Mar 11 16:01:29 2004
--- ./src/test/regress/expected/strings.out     Thu Mar 11 16:01:43 2004
***************
*** 19,24 ****
--- 19,26 ----
  ' - third line'
        AS "Illegal comment within continuation";
  ERROR:  syntax error at or near "' - third line'" at character 75
+ QUERY: ' - third line'
+ QUERY: ^ on line 3
  --
  -- test conversions between various string types
  -- E021-10 implicit casting among the character data types
*** ./src/test/regress/output/create_function_1.source.orig     Mon Jul 28 02:09:16 
2003
--- ./src/test/regress/output/create_function_1.source  Thu Mar 11 16:07:03 2004
***************
*** 55,60 ****
--- 55,62 ----
  CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
      AS 'not even SQL';
  ERROR:  syntax error at or near "not" at character 1
+ QUERY: CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ QUERY: ^ on line 1
  CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
      AS 'SELECT 1, 2, 3;';
  ERROR:  return type mismatch in function declared to return integer
*** ./src/test/regress/sql/errors.sql.orig      Thu Mar 11 15:45:47 2004
--- ./src/test/regress/sql/errors.sql   Thu Mar 11 15:46:59 2004
***************
*** 276,278 ****
--- 276,316 ----
  select 1::float4/0;
  
  select 1/0::float4;
+ 
+ 
+ --
+ -- Error Localisation
+ --
+ ;
+ 
+ xxx;
+ 
+ CREATE foo;
+ 
+ CREATE TABLE ;
+ 
+ INSERT INTO foo VALUES(123) foo;
+ 
+ INSERT INTO 123
+ VALUES(123);
+ 
+ INSERT INTO foo 
+ VALUES(123) 123
+ ;
+ 
+ -- with a tab
+ CREATE TABLE foo
+   (id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY,
+       id3 INTEGER NOT NUL,
+    id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
+ 
+ -- long line to be truncated on the left
+ CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER 
NOT NUL, 
+ id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
+ 
+ -- long line to be truncated on the right
+ CREATE TABLE foo(
+ id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, id INT4 
UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY);
+ 
+ -- long line to be truncated both ways
+ CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER 
NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to