Sending messages

A UDx can handle a problem by reporting an error and terminating execution, but in some cases you might want to send a warning and proceed.

A UDx can handle a problem by reporting an error and terminating execution, but in some cases you might want to send a warning and proceed. For example, a UDx might ignore or use a default for an unexpected input and report that it did so. The C++ and Python messaging APIs support reporting messages at different severity levels.

A UDx has access to a ServerInterface instance. This class has the following methods for reporting messages, in order of severity:

  • reportError (also terminates execution)

  • reportWarning

  • reportNotice

  • reportInfo

Each method produces messages with the following components:

  • ID code: an identification code, any integer. This code does not interact with Vertica error codes.

  • Message string: a succinct description of the issue.

  • Optional details string: provides more contextual information.

  • Optional hint string: provides other guidance.

Duplicate messages are condensed into a single report if they have the same code and message string, even if the details and hint strings differ.

Constructing messages

The UDx should report errors immediately, usually during a process call. For all other message types, record information during processing and call the reporting methods from the UDx's destroy method. The other reporting methods do not produce output if called during processing.

The process of constructing messages is language-specific.

C++

Each ServerInterface reporting method takes a ClientMessage argument. The ClientMessage class has the following methods to set the code and message, detail, and hint:

  • makeMessage: sets the ID code and message string.

  • setDetail: sets the optional detail string.

  • setHint: sets the optional hint string.

These method calls can be chained to simplify creating and passing the message.

All strings support printf-style arguments and formatting.

In the following example, a function records issues in processBlock and reports them in destroy:


class PositiveIdentity : public Vertica::ScalarFunction
    {
public:
    using ScalarFunction::destroy;
    bool hitNotice = false;

    virtual void processBlock(Vertica::ServerInterface &srvInterface,
                              Vertica::BlockReader &arg_reader,
                              Vertica::BlockWriter &res_writer)
    {
        do {
            const Vertica::vint a = arg_reader.getIntRef(0);
            if (a < 0 && a != vint_null) {
                hitNotice = true;
                res_writer.setInt(null);
            } else {
                res_writer.setInt(a);
            }
            res_writer.next();
        } while (arg_reader.next());
    }

    virtual void destroy(ServerInterface &srvInterface,
                         const SizedColumnTypes &argTypes) override
    {
        if (hitNotice) {
            ClientMessage msg = ClientMessage::makeMessage(100, "Passed negative argument")
                                .setDetail("Value set to null");
            srvInterface.reportNotice(msg);
        }
    }
}

Python

Each ServerInterface reporting method has the following positional and keyword arguments:

  • idCode: integer ID code, positional argument.

  • message: message text, positional argument.

  • hint: optional hint text, keyword argument.

  • detail: optional detail text, keyword argument.

All arguments support str.format() and f-string formatting.

In the following example, a function records issues in processBlock and reports them in destroy:


class PositiveIdentity(vertica_sdk.ScalarFunction):
    def __init__(self):
        self.hitNotice = False

    def processBlock(self, server_interface, arg_reader, res_writer):
        while True:
            arg = arg_reader.getInt(0)
            if arg < 0 and arg is not None:
                self.hitNotice = True
                res_writer.setNull()
            else:
                res_writer.setInt(arg)
            res_writer.next()
            if not arg_reader.next():
                break

    def destroy(self, srv, argType):
        if self.hitNotice:
            srv.reportNotice(100, "Passed negative arguement", detail="Value set to null")
        return

API

Before calling a ServerInterface reporting method, construct and populate a message with the ClientMessage class.

The ServerInterface API provides the following methods for reporting messages:


// ClientMessage methods
template<typename... Argtypes>
static ClientMessage makeMessage(int errorcode, const char *fmt, Argtypes&&... args);

template <typename... Argtypes>
ClientMessage & setDetail(const char *fmt, Argtypes&&... args);

template <typename... Argtypes>
ClientMessage & setHint(const char *fmt, Argtypes&&... args);

// ServerInterface reporting methods
virtual void reportError(ClientMessage msg);

virtual void reportInfo(ClientMessage msg);

virtual void reportNotice(ClientMessage msg);

virtual void reportWarning(ClientMessage msg);

The ServerInterface API provides the following methods for reporting messages:


def reportError(self, code, text, hint='', detail=''):

def reportInfo(self, code, text, hint='', detail=''):

def reportNotice(self, code, text, hint='', detail=''):

def reportWarning(self, code, text, hint='', detail=''):