Neaten up our choices of SQLSTATEs for XML-related errors.
authorTom Lane <[email protected]>
Tue, 24 Sep 2024 16:59:43 +0000 (12:59 -0400)
committerTom Lane <[email protected]>
Tue, 24 Sep 2024 16:59:56 +0000 (12:59 -0400)
When our XML-handling modules were first written, the SQL standard
lacked any error codes that were particularly intended for XML
error conditions.  Unsurprisingly, this led to some rather random
choices of errcodes in those modules.  Now the standard has a whole
SQLSTATE class, "Class 10 - XQuery Error", with a reasonably large
selection of relevant-looking errcodes.

In this patch I've chosen one fairly generic code defined by the
standard, 10608 = invalid_argument_for_xquery, and used it where
it seemed appropriate.  I've also made an effort to replace
ERRCODE_INTERNAL_ERROR everywhere it was not clearly reporting
a coding problem; in particular, many of the existing uses look
like they can fairly be reported as ERRCODE_OUT_OF_MEMORY.

It might be interesting to try to map libxml2's error codes into
the standard's new collection, but I've not undertaken that here.

Discussion: https://postgr.es/m/417250.1726341268@sss.pgh.pa.us

contrib/xml2/xpath.c
contrib/xml2/xslt_proc.c
src/backend/utils/adt/xml.c
src/backend/utils/errcodes.txt

index 0fdf735fafe9877ccc58c5cbf0fe1b0fa5dc57f4..ef78aa00c88607d28a7c3d4377b8faaa4a4c9302 100644 (file)
@@ -388,7 +388,7 @@ pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
            /* compile the path */
            comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
            if (comppath == NULL)
-               xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+               xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                            "XPath Syntax Error");
 
            /* Now evaluate the path expression. */
@@ -652,7 +652,7 @@ xpath_table(PG_FUNCTION_ARGS)
                        comppath = xmlXPathCtxtCompile(ctxt, xpaths[j]);
                        if (comppath == NULL)
                            xml_ereport(xmlerrcxt, ERROR,
-                                       ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+                                       ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                                        "XPath Syntax Error");
 
                        /* Now evaluate the path expression. */
index f30a3a42c03e9328d25f44a5d87b8eee76919938..e761ca5cb5f29191dde00ebbca7551919e4ae497 100644 (file)
@@ -90,7 +90,7 @@ xslt_process(PG_FUNCTION_ARGS)
                                XML_PARSE_NOENT);
 
        if (doctree == NULL)
-           xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
                        "error parsing XML document");
 
        /* Same for stylesheet */
@@ -99,14 +99,14 @@ xslt_process(PG_FUNCTION_ARGS)
                              XML_PARSE_NOENT);
 
        if (ssdoc == NULL)
-           xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
                        "error parsing stylesheet as XML document");
 
        /* After this call we need not free ssdoc separately */
        stylesheet = xsltParseStylesheetDoc(ssdoc);
 
        if (stylesheet == NULL)
-           xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                        "failed to parse stylesheet");
 
        xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
@@ -141,7 +141,7 @@ xslt_process(PG_FUNCTION_ARGS)
                                          NULL, NULL, xslt_ctxt);
 
        if (restree == NULL)
-           xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                        "failed to apply stylesheet");
 
        resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
index 41b1a5c6b0bf5868c975d3f1ac057ef3d79e88b3..040a89626391ee13cab79b699ef00adb1561febb 100644 (file)
@@ -344,7 +344,7 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
    }
 
    ereport(WARNING,
-           errcode(ERRCODE_INTERNAL_ERROR),
+           errcode(ERRCODE_DATA_CORRUPTED),
            errmsg_internal("could not parse XML declaration in stored value"),
            errdetail_for_xml_code(res_code));
 #endif
@@ -742,7 +742,7 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
        {
            /* If it's a document, saving is easy. */
            if (xmlSaveDoc(ctxt, doc) == -1 || xmlerrcxt->err_occurred)
-               xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+               xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
                            "could not save document to xmlBuffer");
        }
        else if (content_nodes != NULL)
@@ -785,7 +785,7 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
                    if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)
                    {
                        xmlFreeNode(newline);
-                       xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+                       xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
                                    "could not save newline to xmlBuffer");
                    }
                }
@@ -793,7 +793,7 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
                if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)
                {
                    xmlFreeNode(newline);
-                   xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+                   xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
                                "could not save content to xmlBuffer");
                }
            }
@@ -1004,7 +1004,7 @@ xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null)
 
    if (pg_strcasecmp(target, "xml") == 0)
        ereport(ERROR,
-               (errcode(ERRCODE_SYNTAX_ERROR), /* really */
+               (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
                 errmsg("invalid XML processing instruction"),
                 errdetail("XML processing instruction target name cannot be \"%s\".", target)));
 
@@ -4383,7 +4383,7 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
    xpath_len = VARSIZE_ANY_EXHDR(xpath_expr_text);
    if (xpath_len == 0)
        ereport(ERROR,
-               (errcode(ERRCODE_DATA_EXCEPTION),
+               (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
                 errmsg("empty XPath expression")));
 
    string = pg_xmlCharStrndup(datastr, len);
@@ -4456,7 +4456,7 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
         */
        xpathcomp = xmlXPathCtxtCompile(xpathctx, xpath_expr);
        if (xpathcomp == NULL || xmlerrcxt->err_occurred)
-           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                        "invalid XPath expression");
 
        /*
@@ -4468,7 +4468,7 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
         */
        xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
        if (xpathobj == NULL || xmlerrcxt->err_occurred)
-           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+           xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                        "could not create XPath object");
 
        /*
@@ -4798,7 +4798,7 @@ XmlTableSetNamespace(TableFuncScanState *state, const char *name, const char *ur
    if (xmlXPathRegisterNs(xtCxt->xpathcxt,
                           pg_xmlCharStrndup(name, strlen(name)),
                           pg_xmlCharStrndup(uri, strlen(uri))))
-       xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_DATA_EXCEPTION,
+       xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                    "could not set XML namespace");
 #else
    NO_XML_SUPPORT();
@@ -4820,7 +4820,7 @@ XmlTableSetRowFilter(TableFuncScanState *state, const char *path)
 
    if (*path == '\0')
        ereport(ERROR,
-               (errcode(ERRCODE_DATA_EXCEPTION),
+               (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
                 errmsg("row path filter must not be empty string")));
 
    xstr = pg_xmlCharStrndup(path, strlen(path));
@@ -4830,7 +4830,7 @@ XmlTableSetRowFilter(TableFuncScanState *state, const char *path)
 
    xtCxt->xpathcomp = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
    if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)
-       xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_SYNTAX_ERROR,
+       xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                    "invalid XPath expression");
 #else
    NO_XML_SUPPORT();
@@ -4854,7 +4854,7 @@ XmlTableSetColumnFilter(TableFuncScanState *state, const char *path, int colnum)
 
    if (*path == '\0')
        ereport(ERROR,
-               (errcode(ERRCODE_DATA_EXCEPTION),
+               (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
                 errmsg("column path filter must not be empty string")));
 
    xstr = pg_xmlCharStrndup(path, strlen(path));
@@ -4864,7 +4864,7 @@ XmlTableSetColumnFilter(TableFuncScanState *state, const char *path, int colnum)
 
    xtCxt->xpathscomp[colnum] = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
    if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)
-       xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_DATA_EXCEPTION,
+       xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                    "invalid XPath expression");
 #else
    NO_XML_SUPPORT();
@@ -4891,7 +4891,7 @@ XmlTableFetchRow(TableFuncScanState *state)
    {
        xtCxt->xpathobj = xmlXPathCompiledEval(xtCxt->xpathcomp, xtCxt->xpathcxt);
        if (xtCxt->xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
-           xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+           xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                        "could not create XPath object");
 
        xtCxt->row_count = 0;
@@ -4955,7 +4955,7 @@ XmlTableGetValue(TableFuncScanState *state, int colnum,
        /* Evaluate column path */
        xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt);
        if (xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
-           xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
+           xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
                        "could not create XPath object");
 
        /*
index b43a24d4bcdb99891cce59ea5c8fc902343aa7f6..97d91eb1e9ea19fb40029d3069d56ce1b12e0888 100644 (file)
@@ -141,6 +141,12 @@ Section: Class 0Z - Diagnostics Exception
 0Z000    E    ERRCODE_DIAGNOSTICS_EXCEPTION                                  diagnostics_exception
 0Z002    E    ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER    stacked_diagnostics_accessed_without_active_handler
 
+Section: Class 10 - XQuery Error
+
+# recent SQL versions define quite a few codes in this class, but for now
+# we are only using this generic one
+10608    E    ERRCODE_INVALID_ARGUMENT_FOR_XQUERY                            invalid_argument_for_xquery
+
 Section: Class 20 - Case Not Found
 
 20000    E    ERRCODE_CASE_NOT_FOUND                                         case_not_found