void elog(int elevel, const char *fmt, ...) { va_list args; bool ok; size_t len; pgutErrorData *edata; if (elevel < pgut_abort_level && !log_required(elevel, pgut_log_level)) return; edata = pgut_errinit(elevel); do { va_start(args, fmt); ok = appendStringInfoVA(&edata->msg, fmt, args); va_end(args); } while (!ok); len = strlen(fmt); if (len > 2 && strcmp(fmt + len - 2, ": ") == 0) appendStringInfoString(&edata->msg, strerror(edata->save_errno)); trimStringBuffer(&edata->msg); pgut_errfinish(true); }
/* appendStringInfoVA + automatic buffer extension */ static void appendStringInfoVA_s(StringInfo str, const char *fmt, va_list args) { #if PG_VERSION_NUM >= 90400 int needed; while ((needed = appendStringInfoVA(str, fmt, args)) > 0) { /* Double the buffer size and try again. */ enlargeStringInfo(str, needed); } #else while (!appendStringInfoVA(str, fmt, args)) { /* Double the buffer size and try again. */ enlargeStringInfo(str, str->maxlen); } #endif }
int errdetail_impl(const char* fmt, ...) { StringInfoData buf; initStringInfo(&buf); va_list args; va_start(args, fmt); appendStringInfoVA(&buf, fmt, args); strncpy(lastErrorMsg, buf.data, sizeof(lastErrorMsg) / sizeof(lastErrorMsg[0])); pfree(buf.data); return 0; }
int errdetail(const char *fmt,...) { pgutErrorData *edata = getErrorData(); va_list args; bool ok; do { va_start(args, fmt); ok = appendStringInfoVA(&edata->detail, fmt, args); va_end(args); } while (!ok); trimStringBuffer(&edata->detail); return 0; /* return value does not matter */ }
/* * appendStringInfo * * Format text data under the control of fmt (an sprintf-style format string) * and append it to whatever is already in str. More space is allocated * to str if necessary. This is sort of like a combination of sprintf and * strcat. */ void appendStringInfo(StringInfo str, const char *fmt,...) { for (;;) { va_list args; bool success; /* Try to format the data. */ va_start(args, fmt); success = appendStringInfoVA(str, fmt, args); va_end(args); if (success) break; /* Double the buffer size and try again. */ enlargeStringInfo(str, str->maxlen); } }
/* * appendStringInfo * * Format text data under the control of fmt (an sprintf-style format string) * and append it to whatever is already in str. More space is allocated * to str if necessary. This is sort of like a combination of sprintf and * strcat. */ void appendStringInfo(StringInfo str, const char *fmt,...) { for (;;) { va_list args; int needed; /* Try to format the data. */ va_start(args, fmt); needed = appendStringInfoVA(str, fmt, args); va_end(args); if (needed == 0) break; /* success */ /* Increase the buffer size and try again. */ enlargeStringInfo(str, needed); } }
/* * Error handler for libxml error messages */ static void xml_error_handler(void *ctxt, const char *msg,...) { /* Append the formatted text to xml_err_buf */ for (;;) { va_list args; bool success; /* Try to format the data. */ va_start(args, msg); success = appendStringInfoVA(xml_error_buf, msg, args); va_end(args); if (success) break; /* Double the buffer size and try again. */ enlargeStringInfo(xml_error_buf, xml_error_buf->maxlen); } }
int errmsg(const char *fmt,...) { pgutErrorData *edata = getErrorData(); va_list args; size_t len; bool ok; do { va_start(args, fmt); ok = appendStringInfoVA(&edata->msg, fmt, args); va_end(args); } while (!ok); len = strlen(fmt); if (len > 2 && strcmp(fmt + len - 2, ": ") == 0) appendStringInfoString(&edata->msg, strerror(edata->save_errno)); trimStringBuffer(&edata->msg); return 0; /* return value does not matter */ }
/* * Emit a PG error or notice, together with any available info about * the current Python error, previously set by PLy_exception_set(). * This should be used to propagate Python errors into PG. If fmt is * NULL, the Python error becomes the primary error message, otherwise * it becomes the detail. If there is a Python traceback, it is put * in the context. */ void PLy_elog(int elevel, const char *fmt,...) { char *xmsg; char *tbmsg; int tb_depth; StringInfoData emsg; PyObject *exc, *val, *tb; const char *primary = NULL; int sqlerrcode = 0; char *detail = NULL; char *hint = NULL; char *query = NULL; int position = 0; char *schema_name = NULL; char *table_name = NULL; char *column_name = NULL; char *datatype_name = NULL; char *constraint_name = NULL; PyErr_Fetch(&exc, &val, &tb); if (exc != NULL) { PyErr_NormalizeException(&exc, &val, &tb); if (PyErr_GivenExceptionMatches(val, PLy_exc_spi_error)) PLy_get_spi_error_data(val, &sqlerrcode, &detail, &hint, &query, &position, &schema_name, &table_name, &column_name, &datatype_name, &constraint_name); else if (PyErr_GivenExceptionMatches(val, PLy_exc_error)) PLy_get_error_data(val, &sqlerrcode, &detail, &hint, &schema_name, &table_name, &column_name, &datatype_name, &constraint_name); else if (PyErr_GivenExceptionMatches(val, PLy_exc_fatal)) elevel = FATAL; } /* this releases our refcount on tb! */ PLy_traceback(exc, val, tb, &xmsg, &tbmsg, &tb_depth); if (fmt) { initStringInfo(&emsg); for (;;) { va_list ap; int needed; va_start(ap, fmt); needed = appendStringInfoVA(&emsg, dgettext(TEXTDOMAIN, fmt), ap); va_end(ap); if (needed == 0) break; enlargeStringInfo(&emsg, needed); } primary = emsg.data; /* Since we have a format string, we cannot have a SPI detail. */ Assert(detail == NULL); /* If there's an exception message, it goes in the detail. */ if (xmsg) detail = xmsg; } else { if (xmsg) primary = xmsg; } PG_TRY(); { ereport(elevel, (errcode(sqlerrcode ? sqlerrcode : ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg_internal("%s", primary ? primary : "no exception data"), (detail) ? errdetail_internal("%s", detail) : 0, (tb_depth > 0 && tbmsg) ? errcontext("%s", tbmsg) : 0, (hint) ? errhint("%s", hint) : 0, (query) ? internalerrquery(query) : 0, (position) ? internalerrposition(position) : 0, (schema_name) ? err_generic_string(PG_DIAG_SCHEMA_NAME, schema_name) : 0, (table_name) ? err_generic_string(PG_DIAG_TABLE_NAME, table_name) : 0, (column_name) ? err_generic_string(PG_DIAG_COLUMN_NAME, column_name) : 0, (datatype_name) ? err_generic_string(PG_DIAG_DATATYPE_NAME, datatype_name) : 0, (constraint_name) ? err_generic_string(PG_DIAG_CONSTRAINT_NAME, constraint_name) : 0)); } PG_CATCH(); { if (fmt) pfree(emsg.data); if (xmsg) pfree(xmsg); if (tbmsg) pfree(tbmsg); Py_XDECREF(exc); Py_XDECREF(val); PG_RE_THROW(); } PG_END_TRY(); if (fmt) pfree(emsg.data); if (xmsg) pfree(xmsg); if (tbmsg) pfree(tbmsg); Py_XDECREF(exc); Py_XDECREF(val); }
/* * Emit a PG error or notice, together with any available info about * the current Python error, previously set by PLy_exception_set(). * This should be used to propagate Python errors into PG. If fmt is * NULL, the Python error becomes the primary error message, otherwise * it becomes the detail. If there is a Python traceback, it is put * in the context. */ void PLy_elog(int elevel, const char *fmt,...) { char *xmsg; char *tbmsg; int tb_depth; StringInfoData emsg; PyObject *exc, *val, *tb; const char *primary = NULL; int sqlerrcode = 0; char *detail = NULL; char *hint = NULL; char *query = NULL; int position = 0; PyErr_Fetch(&exc, &val, &tb); if (exc != NULL) { if (PyErr_GivenExceptionMatches(val, PLy_exc_spi_error)) PLy_get_spi_error_data(val, &sqlerrcode, &detail, &hint, &query, &position); else if (PyErr_GivenExceptionMatches(val, PLy_exc_fatal)) elevel = FATAL; } PyErr_Restore(exc, val, tb); PLy_traceback(&xmsg, &tbmsg, &tb_depth); if (fmt) { initStringInfo(&emsg); for (;;) { va_list ap; bool success; va_start(ap, fmt); success = appendStringInfoVA(&emsg, dgettext(TEXTDOMAIN, fmt), ap); va_end(ap); if (success) break; enlargeStringInfo(&emsg, emsg.maxlen); } primary = emsg.data; /* Since we have a format string, we cannot have a SPI detail. */ Assert(detail == NULL); /* If there's an exception message, it goes in the detail. */ if (xmsg) detail = xmsg; } else { if (xmsg) primary = xmsg; } PG_TRY(); { ereport(elevel, (errcode(sqlerrcode ? sqlerrcode : ERRCODE_INTERNAL_ERROR), errmsg_internal("%s", primary ? primary : "no exception data"), (detail) ? errdetail_internal("%s", detail) : 0, (tb_depth > 0 && tbmsg) ? errcontext("%s", tbmsg) : 0, (hint) ? errhint("%s", hint) : 0, (query) ? internalerrquery(query) : 0, (position) ? internalerrposition(position) : 0)); } PG_CATCH(); { if (fmt) pfree(emsg.data); if (xmsg) pfree(xmsg); if (tbmsg) pfree(tbmsg); PG_RE_THROW(); } PG_END_TRY(); if (fmt) pfree(emsg.data); if (xmsg) pfree(xmsg); if (tbmsg) pfree(tbmsg); }