I thought of something I'd overlooked in my original proposal for error-
handling upgrades: what about reporting where an error occurs in a PL
function?

Currently, plpgsql has a hack that prints a separate WARNING giving
the error location, but this is pretty darn ugly.  It should be part of
the error report message to begin with.

I can see how to create a mechanism that gathers the data (details below
if you care), but I'm not too sure how it should be reported to the
client --- ie, what's the protocol message?

This seems nonobvious because (a) the appropriate info might vary
depending on the PL language involved, and (b) when there are several
nested PL functions, we probably want to include the whole stack trace.

Here is an example of what you get right now:

regression=# create function foo (int, int) returns int as '
regression'# begin
regression'# return $1 / $2;
regression'# end' language plpgsql;
CREATE FUNCTION
regression=# select foo(10,0);
WARNING:  Error occurred while executing PL/pgSQL function foo
WARNING:  line 2 at return
ERROR:  division by zero
regression=# create function bar (int, int) returns int as '
regression'# begin
regression'# return foo($1,$2);
regression'# end' language plpgsql;
CREATE FUNCTION
regression=# select bar(10,0);
WARNING:  Error occurred while executing PL/pgSQL function foo
WARNING:  line 2 at return
ERROR:  division by zero
regression=#

Note the lack of any info about bar() in the second case --- this seems
like a bad omission.

I am visualizing some display on the order of

ERROR:  division by zero
WHERE: PL/pgSQL function foo, line 2 at return
WHERE: PL/pgSQL function bar, line 2 at return

but I'm not sure exactly how it should look, nor about the
protocol-message representation.  Should the 'where' entries be sent as
repeated instances of a single field type?  (This seems unpleasant; I'd
prefer not to place any semantic significance on the ordering of fields
within an error message, yet we'd certainly have to do so if we repeat
a field to represent a call stack.)  The alternative is to put all the
call stack levels into a single field, which seems to mean multiple
lines in that field, which goes against the notion that we should avoid
attaching any semantic meaning to the formatting of the contents of a
text field.  In any case, we probably can't use any representation more
specific than a text string for each entry in the call stack, because
of the likelihood that the contents will vary across PLs.

Any thoughts about how to handle all this?  And what should we call this
field, anyway?


As for actually collecting the info, I'm thinking of a stack of "error
context" records, say

        typedef struct ErrorContext {
                struct ErrorContext *previous;
                void (*callback) (void *arg);
                void *arg;
        } ErrorContext;

        extern ErrorContext *error_context_stack;

Any given PL would push an item onto this stack at function entry, and
pop it off again at function return.  (No palloc is needed: the record
is just a local variable in the PL handler.)  If an error needs to be
reported, after errstart() sets up the error parameter collection
structure it traverses the error_context_stack chain and calls each
callback with the specified arg (which the callback can use to access
the PL's info about the current function).  The callback can then use
the usual optional-error-info-addition routines to add information to
the error parameters, something like
        errfunclocation("PL/pgSQL function %s, line %d at %s",
                        funcstate->name, funcstate->lineno, ...);
We'd have to define errfunclocation to do the Right Thing when called
multiple times in a single error report, but that seems easy.

                        regards, tom lane

---------------------------(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