From 621a4782ee2ad07219b06ff87efd785b83375fd7 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Wed, 4 Oct 2023 14:44:22 +0200 Subject: [PATCH] Improve error management --- meos/include/general/error.h | 77 ------ meos/include/general/temporal.h | 2 +- meos/include/meos.h | 41 +++ meos/postgres/common/pgfnames.c | 17 +- meos/postgres/lib/simplehash.h | 3 +- meos/postgres/postgres.h | 7 - meos/postgres/timezone/pgtz.c | 15 +- meos/postgres/utils/datetime.c | 120 +++++---- meos/postgres/utils/float.c | 10 +- meos/postgres/utils/formatting.c | 233 +++++++++++++---- meos/postgres/utils/numutils.c | 14 +- meos/postgres/utils/timestamp.c | 17 +- meos/src/general/error.c | 434 ++++++++++++++++--------------- meos/src/point/pgis_call.c | 6 +- 14 files changed, 571 insertions(+), 425 deletions(-) delete mode 100644 meos/include/general/error.h diff --git a/meos/include/general/error.h b/meos/include/general/error.h deleted file mode 100644 index 820d6af990..0000000000 --- a/meos/include/general/error.h +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * - * This MobilityDB code is provided under The PostgreSQL License. - * Copyright (c) 2016-2023, Université libre de Bruxelles and MobilityDB - * contributors - * - * MobilityDB includes portions of PostGIS version 3 source code released - * under the GNU General Public License (GPLv2 or later). - * Copyright (c) 2001-2023, PostGIS contributors - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose, without fee, and without a written - * agreement is hereby granted, provided that the above copyright notice and - * this paragraph and the following two paragraphs appear in all copies. - * - * IN NO EVENT SHALL UNIVERSITE LIBRE DE BRUXELLES BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING - * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, - * EVEN IF UNIVERSITE LIBRE DE BRUXELLES HAS BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * UNIVERSITE LIBRE DE BRUXELLES SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON - * AN "AS IS" BASIS, AND UNIVERSITE LIBRE DE BRUXELLES HAS NO OBLIGATIONS TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - *****************************************************************************/ - -/** - * @file - * @brief Error handling. - */ - -/* C */ -#include -/* MEOS */ -#include - -typedef enum -{ - MEOS_SUCCESS = 0, // Successful operation - - MEOS_ERR_INTERNAL_ERROR = 1, // Unspecified internal error - MEOS_ERR_INTERNAL_TYPE_ERROR = 2, // Internal type error - MEOS_ERR_VALUE_OUT_OF_RANGE = 3, // Internal out of range error - MEOS_ERR_DIVISION_BY_ZERO = 4, // Internal division by zero error - MEOS_ERR_MEMORY_ALLOC_ERROR = 5, // Internal malloc error - MEOS_ERR_AGGREGATION_ERROR = 6, // Internal aggregation error - MEOS_ERR_DIRECTORY_ERROR = 7, // Internal directory error - MEOS_ERR_FILE_ERROR = 8, // Internal file error - - MEOS_ERR_INVALID_ARG = 10, // Invalid argument - MEOS_ERR_INVALID_ARG_TYPE = 11, // Invalid argument type - MEOS_ERR_INVALID_ARG_VALUE = 12, // Invalid argument value - - MEOS_ERR_MFJSON_INPUT = 20, // MFJSON input error - MEOS_ERR_MFJSON_OUTPUT = 21, // MFJSON output error - MEOS_ERR_TEXT_INPUT = 22, // Text input error - MEOS_ERR_TEXT_OUTPUT = 23, // Text output error - MEOS_ERR_WKB_INPUT = 24, // WKB input error - MEOS_ERR_WKB_OUTPUT = 25, // WKB output error - MEOS_ERR_GEOJSON_INPUT = 26, // GEOJSON input error - MEOS_ERR_GEOJSON_OUTPUT = 27, // GEOJSON output error - -} errorCode; - -extern void meos_error(int errlevel, int errcode, char *format, ...); - -/* Set or read error level */ - -extern int mobdb_errno(void); -extern int mobdb_errno_set(int err); -extern int mobdb_errno_restore(int err); -extern int mobdb_errno_reset(void); - -/*****************************************************************************/ diff --git a/meos/include/general/temporal.h b/meos/include/general/temporal.h index 1bca86d54e..83e056fb49 100644 --- a/meos/include/general/temporal.h +++ b/meos/include/general/temporal.h @@ -37,7 +37,7 @@ /* PostgreSQL */ #include /* MEOS */ -#include "general/error.h" +#include #include "general/meos_catalog.h" #include "general/span.h" #include "general/set.h" diff --git a/meos/include/meos.h b/meos/include/meos.h index 71eca2a217..a8a47feda8 100644 --- a/meos/include/meos.h +++ b/meos/include/meos.h @@ -277,6 +277,47 @@ typedef struct SkipListElem *elems; } SkipList; +/***************************************************************************** + * Error codes + *****************************************************************************/ + +typedef enum +{ + MEOS_SUCCESS = 0, // Successful operation + + MEOS_ERR_INTERNAL_ERROR = 1, // Unspecified internal error + MEOS_ERR_INTERNAL_TYPE_ERROR = 2, // Internal type error + MEOS_ERR_VALUE_OUT_OF_RANGE = 3, // Internal out of range error + MEOS_ERR_DIVISION_BY_ZERO = 4, // Internal division by zero error + MEOS_ERR_MEMORY_ALLOC_ERROR = 5, // Internal malloc error + MEOS_ERR_AGGREGATION_ERROR = 6, // Internal aggregation error + MEOS_ERR_DIRECTORY_ERROR = 7, // Internal directory error + MEOS_ERR_FILE_ERROR = 8, // Internal file error + + MEOS_ERR_INVALID_ARG = 10, // Invalid argument + MEOS_ERR_INVALID_ARG_TYPE = 11, // Invalid argument type + MEOS_ERR_INVALID_ARG_VALUE = 12, // Invalid argument value + + MEOS_ERR_MFJSON_INPUT = 20, // MFJSON input error + MEOS_ERR_MFJSON_OUTPUT = 21, // MFJSON output error + MEOS_ERR_TEXT_INPUT = 22, // Text input error + MEOS_ERR_TEXT_OUTPUT = 23, // Text output error + MEOS_ERR_WKB_INPUT = 24, // WKB input error + MEOS_ERR_WKB_OUTPUT = 25, // WKB output error + MEOS_ERR_GEOJSON_INPUT = 26, // GEOJSON input error + MEOS_ERR_GEOJSON_OUTPUT = 27, // GEOJSON output error + +} errorCode; + +extern void meos_error(int errlevel, int errcode, char *format, ...); + +/* Set or read error level */ + +extern int mobdb_errno(void); +extern int mobdb_errno_set(int err); +extern int mobdb_errno_restore(int err); +extern int mobdb_errno_reset(void); + /***************************************************************************** * Initialization of the MEOS library *****************************************************************************/ diff --git a/meos/postgres/common/pgfnames.c b/meos/postgres/common/pgfnames.c index 0bd78bab6b..405ef50be6 100644 --- a/meos/postgres/common/pgfnames.c +++ b/meos/postgres/common/pgfnames.c @@ -16,6 +16,8 @@ #include "postgres.h" +#include "../../include/meos.h" + /* * pgfnames * @@ -35,7 +37,8 @@ pgfnames(const char *path) dir = opendir(path); if (dir == NULL) { - elog(WARNING, "could not open directory \"%s\": %m", path); + meos_error(WARNING, MEOS_ERR_DIRECTORY_ERROR, + "could not open directory \"%s\": %m", path); return NULL; } @@ -55,12 +58,20 @@ pgfnames(const char *path) } if (errno) - elog(WARNING, "could not read directory \"%s\": %m", path); + { + meos_error(WARNING, MEOS_ERR_DIRECTORY_ERROR, + "could not read directory \"%s\": %m", path); + return NULL; + } filenames[numnames] = NULL; if (closedir(dir)) - elog(WARNING, "could not close directory \"%s\": %m", path); + { + meos_error(WARNING, MEOS_ERR_DIRECTORY_ERROR, + "could not close directory \"%s\": %m", path); + return NULL; + } return filenames; } diff --git a/meos/postgres/lib/simplehash.h b/meos/postgres/lib/simplehash.h index b6fc9b5df6..d45305b697 100644 --- a/meos/postgres/lib/simplehash.h +++ b/meos/postgres/lib/simplehash.h @@ -296,7 +296,8 @@ SH_SCOPE void SH_STAT(SH_TYPE * tb); #define sh_error(...) pg_fatal(__VA_ARGS__) #define sh_log(...) pg_log_info(__VA_ARGS__) #else -#define sh_error(...) elog(ERROR, __VA_ARGS__) +// #define sh_error(...) elog(ERROR, __VA_ARGS__) +#define sh_error(...) meos_error(ERROR, MEOS_ERR_INTERNAL_ERROR, __VA_ARGS__) // /* MEOS */ // #define sh_log(...) elog(LOG, __VA_ARGS__) #endif diff --git a/meos/postgres/postgres.h b/meos/postgres/postgres.h index ba346bc3ee..9e4ed9d652 100644 --- a/meos/postgres/postgres.h +++ b/meos/postgres/postgres.h @@ -62,13 +62,6 @@ #define ERROR 21 /* user error - abort transaction; return to known state */ #endif #define EXIT_FAILURE 1 -#define elog(error, ...) \ - do { \ - fprintf (stderr, __VA_ARGS__); \ - fprintf (stderr, "\n"); \ - if (error == ERROR) \ - exit(EXIT_FAILURE); \ - } while(0); /* MEOS: redefining palloc0, palloc, and pfree */ #if MEOS diff --git a/meos/postgres/timezone/pgtz.c b/meos/postgres/timezone/pgtz.c index 692b27e4d8..8149cd7480 100644 --- a/meos/postgres/timezone/pgtz.c +++ b/meos/postgres/timezone/pgtz.c @@ -22,6 +22,8 @@ #include "utils/timestamp_def.h" #include "pgtz.h" +#include "../../include/meos.h" + /** * Structure to represent the timezone cache hash table, which extends * the `ENTRY` structure used by hsearch @@ -199,7 +201,8 @@ ReadDir(DIR *dir, const char *dirname) /* Give a generic message for AllocateDir failure, if caller didn't */ if (dir == NULL) { - elog(ERROR, "could not open directory \"%s\": %m", dirname); + meos_error(ERROR, MEOS_ERR_DIRECTORY_ERROR, + "could not open directory \"%s\": %m", dirname); return NULL; } @@ -208,7 +211,8 @@ ReadDir(DIR *dir, const char *dirname) return dent; if (errno) - elog(ERROR, "could not read directory \"%s\": %m", dirname); + meos_error(ERROR, MEOS_ERR_DIRECTORY_ERROR, + "could not read directory \"%s\": %m", dirname); return NULL; } @@ -335,7 +339,9 @@ pg_tzset(const char *name) if (!tzparse(uppername, &tzstate, true)) { /* This really, really should not happen ... */ - elog(ERROR, "could not initialize GMT time zone"); + meos_error(ERROR, MEOS_ERR_INTERNAL_ERROR, + "could not initialize GMT time zone"); + return NULL; } /* Use uppercase name as canonical */ strcpy(canonname, uppername); @@ -428,7 +434,8 @@ meos_initialize_timezone(const char *tz_str) session_timezone = pg_tzset(tz_str); if (! session_timezone) - elog(ERROR, "Failed to initialize local timezone"); + meos_error(ERROR, MEOS_ERR_INTERNAL_ERROR, + "Failed to initialize local timezone"); return; } diff --git a/meos/postgres/utils/datetime.c b/meos/postgres/utils/datetime.c index 8272033dcf..6f15412a75 100644 --- a/meos/postgres/utils/datetime.c +++ b/meos/postgres/utils/datetime.c @@ -22,6 +22,8 @@ #include "utils/datetime.h" #include "utils/date.h" +#include "../../include/meos.h" + static const datetkn *datebsearch(const char *key, const datetkn *base, int nel); /* Defined below */ @@ -35,8 +37,7 @@ static int DecodeTime(char *str, int fmask, int range, static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits); -static int DecodeNumberField(int len, char *str, - int fmask, int *tmask, +static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits); static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp); static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, @@ -386,9 +387,12 @@ GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp) * really expect any error here, since current time surely ought to be * within range, but check just for sanity's sake. */ - if (timestamp2tm(cur_ts, &cache_tz, &cache_tm, &cache_fsec, - NULL, session_timezone) != 0) - elog(ERROR, "timestamp out of range"); + if (timestamp2tm(cur_ts, &cache_tz, &cache_tm, &cache_fsec, NULL, + session_timezone) != 0) + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, "timestamp out of range"); + return; + } /* OK, so mark the cache valid. */ cache_ts = cur_ts; @@ -797,25 +801,25 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen, * 1997-05-27 */ int -DecodeDateTime(char **field, int *ftype, int nf, - int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp) +DecodeDateTime(char **field, int *ftype, int nf, int *dtype, + struct pg_tm *tm, fsec_t *fsec, int *tzp) { - int fmask = 0, - tmask, - type; - int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */ - int i; - int val; - int dterr; - int mer = HR24; - bool haveTextMonth = false; - bool isjulian = false; - bool is2digits = false; - bool bc = false; - pg_tz *namedTz = NULL; - pg_tz *abbrevTz = NULL; - pg_tz *valtz; - char *abbrev = NULL; + int fmask = 0, + tmask, + type; + int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */ + int i; + int val; + int dterr; + int mer = HR24; + bool haveTextMonth = false; + bool isjulian = false; + bool is2digits = false; + bool bc = false; + pg_tz *namedTz = NULL; + pg_tz *abbrevTz = NULL; + pg_tz *valtz; + char *abbrev = NULL; struct pg_tm cur_tm; /* @@ -943,7 +947,9 @@ DecodeDateTime(char **field, int *ftype, int nf, * ereport'ing directly, but then there is no way * to report the bad time zone name. */ - elog(ERROR, "time zone \"%s\" not recognized", field[i]); + meos_error(ERROR, MEOS_ERR_FILE_ERROR, + "time zone \"%s\" not recognized", field[i]); + return -1; } /* we'll apply the zone setting below */ tmask = DTK_M(TZ); @@ -1704,24 +1710,24 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, * if time zones are allowed. - thomas 2001-12-26 */ int -DecodeTimeOnly(char **field, int *ftype, int nf, - int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp) +DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, + fsec_t *fsec, int *tzp) { - int fmask = 0, - tmask, - type; - int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */ - int i; - int val; - int dterr; - bool isjulian = false; - bool is2digits = false; - bool bc = false; - int mer = HR24; - pg_tz *namedTz = NULL; - pg_tz *abbrevTz = NULL; - char *abbrev = NULL; - pg_tz *valtz; + int fmask = 0, + tmask, + type; + int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */ + int i; + int val; + int dterr; + bool isjulian = false; + bool is2digits = false; + bool bc = false; + int mer = HR24; + pg_tz *namedTz = NULL; + pg_tz *abbrevTz = NULL; + char *abbrev = NULL; + pg_tz *valtz; *dtype = DTK_TIME; tm->tm_hour = 0; @@ -1751,8 +1757,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, if (i == 0 && nf >= 2 && (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME)) { - dterr = DecodeDate(field[i], fmask, - &tmask, &is2digits, tm); + dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); if (dterr) return dterr; } @@ -1806,7 +1811,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf, * ereport'ing directly, but then there is no way * to report the bad time zone name. */ - elog(ERROR, "time zone \"%s\" not recognized", field[i]); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "time zone \"%s\" not recognized", field[i]); + return DTERR_BAD_FORMAT; } /* we'll apply the zone setting below */ ftype[i] = DTK_TZ; @@ -3709,23 +3716,29 @@ DateTimeParseError(int dterr, const char *str, const char *datatype) switch (dterr) { case DTERR_FIELD_OVERFLOW: - elog(ERROR, "date/time field value out of range: \"%s\"", str); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "date/time field value out of range: \"%s\"", str); break; case DTERR_MD_FIELD_OVERFLOW: /* same as above, but add hint about DateStyle */ - elog(ERROR, "date/time field value out of range: \"%s\"", str); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "date/time field value out of range: \"%s\"", str); break; case DTERR_INTERVAL_OVERFLOW: - elog(ERROR, "interval field value out of range: \"%s\"", str); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "interval field value out of range: \"%s\"", str); break; case DTERR_TZDISP_OVERFLOW: - elog(ERROR, "time zone displacement out of range: \"%s\"", str); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "time zone displacement out of range: \"%s\"", str); break; case DTERR_BAD_FORMAT: default: - elog(ERROR, "invalid input syntax for type %s: \"%s\"", datatype, str); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "invalid input syntax for type %s: \"%s\"", datatype, str); break; } + return; } @@ -3821,7 +3834,9 @@ EncodeSpecialDate(DateADT dt, char *str) else if (DATE_IS_NOEND(dt)) strcpy(str, LATE); else /* shouldn't happen */ - elog(ERROR, "invalid argument for EncodeSpecialDate"); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid argument for EncodeSpecialDate"); + return; } /* EncodeDateOnly() @@ -4388,7 +4403,10 @@ FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp) * then there is no way to report the bad time zone name. */ if (dtza->tz == NULL) - elog(ERROR, "time zone \"%s\" not recognized", dtza->zone); + { + meos_error(ERROR, "time zone \"%s\" not recognized", dtza->zone); + return NULL; + } } return dtza->tz; } diff --git a/meos/postgres/utils/float.c b/meos/postgres/utils/float.c index 4eabab8398..9089cef0b8 100644 --- a/meos/postgres/utils/float.c +++ b/meos/postgres/utils/float.c @@ -19,6 +19,8 @@ #include #include +#include "../../include/meos.h" + /* * Configurable GUC parameter * @@ -39,19 +41,21 @@ int extra_float_digits = 1; pg_noinline void float_overflow_error(void) { - elog(ERROR, "value out of range: overflow"); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "value out of range: overflow"); } pg_noinline void float_underflow_error(void) { - elog(ERROR, "value out of range: underflow"); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "value out of range: underflow"); } pg_noinline void float_zero_divide_error(void) { - elog(ERROR, "division by zero"); + meos_error(ERROR, MEOS_ERR_DIVISION_BY_ZERO, "division by zero"); } /* diff --git a/meos/postgres/utils/formatting.c b/meos/postgres/utils/formatting.c index 8054ea0d7d..dd067c6993 100644 --- a/meos/postgres/utils/formatting.c +++ b/meos/postgres/utils/formatting.c @@ -67,6 +67,8 @@ #include "utils/date.h" #include "utils/float.h" +#include "../../include/meos.h" + #define DEFAULT_COLLATION_OID 100 /* @@ -441,8 +443,11 @@ do { \ #define INVALID_FOR_INTERVAL \ do { \ if (is_interval) \ - elog(ERROR, \ + { \ + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, \ "invalid format specification for an interval value"); \ + return; \ + } \ } while(0) /***************************************************************************** @@ -954,8 +959,12 @@ parse_format(FormatNode *node, const char *str, const KeyWord *kw, * (see below). This is our extension of standard mode. */ if (strchr("-./,':; ", *str) == NULL) - elog(ERROR, "invalid datetime format separator: \"%s\"", - pnstrdup(str, sizeof(char))); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid datetime format separator: \"%s\"", + pnstrdup(str, sizeof(char))); + return; + } if (*str == ' ') n->type = NODE_TYPE_SPACE; @@ -1044,7 +1053,11 @@ get_th(char *num, int type) last = *(num + (len - 1)); if (!isdigit((unsigned char) last)) - elog(ERROR, "\"%s\" is not a number", num); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "\"%s\" is not a number", num); + return NULL; + } /* * All "teens" (1[0-9]) get 'TH/th', while [02-9][123] still get @@ -1315,7 +1328,11 @@ from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, bool *have_err if (tmfc->mode == FROM_CHAR_DATE_NONE) tmfc->mode = mode; else if (tmfc->mode != mode) - elog(ERROR, "invalid combination of date conventions"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid combination of date conventions"); + return; + } } on_error: @@ -1335,9 +1352,13 @@ from_char_set_int(int *dest, const int value, const FormatNode *node, bool *have_error) { if (*dest != 0 && *dest != value) - elog(ERROR, "conflicting values for \"%s\" field in " - "formatting string", - node->key->name); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "conflicting values for \"%s\" field in formatting string", + node->key->name); + return; + } + *dest = value; on_error: @@ -1368,8 +1389,8 @@ from_char_set_int(int *dest, const int value, const FormatNode *node, * and -1 is returned. */ static int -from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode *node, - bool *have_error) +from_char_parse_int_len(int *dest, const char **src, const int len, + FormatNode *node, bool *have_error) { long result; char *copy; // char copy[DCH_MAX_ITEM_SIZ + 1]; @@ -1414,27 +1435,40 @@ from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode * char *last; if (used < len) - elog(ERROR, "source string too short for \"%s\" formatting field", - node->key->name); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "source string too short for \"%s\" formatting field", + node->key->name); + return -1; + } errno = 0; result = strtol(copy, &last, 10); used = last - copy; if (used > 0 && used < len) - elog(ERROR, "invalid value \"%s\" for \"%s\"", - copy, node->key->name); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid value \"%s\" for \"%s\"", copy, node->key->name); + return -1; + } *src += used; } if (*src == init) - elog(ERROR, "invalid value \"%s\" for \"%s\"", - copy, node->key->name); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid value \"%s\" for \"%s\"", copy, node->key->name); + return -1; + } if (errno == ERANGE || result < INT_MIN || result > INT_MAX) - elog(ERROR, "value for \"%s\" in source string is out of range", - node->key->name); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "value for \"%s\" in source string is out of range", node->key->name); + return -1; + } if (dest != NULL) { @@ -1667,8 +1701,9 @@ from_char_seq_search(int *dest, const char **src, const char *const *array, } } - elog(ERROR, "invalid value \"%s\" for \"%s\"", - copy, node->key->name); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid value \"%s\" for \"%s\"", copy, node->key->name); + return -1; } *src += len; return len; @@ -1683,7 +1718,8 @@ from_char_seq_search(int *dest, const char **src, const char *const *array, * ---------- */ static void -DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid) +DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, + Oid collid) { FormatNode *n; char *s; @@ -1877,12 +1913,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; if (S_TM(n->suffix)) { - char *str = str_toupper_z(months_full[tm->tm_mon - 1], collid); + char *str = str_toupper_z(months_full[tm->tm_mon - 1], collid); if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, @@ -1900,7 +1940,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, @@ -1918,7 +1962,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, @@ -1936,7 +1984,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else strcpy(s, asc_toupper_z(months[tm->tm_mon - 1])); @@ -1953,7 +2005,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else strcpy(s, months[tm->tm_mon - 1]); @@ -1970,7 +2026,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else strcpy(s, asc_tolower_z(months[tm->tm_mon - 1])); @@ -1992,7 +2052,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, @@ -2008,7 +2072,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, @@ -2024,7 +2092,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, @@ -2040,7 +2112,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else strcpy(s, asc_toupper_z(days_short[tm->tm_wday])); @@ -2055,7 +2131,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else strcpy(s, days_short[tm->tm_wday]); @@ -2070,7 +2150,11 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ) strcpy(s, str); else - elog(ERROR, "localized string format value too long"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "localized string format value too long"); + return; + } } else strcpy(s, asc_tolower_z(days_short[tm->tm_wday])); @@ -2287,6 +2371,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col } *s = '\0'; + return; } /* @@ -2345,8 +2430,11 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, if (*s == n->character[0]) s++; else - elog(ERROR, "unmatched format separator \"%c\"", - n->character[0]); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "unmatched format separator \"%c\"", n->character[0]); + return; + } } else if (!fx_mode) { @@ -2404,8 +2492,11 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, */ if (std && n->type == NODE_TYPE_CHAR && strncmp(s, n->character, chlen) != 0) - elog(ERROR, "unmatched format character \"%s\"", - n->character); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "unmatched format character \"%s\"", n->character); + return; + } s += chlen; } @@ -2508,10 +2599,12 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, case DCH_tz: case DCH_TZ: case DCH_OF: - elog(ERROR, "formatting field \"%s\" is only supported in to_char", + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "formatting field \"%s\" is only supported in to_char", n->key->name); - CHECK_ERROR; - break; + return; + // CHECK_ERROR; + // break; case DCH_TZH: /* @@ -2681,7 +2774,11 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch); if (matched < 2) - elog(ERROR, "invalid input string for \"Y,YYY\""); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid input string for \"Y,YYY\""); + return; + } years += (millennia * 1000); from_char_set_int(&out->year, years, n, have_error); CHECK_ERROR; @@ -2765,14 +2862,21 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, if (std) { if (n->type != NODE_TYPE_END) - elog(ERROR, "input string is too short for datetime format"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "input string is too short for datetime format"); + return; + } while (*s != '\0' && isspace((unsigned char) *s)) s++; if (*s != '\0') - elog(ERROR, "trailing characters remain in input string " - "after datetime format"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "trailing characters remain in input string after datetime format"); + return; + } } on_error: @@ -2844,8 +2948,9 @@ DCH_datetime_type(FormatNode *node, bool *have_error) case DCH_tz: case DCH_TZ: case DCH_OF: - elog(ERROR, "formatting field \"%s\" is only supported in to_char", - n->key->name); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "formatting field \"%s\" is only supported in to_char", + n->key->name); flags |= DCH_ZONED; break; case DCH_TZH: @@ -3093,7 +3198,10 @@ pg_timestamp_to_char(Timestamp dt, text *fmt) tm = tmtcTm(&tmtc); if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0) - elog(ERROR, "timestamp out of range"); + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, "timestamp out of range"); + return NULL; + } thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); tm->tm_wday = (thisdate + 1) % 7; @@ -3125,7 +3233,10 @@ pg_timestamptz_to_char(TimestampTz dt, text *fmt) tm = tmtcTm(&tmtc); if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0) - elog(ERROR, "timestamp out of range"); + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, "timestamp out of range"); + return NULL; + } thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); tm->tm_wday = (thisdate + 1) % 7; @@ -3207,7 +3318,10 @@ pg_to_timestamp(text *date_txt, text *fmt) tz = DetermineTimeZoneOffset(&tm, session_timezone); if (tm2timestamp(&tm, fsec, &tz, &result) != 0) - elog(ERROR, "timestamp out of range"); + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, "timestamp out of range"); + return NULL; + } /* Use the specified fractional precision, if any. */ if (fprec) @@ -3237,13 +3351,21 @@ pg_to_date(text *date_txt, text *fmt) /* Prevent overflow in Julian-day routines */ if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) - elog(ERROR, "date out of range: \"%s\"", text2cstring(date_txt)); + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "date out of range: \"%s\"", text2cstring(date_txt)); + return 0; + } result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE; /* Now check for just-out-of-range dates */ if (!IS_VALID_DATE(result)) - elog(ERROR, "date out of range: \"%s\"", text2cstring(date_txt)); + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "date out of range: \"%s\"", text2cstring(date_txt)); + return 0; + } return result; } @@ -3365,8 +3487,8 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, { if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2) { - elog(ERROR, "hour \"%d\" is invalid for the 12-hour clock", - tm->tm_hour); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "hour \"%d\" is invalid for the 12-hour clock", tm->tm_hour); } if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2) @@ -3475,7 +3597,8 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, if (!tm->tm_year && !tmfc.bc) { - elog(ERROR, "cannot calculate day of year without year information"); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "cannot calculate day of year without year information"); } if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK) diff --git a/meos/postgres/utils/numutils.c b/meos/postgres/utils/numutils.c index e568737626..5e34cd818b 100644 --- a/meos/postgres/utils/numutils.c +++ b/meos/postgres/utils/numutils.c @@ -17,6 +17,8 @@ #include "common/int.h" #include "port/pg_bitutils.h" +#include "../../include/meos.h" + /* * A table of all two-digit numbers. This is used to speed up decimal digit * generation by copying pairs of digits into the final output. @@ -142,10 +144,12 @@ pg_strtoint32(const char *s) return tmp; out_of_range: - elog(ERROR, "value \"%s\" is out of range for type %s", s, "integer"); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "value \"%s\" is out of range for type %s", s, "integer"); invalid_syntax: - elog(ERROR, "invalid input syntax for type %s: \"%s\"", "integer", s); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "invalid input syntax for type %s: \"%s\"", "integer", s); return 0; /* keep compiler quiet */ } @@ -221,10 +225,12 @@ pg_strtoint64(const char *s) return tmp; out_of_range: - elog(ERROR, "value \"%s\" is out of range for type %s", s, "bigint"); + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "value \"%s\" is out of range for type %s", s, "bigint"); invalid_syntax: - elog(ERROR, "invalid input syntax for type %s: \"%s\"", "bigint", s); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid input syntax for type %s: \"%s\"", "bigint", s); return 0; /* keep compiler quiet */ } diff --git a/meos/postgres/utils/timestamp.c b/meos/postgres/utils/timestamp.c index d5654958e9..270d3b9cc0 100644 --- a/meos/postgres/utils/timestamp.c +++ b/meos/postgres/utils/timestamp.c @@ -17,6 +17,8 @@ #include "postgres.h" +#include "../../include/meos.h" + // MEOS // #include "datatype/timestamp.h" #include "utils/timestamp_def.h" @@ -41,7 +43,8 @@ EncodeSpecialTimestamp(Timestamp dt, char *str) else if (TIMESTAMP_IS_NOEND(dt)) strcpy(str, LATE); else /* shouldn't happen */ - elog(ERROR, "invalid argument for EncodeSpecialTimestamp"); + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "invalid argument for EncodeSpecialTimestamp"); } /* @@ -248,7 +251,11 @@ interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec) time -= tfrac * USECS_PER_HOUR; tm->tm_hour = tfrac; if (!SAMESIGN(tm->tm_hour, tfrac)) - elog(ERROR, "interval out of range"); + { + meos_error(ERROR, MEOS_ERR_VALUE_OUT_OF_RANGE, + "interval out of range"); + return; + } tfrac = time / USECS_PER_MINUTE; time -= tfrac * USECS_PER_MINUTE; tm->tm_min = tfrac; @@ -301,7 +308,11 @@ GetEpochTime(struct pg_tm *tm) t0 = pg_gmtime(&epoch); if (t0 == NULL) - elog(ERROR, "could not convert epoch to timestamp: %m"); + { + meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, + "could not convert epoch to timestamp: %m"); + return; + } tm->tm_year = t0->tm_year; tm->tm_mon = t0->tm_mon; diff --git a/meos/src/general/error.c b/meos/src/general/error.c index eceb0c4847..7463971244 100644 --- a/meos/src/general/error.c +++ b/meos/src/general/error.c @@ -1,228 +1,232 @@ -/***************************************************************************** - * - * This MobilityDB code is provided under The PostgreSQL License. - * Copyright (c) 2016-2023, Université libre de Bruxelles and MobilityDB - * contributors - * - * MobilityDB includes portions of PostGIS version 3 source code released - * under the GNU General Public License (GPLv2 or later). - * Copyright (c) 2001-2023, PostGIS contributors - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose, without fee, and without a written - * agreement is hereby granted, provided that the above copyright notice and - * this paragraph and the following two paragraphs appear in all copies. - * - * IN NO EVENT SHALL UNIVERSITE LIBRE DE BRUXELLES BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING - * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, - * EVEN IF UNIVERSITE LIBRE DE BRUXELLES HAS BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * UNIVERSITE LIBRE DE BRUXELLES SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON - * AN "AS IS" BASIS, AND UNIVERSITE LIBRE DE BRUXELLES HAS NO OBLIGATIONS TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - *****************************************************************************/ - -/** - * @file - * @brief MEOS error handling inspired by GEOS and Proj - * https://github.com/libgeos/geos/blob/main/capi/geos_c.h.in - * https://github.com/OSGeo/PROJ/blob/master/src/4D_api.cpp - */ - -#include "general/error.h" - -/* C */ -#include -#include -/* C */ -#include -#if ! MEOS - #include -#endif /* ! MEOS */ - -/*****************************************************************************/ - -/** - * @brief Global variable that keeps the last error number. - */ -int _meos_errno = 0; - -/** - * @brief Read an error number - */ -static int -meos_errno(void) -{ - return _meos_errno; -} - -/** - * @brief Set an error number - */ -int -meos_errno_set(int err) -{ - /* Use #meos_errno_reset to explicitly clear the error status */ - if (err == 0) - return 0; - - meos_errno_set(err); - errno = err; - return err; -} - -/** - * @brief Set an error number - * - * Use #meos_errno_restore when the current function succeeds, but the - * error flag was set on entry, and stored/reset using #meos_errno_reset - * in order to monitor for new errors. - * See usage example under #meos_errno_reset() - */ -int -meos_errno_restore(int err) -{ - if (err == 0) - return 0; - meos_errno_set(err); - return 0; -} - +/***************************************************************************** + * + * This MobilityDB code is provided under The PostgreSQL License. + * Copyright (c) 2016-2023, Université libre de Bruxelles and MobilityDB + * contributors + * + * MobilityDB includes portions of PostGIS version 3 source code released + * under the GNU General Public License (GPLv2 or later). + * Copyright (c) 2001-2023, PostGIS contributors + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without a written + * agreement is hereby granted, provided that the above copyright notice and + * this paragraph and the following two paragraphs appear in all copies. + * + * IN NO EVENT SHALL UNIVERSITE LIBRE DE BRUXELLES BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING + * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, + * EVEN IF UNIVERSITE LIBRE DE BRUXELLES HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * UNIVERSITE LIBRE DE BRUXELLES SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND UNIVERSITE LIBRE DE BRUXELLES HAS NO OBLIGATIONS TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + *****************************************************************************/ + +/** + * @file + * @brief MEOS error handling inspired by GEOS and Proj + * https://github.com/libgeos/geos/blob/main/capi/geos_c.h.in + * https://github.com/OSGeo/PROJ/blob/master/src/4D_api.cpp + */ + +/* C */ +#include +#include +/* Postgres */ +#include +/* MEOS */ +#include + +/*****************************************************************************/ + +/** + * @brief Global variable that keeps the last error number. + */ +int _meos_errno = 0; + +/** + * @brief Read an error number + */ +static int +meos_errno(void) +{ + return _meos_errno; +} + +/** + * @brief Set an error number + */ +int +meos_errno_set(int err) +{ + /* Use #meos_errno_reset to explicitly clear the error status */ + if (err == 0) + return 0; + + meos_errno_set(err); + errno = err; + return err; +} + /** - * @brief Clears errno. + * @brief Set an error number + * + * Use #meos_errno_restore when the current function succeeds, but the + * error flag was set on entry, and stored/reset using #meos_errno_reset + * in order to monitor for new errors. + * See usage example under #meos_errno_reset() + */ +int +meos_errno_restore(int err) +{ + if (err == 0) + return 0; + meos_errno_set(err); + return 0; +} + +/** + * @brief Clears errno. * @return Returns the previous value of the errno, for convenient reset/restore - * operations - * - * @code - * int foo(void) + * operations + * + * @code + * int foo(void) * { * // errno may be set on entry, but we need to reset it to be able to * // check for errors from "do_something()" - * int last_errno = meos_errno_reset(); + * int last_errno = meos_errno_reset(); * * // local failure * if (0==P) - * return meos_errno_set(42); - * + * return meos_errno_set(42); + * * // call to function that may fail - * do_something(); - * + * do_something(); + * * // failure in do_something? - keep latest error status * if (meos_errno()) - * return meos_errno(); - * + * return meos_errno(); + * * // success - restore previous error status, return 0 * return meos_errno_restore(last_errno); - * } - * @endcode - */ - -int meos_errno_reset(void) -{ - int last_errno = meos_errno(); - meos_errno_set(0); - errno = 0; - return last_errno; -} - -/*****************************************************************************/ - -/** - * @brief Global variable that keeps the error handler function - */ -void (*_error_handler)(int, int, char *) = NULL; - -#if MEOS -/** - * @brief Default error handler function that prints the error to stderr and - * exits if error level is equal to `ERROR` - */ -void -default_error_handler(int errlevel, int errcode __attribute((__unused__)), - char *text) -{ - fprintf(stderr, "%s", text); - fprintf(stderr, "\n"); - if (errlevel == ERROR) - exit(EXIT_FAILURE); - return; -} - -/** - * @brief Error handler function that sets the errno - */ -void -error_handler_errno(int errlevel __attribute((__unused__)), int errcode, - char *text) -{ - perror(text); - meos_errno_set(errcode); - return; -} - -/* - * Initialize error handler function - */ -void -meos_initialize_error_handler(error_handler_fn err_handler) -{ - if (err_handler) - _error_handler = err_handler; - else - _error_handler = &default_error_handler; - return; -} -#endif /* MEOS */ - -/*****************************************************************************/ - -/** - * @brief Function handling error messages - */ -void -meos_error(int errlevel, int errcode, char *errmsg, ...) -{ - char buffer[1024]; - va_list args; - va_start(args, errmsg); - vsprintf(buffer, errmsg, args); - /* Execute the error handler function */ - if (_error_handler) - _error_handler(errlevel, errcode, buffer); - else - elog(errlevel, "%s", buffer); - va_end(args); - return; -} - -/*****************************************************************************/ - -#if MEOS -/* - * Initialize MEOS library - */ -void -meos_initialize(const char *tz_str, error_handler_fn err_handler) -{ - meos_initialize_timezone(tz_str); - meos_initialize_error_handler(err_handler); - return; -} - -/* - * Free the timezone cache - */ -void -meos_finalize(void) -{ - meos_finalize_timezone(); - return; -} -#endif /* MEOS */ - -/*****************************************************************************/ + * } + * @endcode + */ + +int meos_errno_reset(void) +{ + int last_errno = meos_errno(); + meos_errno_set(0); + errno = 0; + return last_errno; +} + +/*****************************************************************************/ + +/** + * @brief Global variable that keeps the error handler function + */ +void (*_error_handler)(int, int, char *) = NULL; + +#if MEOS +/** + * @brief Default error handler function that prints the error to stderr and + * exits if error level is equal to `ERROR` + */ +void +default_error_handler(int errlevel, int errcode __attribute((__unused__)), + char *text) +{ + fprintf(stderr, "%s", text); + fprintf(stderr, "\n"); + if (errlevel == ERROR) + exit(EXIT_FAILURE); + return; +} + +/** + * @brief Error handler function that sets the errno + */ +void +error_handler_errno(int errlevel __attribute((__unused__)), int errcode, + char *text) +{ + perror(text); + meos_errno_set(errcode); + return; +} + +/* + * Initialize error handler function + */ +void +meos_initialize_error_handler(error_handler_fn err_handler) +{ + if (err_handler) + _error_handler = err_handler; + else + _error_handler = &default_error_handler; + return; +} +#endif /* MEOS */ + +/*****************************************************************************/ + +/** + * @brief Function handling error messages + */ +void +meos_error(int errlevel, int errcode, char *errmsg, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, errmsg); + vsprintf(buffer, errmsg, args); + /* Execute the error handler function */ + if (_error_handler) + { + _error_handler(errlevel, errcode, buffer); + va_end(args); + } + else + { + fprintf (stderr, "%s\n", buffer); + va_end(args); + if (errlevel == ERROR) + exit(EXIT_FAILURE); + } + return; +} + +/*****************************************************************************/ + +#if MEOS +/* + * Initialize MEOS library + */ +void +meos_initialize(const char *tz_str, error_handler_fn err_handler) +{ + meos_initialize_timezone(tz_str); + meos_initialize_error_handler(err_handler); + return; +} + +/* + * Free the timezone cache + */ +void +meos_finalize(void) +{ + meos_finalize_timezone(); + return; +} +#endif /* MEOS */ + +/*****************************************************************************/ diff --git a/meos/src/point/pgis_call.c b/meos/src/point/pgis_call.c index 708c243402..db09252529 100644 --- a/meos/src/point/pgis_call.c +++ b/meos/src/point/pgis_call.c @@ -65,7 +65,8 @@ void srid_check_latlong(int32_t srid); #if MEOS #define PG_PARSER_ERROR(lwg_parser_result) \ do { \ - elog(ERROR, "%s", lwg_parser_result.message); \ + meos_error(ERROR, MEOS_ERR_INTERNAL_TYPE_ERROR, \ + "%s", lwg_parser_result.message); \ } while(0); #else #include @@ -1274,8 +1275,11 @@ gserialized_geog_distance(const GSERIALIZED *gs1, const GSERIALIZED *gs2) /* Something went wrong, negative return... should already be eloged, return NULL */ if ( distance < 0.0 ) + { meos_error(ERROR, MEOS_ERR_INTERNAL_TYPE_ERROR, "gserialized_geog_distance returned distance < 0.0"); + return -1; + } return distance; }