Re: [PATCH] Extend ALTER OPERATOR to support adding commutator, negator, hashes, and merges - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [PATCH] Extend ALTER OPERATOR to support adding commutator, negator, hashes, and merges
Date
Msg-id 325394.1727365907@sss.pgh.pa.us
Whole thread Raw
In response to Re: [PATCH] Extend ALTER OPERATOR to support adding commutator, negator, hashes, and merges  (Christoph Berg <myon@debian.org>)
Responses Better error reporting from extension scripts (Was: Extend ALTER OPERATOR)
List pgsql-hackers
Christoph Berg <myon@debian.org> writes:
> I wish there was. The error reporting from failing extension scripts
> is really bad with no context at all, it has hit me a few times in the
> past already.

Nobody's spent any work on that :-(.  A really basic reporting
facility is not hard to add, as in the attached finger exercise.
The trouble with it can be explained by showing what I get after
intentionally breaking a script file command:

regression=# create extension cube;
ERROR:  syntax error at or near "CREAT"
LINE 16: CREAT FUNCTION cube_send(cube)
         ^
QUERY:  /* contrib/cube/cube--1.4--1.5.sql */

-- complain if script is sourced in psql, rather than via ALTER EXTENSION


-- Remove @ and ~
DROP OPERATOR @ (cube, cube);
DROP OPERATOR ~ (cube, cube);

-- Add binary input/output handlers
CREATE FUNCTION cube_recv(internal)
RETURNS cube
AS '$libdir/cube'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREAT FUNCTION cube_send(cube)
RETURNS bytea
AS '$libdir/cube'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

ALTER TYPE cube SET ( RECEIVE = cube_recv, SEND = cube_send );

CONTEXT:  extension script file "/home/postgres/install/share/extension/cube--1.4--1.5.sql"

So the first part of that is great, but if your script file is
large you probably won't be happy about having the whole thing
repeated in the "QUERY" field.  So this needs some work on
user-friendliness.

I'm inclined to think that maybe we'd be best off keeping the server
end of it straightforward, and trying to teach psql to abbreviate the
QUERY field in a useful way.  IIRC you get this same type of problem
with very large SQL-language functions and suchlike.

Also, I believe this doesn't help much for non-syntax errors
(those that aren't reported with an error location).  It might
be interesting to use the RawStmt.stmt_location/stmt_len fields
for the current parsetree to identify what to report, but
I've not dug further than this.

            regards, tom lane

diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index fab59ad5f6..6af72ff422 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -107,6 +107,13 @@ typedef struct ExtensionVersionInfo
     struct ExtensionVersionInfo *previous;    /* current best predecessor */
 } ExtensionVersionInfo;

+/* Info structure for script_error_callback() */
+typedef struct
+{
+    const char *sql;
+    const char *filename;
+} script_error_callback_arg;
+
 /* Local functions */
 static List *find_update_path(List *evi_list,
                               ExtensionVersionInfo *evi_start,
@@ -670,9 +677,32 @@ read_extension_script_file(const ExtensionControlFile *control,
     return dest_str;
 }

+/*
+ * error context callback for failures in script-file execution
+ */
+static void
+script_error_callback(void *arg)
+{
+    script_error_callback_arg *callback_arg = (script_error_callback_arg *) arg;
+    int            syntaxerrposition;
+
+    /* If it's a syntax error, convert to internal syntax error report */
+    syntaxerrposition = geterrposition();
+    if (syntaxerrposition > 0)
+    {
+        errposition(0);
+        internalerrposition(syntaxerrposition);
+        internalerrquery(callback_arg->sql);
+    }
+
+    errcontext("extension script file \"%s\"", callback_arg->filename);
+}
+
 /*
  * Execute given SQL string.
  *
+ * The filename the string came from is also provided, for error reporting.
+ *
  * Note: it's tempting to just use SPI to execute the string, but that does
  * not work very well.  The really serious problem is that SPI will parse,
  * analyze, and plan the whole string before executing any of it; of course
@@ -682,12 +712,25 @@ read_extension_script_file(const ExtensionControlFile *control,
  * could be very long.
  */
 static void
-execute_sql_string(const char *sql)
+execute_sql_string(const char *sql, const char *filename)
 {
+    script_error_callback_arg callback_arg;
+    ErrorContextCallback scripterrcontext;
     List       *raw_parsetree_list;
     DestReceiver *dest;
     ListCell   *lc1;

+    /*
+     * Setup error traceback support for ereport().
+     */
+    callback_arg.sql = sql;
+    callback_arg.filename = filename;
+
+    scripterrcontext.callback = script_error_callback;
+    scripterrcontext.arg = (void *) &callback_arg;
+    scripterrcontext.previous = error_context_stack;
+    error_context_stack = &scripterrcontext;
+
     /*
      * Parse the SQL string into a list of raw parse trees.
      */
@@ -780,6 +823,8 @@ execute_sql_string(const char *sql)

     /* Be sure to advance the command counter after the last script command */
     CommandCounterIncrement();
+
+    error_context_stack = scripterrcontext.previous;
 }

 /*
@@ -1054,7 +1099,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
         /* And now back to C string */
         c_sql = text_to_cstring(DatumGetTextPP(t_sql));

-        execute_sql_string(c_sql);
+        execute_sql_string(c_sql, filename);
     }
     PG_FINALLY();
     {

pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: Opinion poll: Sending an automated email to a thread when it gets added to the commitfest
Next
From: Alexander Korotkov
Date:
Subject: Re: [PATCH] Support Int64 GUCs