diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c index 3d2f268961..ff866c44cb 100644 --- a/src/backend/utils/adt/bool.c +++ b/src/backend/utils/adt/bool.c @@ -148,7 +148,7 @@ boolin(PG_FUNCTION_ARGS) if (parse_bool_with_len(str, len, &result)) PG_RETURN_BOOL(result); - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type boolean: \"%s\"", in_str))); diff --git a/src/backend/utils/adt/char.c b/src/backend/utils/adt/char.c index e0d974eea5..f840a29bc3 100644 --- a/src/backend/utils/adt/char.c +++ b/src/backend/utils/adt/char.c @@ -164,7 +164,7 @@ i4tochar(PG_FUNCTION_ARGS) int32 arg1 = PG_GETARG_INT32(0); if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("\"char\" out of range"))); diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 6a831875f7..2b1877c5fa 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -48,8 +48,8 @@ static void AdjustTimeForTypmod(TimeADT *time, int32 typmod); /* common code for timetypmodin and timetztypmodin */ -static int32 -anytime_typmodin(bool istz, ArrayType *ta) +static bool +anytime_typmodin_safe(bool istz, ArrayType *ta, int32 *result, Node *escontext) { int32 typmod; int32 *tl; @@ -62,12 +62,12 @@ anytime_typmodin(bool istz, ArrayType *ta) * shouldn't allow wrong number of modifiers for TIME */ if (n != 1) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid type modifier"))); if (*tl < 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("TIME(%d)%s precision must not be negative", *tl, (istz ? " WITH TIME ZONE" : "")))); @@ -83,7 +83,16 @@ anytime_typmodin(bool istz, ArrayType *ta) else typmod = *tl; - return typmod; + *result = typmod; + return true; +} + +static int32 +anytime_typmodin(bool istz, ArrayType *ta) +{ + int32 result; + (void) anytime_typmodin_safe(istz, ta, &result, NULL); + return result; } /* common code for timetypmodout and timetztypmodout */ @@ -126,9 +135,11 @@ date_in(PG_FUNCTION_ARGS) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) - dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp); + if (!DecodeDateTimeSafe(field, ftype, nf, &dtype, tm, &fsec, &tzp, &dterr, fcinfo->context)) + PG_RETURN_NULL(); if (dterr != 0) - DateTimeParseError(dterr, str, "date"); + if (!DateTimeParseErrorSafe(dterr, str, "date", fcinfo->context)) + PG_RETURN_NULL(); switch (dtype) { @@ -136,7 +147,7 @@ date_in(PG_FUNCTION_ARGS) break; case DTK_CURRENT: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"current\" is no longer supported"))); @@ -156,12 +167,13 @@ date_in(PG_FUNCTION_ARGS) PG_RETURN_DATEADT(date); default: - DateTimeParseError(DTERR_BAD_FORMAT, str, "date"); + (void) DateTimeParseErrorSafe(DTERR_BAD_FORMAT, str, "date", fcinfo->context); + PG_RETURN_NULL(); break; } if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range: \"%s\"", str))); @@ -211,7 +223,7 @@ date_recv(PG_FUNCTION_ARGS) /* ok */ ; else if (result < -POSTGRES_EPOCH_JDATE || result >= JULIAN_MAX - POSTGRES_EPOCH_JDATE) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range"))); @@ -253,13 +265,13 @@ make_date(PG_FUNCTION_ARGS) dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm); if (dterr != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), errmsg("date field value out of range: %d-%02d-%02d", tm.tm_year, tm.tm_mon, tm.tm_mday))); if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range: %d-%02d-%02d", tm.tm_year, tm.tm_mon, tm.tm_mday))); @@ -412,7 +424,7 @@ date_mi(PG_FUNCTION_ARGS) DateADT dateVal2 = PG_GETARG_DATEADT(1); if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("cannot subtract infinite dates"))); @@ -452,9 +464,8 @@ date_mii(PG_FUNCTION_ARGS) * Internal routines for promoting date to timestamp and timestamp with * time zone */ - -static Timestamp -date2timestamp(DateADT dateVal) +static bool +date2timestamp_safe(DateADT dateVal, Timestamp *res, Node *escontext) { Timestamp result; @@ -469,7 +480,7 @@ date2timestamp(DateADT dateVal) result = dateVal * USECS_PER_DAY; /* Date's range is wider than timestamp's, so check for overflow */ if (result / USECS_PER_DAY != dateVal) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range for timestamp"))); #else @@ -478,11 +489,20 @@ date2timestamp(DateADT dateVal) #endif } + *res = result; + return true; +} + +static Timestamp +date2timestamp(DateADT dateVal) +{ + Timestamp result; + (void) date2timestamp_safe(dateVal, &result, NULL); return result; } -static TimestampTz -date2timestamptz(DateADT dateVal) +static bool +date2timestamptz_safe(DateADT dateVal, TimestampTz *res, Node *escontext) { TimestampTz result; struct pg_tm tt, @@ -506,7 +526,7 @@ date2timestamptz(DateADT dateVal) result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC; /* Date's range is wider than timestamp's, so check for overflow */ if ((result - tz * USECS_PER_SEC) / USECS_PER_DAY != dateVal) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range for timestamp"))); #else @@ -514,6 +534,15 @@ date2timestamptz(DateADT dateVal) #endif } + *res = result; + return true; +} + +static TimestampTz +date2timestamptz(DateADT dateVal) +{ + TimestampTz result; + (void) date2timestamptz_safe(dateVal, &result, NULL); return result; } @@ -562,7 +591,8 @@ date_eq_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0); } @@ -574,7 +604,8 @@ date_ne_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0); } @@ -586,7 +617,8 @@ date_lt_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0); } @@ -598,7 +630,8 @@ date_gt_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0); } @@ -610,7 +643,8 @@ date_le_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0); } @@ -622,7 +656,8 @@ date_ge_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0); } @@ -634,7 +669,8 @@ date_cmp_timestamp(PG_FUNCTION_ARGS) Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Timestamp dt1; - dt1 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2)); } @@ -646,7 +682,8 @@ date_eq_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0); } @@ -658,7 +695,8 @@ date_ne_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0); } @@ -670,7 +708,8 @@ date_lt_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0); } @@ -682,7 +721,8 @@ date_gt_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0); } @@ -694,7 +734,8 @@ date_le_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0); } @@ -706,7 +747,8 @@ date_ge_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0); } @@ -718,7 +760,8 @@ date_cmp_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2)); } @@ -730,7 +773,8 @@ timestamp_eq_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0); } @@ -742,7 +786,8 @@ timestamp_ne_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0); } @@ -754,7 +799,8 @@ timestamp_lt_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0); } @@ -766,7 +812,8 @@ timestamp_gt_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0); } @@ -778,7 +825,8 @@ timestamp_le_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0); } @@ -790,7 +838,8 @@ timestamp_ge_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0); } @@ -802,7 +851,8 @@ timestamp_cmp_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); Timestamp dt2; - dt2 = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2)); } @@ -814,7 +864,8 @@ timestamptz_eq_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0); } @@ -826,7 +877,8 @@ timestamptz_ne_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0); } @@ -838,7 +890,8 @@ timestamptz_lt_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0); } @@ -850,7 +903,8 @@ timestamptz_gt_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0); } @@ -862,7 +916,8 @@ timestamptz_le_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0); } @@ -874,7 +929,8 @@ timestamptz_ge_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0); } @@ -886,7 +942,8 @@ timestamptz_cmp_date(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(1); TimestampTz dt2; - dt2 = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2)); } @@ -905,7 +962,8 @@ date_pl_interval(PG_FUNCTION_ARGS) Interval *span = PG_GETARG_INTERVAL_P(1); Timestamp dateStamp; - dateStamp = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dateStamp, fcinfo->context)) + PG_RETURN_NULL(); return DirectFunctionCall2(timestamp_pl_interval, TimestampGetDatum(dateStamp), @@ -925,7 +983,8 @@ date_mi_interval(PG_FUNCTION_ARGS) Interval *span = PG_GETARG_INTERVAL_P(1); Timestamp dateStamp; - dateStamp = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &dateStamp, fcinfo->context)) + PG_RETURN_NULL(); return DirectFunctionCall2(timestamp_mi_interval, TimestampGetDatum(dateStamp), @@ -941,7 +1000,8 @@ date_timestamp(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(0); Timestamp result; - result = date2timestamp(dateVal); + if (!date2timestamp_safe(dateVal, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -965,7 +1025,7 @@ timestamp_date(PG_FUNCTION_ARGS) else { if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -985,7 +1045,8 @@ date_timestamptz(PG_FUNCTION_ARGS) DateADT dateVal = PG_GETARG_DATEADT(0); TimestampTz result; - result = date2timestamptz(dateVal); + if (!date2timestamptz_safe(dateVal, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -1011,7 +1072,7 @@ timestamptz_date(PG_FUNCTION_ARGS) else { if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -1037,7 +1098,7 @@ abstime_date(PG_FUNCTION_ARGS) switch (abstime) { case INVALID_ABSTIME: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert reserved abstime value to date"))); result = 0; /* keep compiler quiet */ @@ -1089,9 +1150,11 @@ time_in(PG_FUNCTION_ARGS) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) - dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz); + if (!DecodeTimeOnlySafe(field, ftype, nf, &dtype, tm, &fsec, &tz, &dterr, fcinfo->context)) + PG_RETURN_NULL(); if (dterr != 0) - DateTimeParseError(dterr, str, "time"); + if (!DateTimeParseErrorSafe(dterr, str, "time", fcinfo->context)) + PG_RETURN_NULL(); tm2time(tm, fsec, &result); AdjustTimeForTypmod(&result, typmod); @@ -1191,14 +1254,14 @@ time_recv(PG_FUNCTION_ARGS) result = pq_getmsgint64(buf); if (result < INT64CONST(0) || result > USECS_PER_DAY) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("time out of range"))); #else result = pq_getmsgfloat8(buf); if (result < 0 || result > (double) SECS_PER_DAY) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("time out of range"))); #endif @@ -1231,7 +1294,12 @@ timetypmodin(PG_FUNCTION_ARGS) { ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); - PG_RETURN_INT32(anytime_typmodin(false, ta)); + int32 typmod; + + if(!anytime_typmodin_safe(false, ta, &typmod, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_INT32(typmod); } Datum @@ -1259,7 +1327,7 @@ make_time(PG_FUNCTION_ARGS) tm_hour > HOURS_PER_DAY || /* test for > 24:00:00 */ (tm_hour == HOURS_PER_DAY && (tm_min > 0 || sec > 0))) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), errmsg("time field value out of range: %d:%02d:%02g", tm_hour, tm_min, sec))); @@ -1611,7 +1679,7 @@ timestamp_time(PG_FUNCTION_ARGS) PG_RETURN_NULL(); if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -1647,7 +1715,7 @@ timestamptz_time(PG_FUNCTION_ARGS) PG_RETURN_NULL(); if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -1676,7 +1744,8 @@ datetime_timestamp(PG_FUNCTION_ARGS) TimeADT time = PG_GETARG_TIMEADT(1); Timestamp result; - result = date2timestamp(date); + if (!date2timestamp_safe(date, &result, fcinfo->context)) + PG_RETURN_NULL(); if (!TIMESTAMP_NOT_FINITE(result)) result += time; @@ -1961,7 +2030,7 @@ time_part(PG_FUNCTION_ARGS) case DTK_MILLENNIUM: case DTK_ISOYEAR: default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"time\" units \"%s\" not recognized", lowunits))); @@ -1978,7 +2047,7 @@ time_part(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"time\" units \"%s\" not recognized", lowunits))); @@ -2034,9 +2103,11 @@ timetz_in(PG_FUNCTION_ARGS) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) - dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz); + if (!DecodeTimeOnlySafe(field, ftype, nf, &dtype, tm, &fsec, &tz, &dterr, fcinfo->context)) + PG_RETURN_NULL(); if (dterr != 0) - DateTimeParseError(dterr, str, "time with time zone"); + if (!DateTimeParseErrorSafe(dterr, str, "time with time zone", fcinfo->context)) + PG_RETURN_NULL(); result = (TimeTzADT *) palloc(sizeof(TimeTzADT)); tm2timetz(tm, fsec, tz, result); @@ -2083,14 +2154,14 @@ timetz_recv(PG_FUNCTION_ARGS) result->time = pq_getmsgint64(buf); if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("time out of range"))); #else result->time = pq_getmsgfloat8(buf); if (result->time < 0 || result->time > (double) SECS_PER_DAY) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("time out of range"))); #endif @@ -2099,7 +2170,7 @@ timetz_recv(PG_FUNCTION_ARGS) /* Check for sane GMT displacement; see notes in datatype/timestamp.h */ if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE), errmsg("time zone displacement out of range"))); @@ -2132,7 +2203,12 @@ timetztypmodin(PG_FUNCTION_ARGS) { ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); - PG_RETURN_INT32(anytime_typmodin(true, ta)); + int32 typmod; + + if(!anytime_typmodin_safe(false, ta, &typmod, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_INT32(typmod); } Datum @@ -2593,7 +2669,7 @@ timestamptz_timetz(PG_FUNCTION_ARGS) PG_RETURN_NULL(); if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -2723,7 +2799,7 @@ timetz_part(PG_FUNCTION_ARGS) case DTK_CENTURY: case DTK_MILLENNIUM: default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"time with time zone\" units \"%s\" not recognized", lowunits))); @@ -2740,7 +2816,7 @@ timetz_part(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"time with time zone\" units \"%s\" not recognized", lowunits))); @@ -2782,7 +2858,8 @@ timetz_zone(PG_FUNCTION_ARGS) strlen(tzname), false); - type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp); + if (!DecodeTimezoneAbbrevSafe(0, lowzone, &val, &tzp, &type, fcinfo->context)) + PG_RETURN_NULL(); if (type == TZ || type == DTZ) { @@ -2813,7 +2890,7 @@ timetz_zone(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", tzname))); tz = 0; /* keep compiler quiet */ @@ -2853,7 +2930,7 @@ timetz_izone(PG_FUNCTION_ARGS) int tz; if (zone->month != 0 || zone->day != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval time zone \"%s\" must not include months or days", DatumGetCString(DirectFunctionCall1(interval_out, diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index dcf39e3e81..06db8c0b5d 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -69,6 +69,7 @@ static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst); static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp); +static bool FetchDynamicTimeZoneSafe(TimeZoneAbbrevTable *tbl, const datetkn *tp, pg_tz **result, Node *escontext); const int day_tab[2][13] = @@ -800,6 +801,15 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen, int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp) +{ + int result; + (void) DecodeDateTimeSafe(field, ftype, nf, dtype, tm, fsec, tzp, &result, NULL); + return result; +} + +bool +DecodeDateTimeSafe(char **field, int *ftype, int nf, + int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp, int *result, Node *escontext) { int fmask = 0, tmask, @@ -849,21 +859,27 @@ DecodeDateTime(char **field, int *ftype, int nf, char *cp; int val; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } errno = 0; val = strtoint(field[i], &cp, 10); - if (errno == ERANGE || val < 0) - return DTERR_FIELD_OVERFLOW; + if (errno == ERANGE || val < 0) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); isjulian = TRUE; /* Get the time zone from the end of the string */ dterr = DecodeTimezone(cp, tzp); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ); ptype = 0; @@ -885,8 +901,10 @@ DecodeDateTime(char **field, int *ftype, int nf, (DTK_M(MONTH) | DTK_M(DAY)))) { /* No time zone accepted? Then quit... */ - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } if (isdigit((unsigned char) *field[i]) || ptype != 0) { @@ -895,8 +913,10 @@ DecodeDateTime(char **field, int *ftype, int nf, if (ptype != 0) { /* Sanity check; should not fail this test */ - if (ptype != DTK_TIME) - return DTERR_BAD_FORMAT; + if (ptype != DTK_TIME) { + *result = DTERR_BAD_FORMAT; + return true; + } ptype = 0; } @@ -905,16 +925,22 @@ DecodeDateTime(char **field, int *ftype, int nf, * field? Then we are in trouble with a date and time * already... */ - if ((fmask & DTK_TIME_M) == DTK_TIME_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_TIME_M) == DTK_TIME_M) { + *result = DTERR_BAD_FORMAT; + return true; + } - if ((cp = strchr(field[i], '-')) == NULL) - return DTERR_BAD_FORMAT; + if ((cp = strchr(field[i], '-')) == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } /* Get the time zone from the end of the string */ dterr = DecodeTimezone(cp, tzp); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } *cp = '\0'; /* @@ -925,8 +951,10 @@ DecodeDateTime(char **field, int *ftype, int nf, fmask, &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } /* * modify tmask after returning from @@ -944,7 +972,7 @@ DecodeDateTime(char **field, int *ftype, int nf, * ereport'ing directly, but then there is no way * to report the bad time zone name. */ - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", field[i]))); @@ -957,8 +985,10 @@ DecodeDateTime(char **field, int *ftype, int nf, { dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } } break; @@ -970,14 +1000,18 @@ DecodeDateTime(char **field, int *ftype, int nf, if (ptype != 0) { /* Sanity check; should not fail this test */ - if (ptype != DTK_TIME) - return DTERR_BAD_FORMAT; + if (ptype != DTK_TIME) { + *result = DTERR_BAD_FORMAT; + return true; + } ptype = 0; } dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE, &tmask, tm, fsec); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } /* * Check upper limit on hours; other limits checked in @@ -986,20 +1020,26 @@ DecodeDateTime(char **field, int *ftype, int nf, /* test for > 24:00:00 */ if (tm->tm_hour > HOURS_PER_DAY || (tm->tm_hour == HOURS_PER_DAY && - (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0))) - return DTERR_FIELD_OVERFLOW; + (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0))) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } break; case DTK_TZ: { int tz; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } dterr = DecodeTimezone(field[i], &tz); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } *tzp = tz; tmask = DTK_M(TZ); } @@ -1018,8 +1058,10 @@ DecodeDateTime(char **field, int *ftype, int nf, errno = 0; val = strtoint(field[i], &cp, 10); - if (errno == ERANGE) - return DTERR_FIELD_OVERFLOW; + if (errno == ERANGE) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } /* * only a few kinds are allowed to have an embedded @@ -1033,11 +1075,14 @@ DecodeDateTime(char **field, int *ftype, int nf, case DTK_SECOND: break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; break; } - else if (*cp != '\0') - return DTERR_BAD_FORMAT; + else if (*cp != '\0') { + *result = DTERR_BAD_FORMAT; + return true; + } switch (ptype) { @@ -1086,8 +1131,10 @@ DecodeDateTime(char **field, int *ftype, int nf, if (*cp == '.') { dterr = ParseFractionalSecond(cp, fsec); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } tmask = DTK_ALL_SECS_M; } break; @@ -1095,14 +1142,18 @@ DecodeDateTime(char **field, int *ftype, int nf, case DTK_TZ: tmask = DTK_M(TZ); dterr = DecodeTimezone(field[i], tzp); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } break; case DTK_JULIAN: /* previous field was a label for "julian date" */ - if (val < 0) - return DTERR_FIELD_OVERFLOW; + if (val < 0) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } tmask = DTK_DATE_M; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); isjulian = TRUE; @@ -1114,8 +1165,10 @@ DecodeDateTime(char **field, int *ftype, int nf, errno = 0; time = strtod(cp, &cp); - if (*cp != '\0' || errno != 0) - return DTERR_BAD_FORMAT; + if (*cp != '\0' || errno != 0) { + *result = DTERR_BAD_FORMAT; + return true; + } #ifdef HAVE_INT64_TIMESTAMP time *= USECS_PER_DAY; @@ -1135,14 +1188,19 @@ DecodeDateTime(char **field, int *ftype, int nf, (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; - if (tmask != DTK_TIME_M) - return DTERR_BAD_FORMAT; + if (dterr < 0) { + *result = dterr; + return true; + } + if (tmask != DTK_TIME_M) { + *result = DTERR_BAD_FORMAT; + return true; + } break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; break; } @@ -1165,8 +1223,10 @@ DecodeDateTime(char **field, int *ftype, int nf, { dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } } /* embedded decimal and several digits before? */ else if (cp != NULL && flen - strlen(cp) > 2) @@ -1179,8 +1239,10 @@ DecodeDateTime(char **field, int *ftype, int nf, dterr = DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } } /* @@ -1198,8 +1260,10 @@ DecodeDateTime(char **field, int *ftype, int nf, dterr = DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } } /* otherwise it is a single date/time field... */ else @@ -1208,8 +1272,10 @@ DecodeDateTime(char **field, int *ftype, int nf, haveTextMonth, fmask, &tmask, tm, fsec, &is2digits); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } } } break; @@ -1217,7 +1283,8 @@ DecodeDateTime(char **field, int *ftype, int nf, case DTK_STRING: case DTK_SPECIAL: /* timezone abbrevs take precedence over built-in tokens */ - type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz); + if (!DecodeTimezoneAbbrevSafe(i, field[i], &val, &valtz, &type, escontext)) + return false; if (type == UNKNOWN_FIELD) type = DecodeSpecial(i, field[i], &val); if (type == IGNORE_DTF) @@ -1230,11 +1297,12 @@ DecodeDateTime(char **field, int *ftype, int nf, switch (val) { case DTK_CURRENT: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"current\" is no longer supported"))); - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; break; case DTK_NOW: @@ -1309,8 +1377,10 @@ DecodeDateTime(char **field, int *ftype, int nf, */ tmask |= DTK_M(DTZ); tm->tm_isdst = 1; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp -= val; break; @@ -1322,22 +1392,28 @@ DecodeDateTime(char **field, int *ftype, int nf, */ tmask |= DTK_M(TZ); tm->tm_isdst = 1; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = -val; break; case TZ: tm->tm_isdst = 0; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = -val; break; case DYNTZ: tmask |= DTK_M(TZ); - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } /* we'll determine the actual offset later */ abbrevTz = valtz; abbrev = field[i]; @@ -1369,8 +1445,10 @@ DecodeDateTime(char **field, int *ftype, int nf, tmask = 0; /* No preceding date? Then quit... */ - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_DATE_M) != DTK_DATE_M) { + *result = DTERR_BAD_FORMAT; + return true; + } /*** * We will need one of the following fields: @@ -1381,8 +1459,10 @@ DecodeDateTime(char **field, int *ftype, int nf, if (i >= nf - 1 || (ftype[i + 1] != DTK_NUMBER && ftype[i + 1] != DTK_TIME && - ftype[i + 1] != DTK_DATE)) - return DTERR_BAD_FORMAT; + ftype[i + 1] != DTK_DATE)) { + *result = DTERR_BAD_FORMAT; + return true; + } ptype = val; break; @@ -1394,30 +1474,38 @@ DecodeDateTime(char **field, int *ftype, int nf, * if it is an all-alpha timezone name. */ namedTz = pg_tzset(field[i]); - if (!namedTz) - return DTERR_BAD_FORMAT; + if (!namedTz) { + *result = DTERR_BAD_FORMAT; + return true; + } /* we'll apply the zone setting below */ tmask = DTK_M(TZ); break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; } break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; } - if (tmask & fmask) - return DTERR_BAD_FORMAT; + if (tmask & fmask) { + *result = DTERR_BAD_FORMAT; + return true; + } fmask |= tmask; } /* end loop over fields */ /* do final checking/adjustment of Y/M/D fields */ dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } /* handle AM/PM */ if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2) @@ -1432,9 +1520,12 @@ DecodeDateTime(char **field, int *ftype, int nf, { if ((fmask & DTK_DATE_M) != DTK_DATE_M) { - if ((fmask & DTK_TIME_M) == DTK_TIME_M) - return 1; - return DTERR_BAD_FORMAT; + if ((fmask & DTK_TIME_M) == DTK_TIME_M) { + *result = 1; + return true; + } + *result = DTERR_BAD_FORMAT; + return true; } /* @@ -1444,8 +1535,10 @@ DecodeDateTime(char **field, int *ftype, int nf, if (namedTz != NULL) { /* daylight savings time modifier disallowed with full TZ */ - if (fmask & DTK_M(DTZMOD)) - return DTERR_BAD_FORMAT; + if (fmask & DTK_M(DTZMOD)) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = DetermineTimeZoneOffset(tm, namedTz); } @@ -1457,8 +1550,10 @@ DecodeDateTime(char **field, int *ftype, int nf, if (abbrevTz != NULL) { /* daylight savings time modifier disallowed with dynamic TZ */ - if (fmask & DTK_M(DTZMOD)) - return DTERR_BAD_FORMAT; + if (fmask & DTK_M(DTZMOD)) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = DetermineTimeZoneAbbrevOffset(tm, abbrev, abbrevTz); } @@ -1470,14 +1565,17 @@ DecodeDateTime(char **field, int *ftype, int nf, * daylight savings time modifier but no standard timezone? then * error */ - if (fmask & DTK_M(DTZMOD)) - return DTERR_BAD_FORMAT; + if (fmask & DTK_M(DTZMOD)) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = DetermineTimeZoneOffset(tm, session_timezone); } } - return 0; + *result = 0; + return true; } @@ -1695,6 +1793,15 @@ DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp) int DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst) +{ + int result; + (void) DetermineTimeZoneAbbrevOffsetTSSafe(ts, abbr, tzp, isdst, &result, NULL); + return result; +} + +bool +DetermineTimeZoneAbbrevOffsetTSSafe(TimestampTz ts, const char *abbr, + pg_tz *tzp, int *isdst, int *result, Node *escontext) { pg_time_t t = timestamptz_to_time_t(ts); int zone_offset; @@ -1707,20 +1814,23 @@ DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, * If the abbrev matches anything in the zone data, this is pretty easy. */ if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, - &abbr_offset, isdst)) - return abbr_offset; + &abbr_offset, isdst)) { + *result = abbr_offset; + return true; + } /* * Else, break down the timestamp so we can use DetermineTimeZoneOffset. */ if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); zone_offset = DetermineTimeZoneOffset(&tm, tzp); *isdst = tm.tm_isdst; - return zone_offset; + *result = zone_offset; + return true; } @@ -1772,6 +1882,15 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp) +{ + int result; + (void) DecodeTimeOnlySafe(field, ftype, nf, dtype, tm, fsec, tzp, &result, NULL); + return result; +} + +bool +DecodeTimeOnlySafe(char **field, int *ftype, int nf, + int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp, int *result, Node *escontext) { int fmask = 0, tmask, @@ -1810,8 +1929,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, * Time zone not allowed? Then should not accept dates or time * zones no matter what else! */ - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } /* Under limited circumstances, we will accept a date... */ if (i == 0 && nf >= 2 && @@ -1819,8 +1940,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, { dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } } /* otherwise, this is a time and/or time zone */ else @@ -1833,19 +1956,25 @@ DecodeTimeOnly(char **field, int *ftype, int nf, * Starts with a digit but we already have a time * field? Then we are in trouble with time already... */ - if ((fmask & DTK_TIME_M) == DTK_TIME_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_TIME_M) == DTK_TIME_M) { + *result = DTERR_BAD_FORMAT; + return true; + } /* * Should not get here and fail. Sanity check only... */ - if ((cp = strchr(field[i], '-')) == NULL) - return DTERR_BAD_FORMAT; + if ((cp = strchr(field[i], '-')) == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } /* Get the time zone from the end of the string */ dterr = DecodeTimezone(cp, tzp); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } *cp = '\0'; /* @@ -1856,8 +1985,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } ftype[i] = dterr; tmask |= DTK_M(TZ); @@ -1872,7 +2003,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, * ereport'ing directly, but then there is no way * to report the bad time zone name. */ - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", field[i]))); @@ -1888,20 +2019,26 @@ DecodeTimeOnly(char **field, int *ftype, int nf, dterr = DecodeTime(field[i], (fmask | DTK_DATE_M), INTERVAL_FULL_RANGE, &tmask, tm, fsec); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } break; case DTK_TZ: { int tz; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } dterr = DecodeTimezone(field[i], &tz); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } *tzp = tz; tmask = DTK_M(TZ); } @@ -1925,16 +2062,20 @@ DecodeTimeOnly(char **field, int *ftype, int nf, case DTK_YEAR: case DTK_MONTH: case DTK_DAY: - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } default: break; } errno = 0; val = strtoint(field[i], &cp, 10); - if (errno == ERANGE) - return DTERR_FIELD_OVERFLOW; + if (errno == ERANGE) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } /* * only a few kinds are allowed to have an embedded @@ -1948,11 +2089,14 @@ DecodeTimeOnly(char **field, int *ftype, int nf, case DTK_SECOND: break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; break; } - else if (*cp != '\0') - return DTERR_BAD_FORMAT; + else if (*cp != '\0') { + *result = DTERR_BAD_FORMAT; + return true; + } switch (ptype) { @@ -2001,8 +2145,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, if (*cp == '.') { dterr = ParseFractionalSecond(cp, fsec); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } tmask = DTK_ALL_SECS_M; } break; @@ -2010,14 +2156,18 @@ DecodeTimeOnly(char **field, int *ftype, int nf, case DTK_TZ: tmask = DTK_M(TZ); dterr = DecodeTimezone(field[i], tzp); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } break; case DTK_JULIAN: /* previous field was a label for "julian date" */ - if (val < 0) - return DTERR_FIELD_OVERFLOW; + if (val < 0) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } tmask = DTK_DATE_M; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); isjulian = TRUE; @@ -2028,8 +2178,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, errno = 0; time = strtod(cp, &cp); - if (*cp != '\0' || errno != 0) - return DTERR_BAD_FORMAT; + if (*cp != '\0' || errno != 0) { + *result = DTERR_BAD_FORMAT; + return true; + } #ifdef HAVE_INT64_TIMESTAMP time *= USECS_PER_DAY; @@ -2049,16 +2201,21 @@ DecodeTimeOnly(char **field, int *ftype, int nf, (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } ftype[i] = dterr; - if (tmask != DTK_TIME_M) - return DTERR_BAD_FORMAT; + if (tmask != DTK_TIME_M) { + *result = DTERR_BAD_FORMAT; + return true; + } break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; break; } @@ -2084,8 +2241,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, { dterr = DecodeDate(field[i], fmask, &tmask, &is2digits, tm); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } } /* embedded decimal and several digits before? */ else if (flen - strlen(cp) > 2) @@ -2099,12 +2258,16 @@ DecodeTimeOnly(char **field, int *ftype, int nf, (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } ftype[i] = dterr; } - else - return DTERR_BAD_FORMAT; + else { + *result = DTERR_BAD_FORMAT; + return true; + } } else if (flen > 4) { @@ -2112,8 +2275,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); - if (dterr < 0) - return dterr; + if (dterr < 0) { + *result = dterr; + return true; + } ftype[i] = dterr; } /* otherwise it is a single date/time field... */ @@ -2124,8 +2289,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } } } break; @@ -2133,7 +2300,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf, case DTK_STRING: case DTK_SPECIAL: /* timezone abbrevs take precedence over built-in tokens */ - type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz); + if (!DecodeTimezoneAbbrevSafe(i, field[i], &val, &valtz, &type, escontext)) + return false; if (type == UNKNOWN_FIELD) type = DecodeSpecial(i, field[i], &val); if (type == IGNORE_DTF) @@ -2146,10 +2314,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf, switch (val) { case DTK_CURRENT: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"current\" is no longer supported"))); - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; break; case DTK_NOW: @@ -2168,7 +2337,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf, break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; } break; @@ -2181,8 +2351,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, */ tmask |= DTK_M(DTZ); tm->tm_isdst = 1; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp -= val; break; @@ -2194,24 +2366,30 @@ DecodeTimeOnly(char **field, int *ftype, int nf, */ tmask |= DTK_M(TZ); tm->tm_isdst = 1; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = -val; ftype[i] = DTK_TZ; break; case TZ: tm->tm_isdst = 0; - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = -val; ftype[i] = DTK_TZ; break; case DYNTZ: tmask |= DTK_M(TZ); - if (tzp == NULL) - return DTERR_BAD_FORMAT; + if (tzp == NULL) { + *result = DTERR_BAD_FORMAT; + return true; + } /* we'll determine the actual offset later */ abbrevTz = valtz; abbrev = field[i]; @@ -2243,8 +2421,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, if (i >= nf - 1 || (ftype[i + 1] != DTK_NUMBER && ftype[i + 1] != DTK_TIME && - ftype[i + 1] != DTK_DATE)) - return DTERR_BAD_FORMAT; + ftype[i + 1] != DTK_DATE)) { + *result = DTERR_BAD_FORMAT; + return true; + } ptype = val; break; @@ -2256,34 +2436,44 @@ DecodeTimeOnly(char **field, int *ftype, int nf, * if it is an all-alpha timezone name. */ namedTz = pg_tzset(field[i]); - if (!namedTz) - return DTERR_BAD_FORMAT; + if (!namedTz) { + *result = DTERR_BAD_FORMAT; + return true; + } /* we'll apply the zone setting below */ tmask = DTK_M(TZ); break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; } break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; } - if (tmask & fmask) - return DTERR_BAD_FORMAT; + if (tmask & fmask) { + *result = DTERR_BAD_FORMAT; + return true; + } fmask |= tmask; } /* end loop over fields */ /* do final checking/adjustment of Y/M/D fields */ dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm); - if (dterr) - return dterr; + if (dterr) { + *result = dterr; + return true; + } /* handle AM/PM */ - if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2) - return DTERR_FIELD_OVERFLOW; + if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2) tm->tm_hour = 0; else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2) @@ -2303,11 +2493,15 @@ DecodeTimeOnly(char **field, int *ftype, int nf, #else *fsec < 0 || *fsec > 1 #endif - ) - return DTERR_FIELD_OVERFLOW; + ) { + *result = DTERR_FIELD_OVERFLOW; + return true; + } - if ((fmask & DTK_TIME_M) != DTK_TIME_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_TIME_M) != DTK_TIME_M ) { + *result = DTERR_BAD_FORMAT; + return true; + } /* * If we had a full timezone spec, compute the offset (we could not do it @@ -2318,8 +2512,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, long int gmtoff; /* daylight savings time modifier disallowed with full TZ */ - if (fmask & DTK_M(DTZMOD)) - return DTERR_BAD_FORMAT; + if (fmask & DTK_M(DTZMOD)) { + *result = DTERR_BAD_FORMAT; + return true; + } /* if non-DST zone, we do not need to know the date */ if (pg_get_timezone_offset(namedTz, &gmtoff)) @@ -2329,8 +2525,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf, else { /* a date has to be specified */ - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_DATE_M) != DTK_DATE_M) { + *result = DTERR_BAD_FORMAT; + return true; + } *tzp = DetermineTimeZoneOffset(tm, namedTz); } } @@ -2346,16 +2544,20 @@ DecodeTimeOnly(char **field, int *ftype, int nf, /* * daylight savings time modifier but no standard timezone? then error */ - if (fmask & DTK_M(DTZMOD)) - return DTERR_BAD_FORMAT; + if (fmask & DTK_M(DTZMOD)) { + *result = DTERR_BAD_FORMAT; + return true; + } if ((fmask & DTK_DATE_M) == 0) GetCurrentDateTime(tmp); else { /* a date has to be specified */ - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_DATE_M) != DTK_DATE_M) { + *result = DTERR_BAD_FORMAT; + return true; + } tmp->tm_year = tm->tm_year; tmp->tm_mon = tm->tm_mon; tmp->tm_mday = tm->tm_mday; @@ -2376,16 +2578,20 @@ DecodeTimeOnly(char **field, int *ftype, int nf, /* * daylight savings time modifier but no standard timezone? then error */ - if (fmask & DTK_M(DTZMOD)) - return DTERR_BAD_FORMAT; + if (fmask & DTK_M(DTZMOD)) { + *result = DTERR_BAD_FORMAT; + return true; + } if ((fmask & DTK_DATE_M) == 0) GetCurrentDateTime(tmp); else { /* a date has to be specified */ - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return DTERR_BAD_FORMAT; + if ((fmask & DTK_DATE_M) != DTK_DATE_M) { + *result = DTERR_BAD_FORMAT; + return true; + } tmp->tm_year = tm->tm_year; tmp->tm_mon = tm->tm_mon; tmp->tm_mday = tm->tm_mday; @@ -2397,7 +2603,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf, tm->tm_isdst = tmp->tm_isdst; } - return 0; + *result = 0; + return true; } /* DecodeDate() @@ -3070,6 +3277,15 @@ DecodeTimezone(char *str, int *tzp) int DecodeTimezoneAbbrev(int field, char *lowtoken, int *offset, pg_tz **tz) +{ + int result = 0; + (void) DecodeTimezoneAbbrevSafe(field, lowtoken, offset, tz, &result, NULL); + return result; +} + +bool +DecodeTimezoneAbbrevSafe(int field, char *lowtoken, + int *offset, pg_tz **tz, int *result, Node *escontext) { int type; const datetkn *tp; @@ -3097,7 +3313,8 @@ DecodeTimezoneAbbrev(int field, char *lowtoken, if (type == DYNTZ) { *offset = 0; - *tz = FetchDynamicTimeZone(zoneabbrevtbl, tp); + if (!FetchDynamicTimeZoneSafe(zoneabbrevtbl, tp, tz, escontext)) + return false; } else { @@ -3106,7 +3323,8 @@ DecodeTimezoneAbbrev(int field, char *lowtoken, } } - return type; + *result = type; + return true; } @@ -3868,38 +4086,44 @@ DecodeUnits(int field, char *lowtoken, int *val) */ void DateTimeParseError(int dterr, const char *str, const char *datatype) +{ + (void) DateTimeParseErrorSafe(dterr, str, datatype, NULL); +} + +bool +DateTimeParseErrorSafe(int dterr, const char *str, const char *datatype, Node *escontext) { switch (dterr) { case DTERR_FIELD_OVERFLOW: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), errmsg("date/time field value out of range: \"%s\"", str))); break; case DTERR_MD_FIELD_OVERFLOW: /* same as above, but add hint about DateStyle */ - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), errmsg("date/time field value out of range: \"%s\"", str), errhint("Perhaps you need a different \"datestyle\" setting."))); break; case DTERR_INTERVAL_OVERFLOW: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW), errmsg("interval field value out of range: \"%s\"", str))); break; case DTERR_TZDISP_OVERFLOW: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE), errmsg("time zone displacement out of range: \"%s\"", str))); break; case DTERR_BAD_FORMAT: default: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid input syntax for type %s: \"%s\"", datatype, str))); @@ -4716,6 +4940,14 @@ InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl) */ static pg_tz * FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp) +{ + pg_tz *result; + FetchDynamicTimeZoneSafe(tbl, tp, &result, NULL); + return result; +} + +static bool +FetchDynamicTimeZoneSafe(TimeZoneAbbrevTable *tbl, const datetkn *tp, pg_tz **result, Node *escontext) { DynamicZoneAbbrev *dtza; @@ -4735,14 +4967,15 @@ FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp) * then there is no way to report the bad time zone name. */ if (dtza->tz == NULL) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("time zone \"%s\" not recognized", dtza->zone), errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".", tp->token))); } - return dtza->tz; + *result = dtza->tz; + return true; } @@ -4828,13 +5061,20 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS) pg_tz *tzp; TimestampTz now; int isdst; + int ngmtoffset; - tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp); + if (!FetchDynamicTimeZoneSafe(zoneabbrevtbl, tp, &tzp, fcinfo->context)) + PG_RETURN_NULL(); now = GetCurrentTransactionStartTimestamp(); - gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now, - tp->token, - tzp, - &isdst); + if (!DetermineTimeZoneAbbrevOffsetTSSafe(now, + tp->token, + tzp, + &isdst, + &ngmtoffset, + fcinfo->context)) + PG_RETURN_NULL(); + gmtoffset = -ngmtoffset; + is_dst = (bool) isdst; break; } diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 74adce994f..cde1821051 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -964,6 +964,8 @@ static int from_char_seq_search(int *dest, const char **src, FormatNode *node); static void do_to_timestamp(text *date_txt, text *fmt, struct pg_tm * tm, fsec_t *fsec); +static bool do_to_timestamp_safe(text *date_txt, text *fmt, + struct pg_tm * tm, fsec_t *fsec, Node *escontext); static char *fill_str(char *str, int c, int max); static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree); static char *int_to_roman(int number); @@ -2360,8 +2362,17 @@ from_char_seq_search(int *dest, const char **src, const char *const *array, * The formatted data is written to the string pointed to by 'out'. * ---------- */ +static bool +DCH_to_char_safe(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid, Node *escontext); + static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid) +{ + (void) DCH_to_char_safe(node, is_interval, in, out, collid, NULL); +} + +static bool +DCH_to_char_safe(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid, Node *escontext) { FormatNode *n; char *s; @@ -2538,7 +2549,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2558,7 +2569,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2578,7 +2589,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2598,7 +2609,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2617,7 +2628,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2636,7 +2647,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2659,7 +2670,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2677,7 +2688,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2695,7 +2706,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2713,7 +2724,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2730,7 +2741,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2747,7 +2758,7 @@ 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 - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("localized string format value too long"))); } @@ -2920,6 +2931,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col } *s = '\0'; + return true; } /* ---------- @@ -2930,8 +2942,17 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col * is no need here for INVALID_FOR_INTERVAL checks. * ---------- */ +static bool +DCH_from_char_safe(FormatNode *node, const char *in, TmFromChar *out, Node *escontext); + static void DCH_from_char(FormatNode *node, const char *in, TmFromChar *out) +{ + (void) DCH_from_char_safe(node, in, out, NULL); +} + +static bool +DCH_from_char_safe(FormatNode *node, const char *in, TmFromChar *out, Node *escontext) { FormatNode *n; const char *s; @@ -3031,7 +3052,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out) case DCH_tz: case DCH_TZ: case DCH_OF: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("\"TZ\"/\"tz\"/\"OF\" format patterns are not supported in to_date"))); break; @@ -3141,7 +3162,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out) matched = sscanf(s, "%d,%03d%n", &millenia, &years, &nch); if (matched < 2) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid input string for \"Y,YYY\" in function \"to_date\""))); years += (millenia * 1000); @@ -3194,6 +3215,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out) break; } } + return true; } static DCHCacheEntry * @@ -3279,8 +3301,19 @@ DCH_cache_search(char *str) * We parse fmt into a list of FormatNodes. This is then passed to DCH_to_char * for formatting. */ +static bool +datetime_to_char_body_safe(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid, text **result_text, Node *escontext); + static text * datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) +{ + text *result; + (void) datetime_to_char_body_safe(tmtc, fmt, is_interval, collid, &result, NULL); + return result; + +} +static bool +datetime_to_char_body_safe(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid, text **result_text, Node *escontext) { FormatNode *format; char *fmt_str, @@ -3348,7 +3381,14 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) } /* The real work is here */ - DCH_to_char(format, is_interval, tmtc, result, collid); + if (!DCH_to_char_safe(format, is_interval, tmtc, result, collid, escontext)) { + if (!incache) + pfree(format); + pfree(fmt_str); + pfree(result); + + return false; + } if (!incache) pfree(format); @@ -3359,7 +3399,9 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) res = cstring_to_text(result); pfree(result); - return res; + + *result_text = res; + return true; } /**************************************************************************** @@ -3387,7 +3429,7 @@ timestamp_to_char(PG_FUNCTION_ARGS) tm = tmtcTm(&tmtc); if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range for function \"to_char\""))); @@ -3395,7 +3437,10 @@ timestamp_to_char(PG_FUNCTION_ARGS) tm->tm_wday = (thisdate + 1) % 7; tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1; - if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION()))) + if (!datetime_to_char_body_safe(&tmtc, fmt, false, PG_GET_COLLATION(), &res, fcinfo->context)) + PG_RETURN_NULL(); + + if (!res) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); @@ -3419,7 +3464,7 @@ timestamptz_to_char(PG_FUNCTION_ARGS) tm = tmtcTm(&tmtc); if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range for function \"to_char\""))); @@ -3427,7 +3472,10 @@ timestamptz_to_char(PG_FUNCTION_ARGS) tm->tm_wday = (thisdate + 1) % 7; tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1; - if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION()))) + if (!datetime_to_char_body_safe(&tmtc, fmt, false, PG_GET_COLLATION(), &res, fcinfo->context)) + PG_RETURN_NULL(); + + if (!res) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); @@ -3459,7 +3507,10 @@ interval_to_char(PG_FUNCTION_ARGS) /* wday is meaningless, yday approximates the total span in days */ tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday; - if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION()))) + if (!datetime_to_char_body_safe(&tmtc, fmt, true, PG_GET_COLLATION(), &res, fcinfo->context)) + PG_RETURN_NULL(); + + if (!res) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); @@ -3482,12 +3533,13 @@ to_timestamp(PG_FUNCTION_ARGS) struct pg_tm tm; fsec_t fsec; - do_to_timestamp(date_txt, fmt, &tm, &fsec); + if (!do_to_timestamp_safe(date_txt, fmt, &tm, &fsec, fcinfo->context)) + PG_RETURN_NULL(); tz = DetermineTimeZoneOffset(&tm, session_timezone); if (tm2timestamp(&tm, fsec, &tz, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range for function \"to_timestamp\""))); @@ -3508,10 +3560,11 @@ to_date(PG_FUNCTION_ARGS) struct pg_tm tm; fsec_t fsec; - do_to_timestamp(date_txt, fmt, &tm, &fsec); + if (!do_to_timestamp_safe(date_txt, fmt, &tm, &fsec, fcinfo->context)) + PG_RETURN_NULL(); if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); @@ -3537,6 +3590,13 @@ to_date(PG_FUNCTION_ARGS) static void do_to_timestamp(text *date_txt, text *fmt, struct pg_tm * tm, fsec_t *fsec) +{ + (void) do_to_timestamp_safe(date_txt, fmt, tm, fsec, NULL); +} + +static bool +do_to_timestamp_safe(text *date_txt, text *fmt, + struct pg_tm * tm, fsec_t *fsec, Node *escontext) { FormatNode *format; TmFromChar tmfc; @@ -3607,7 +3667,12 @@ do_to_timestamp(text *date_txt, text *fmt, /* dump_index(DCH_keywords, DCH_index); */ #endif - DCH_from_char(format, date_str, &tmfc); + if (!DCH_from_char_safe(format, date_str, &tmfc, escontext)){ + pfree(fmt_str); + if (!incache) + pfree(format); + return false; + } pfree(fmt_str); if (!incache) @@ -3652,7 +3717,7 @@ do_to_timestamp(text *date_txt, text *fmt, tm->tm_hour = tm->tm_hour - HOURS_PER_DAY / 2; } else - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("hour \"%d\" is invalid for the 12-hour clock", tm->tm_hour), @@ -3761,7 +3826,7 @@ do_to_timestamp(text *date_txt, text *fmt, */ if (!tm->tm_year && !tmfc.bc) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("cannot calculate day of year without year information"))); @@ -3825,7 +3890,8 @@ do_to_timestamp(text *date_txt, text *fmt, * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an * irrelevant hint about datestyle. */ - DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"); + if (!DateTimeParseErrorSafe(DTERR_FIELD_OVERFLOW, date_str, "timestamp", escontext)) + return false; } } @@ -3839,11 +3905,14 @@ do_to_timestamp(text *date_txt, text *fmt, *fsec < 0 || *fsec >= 1 #endif ) - DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"); + if (!DateTimeParseErrorSafe(DTERR_FIELD_OVERFLOW, date_str, "timestamp", escontext)) + return false; DEBUG_TM(tm); pfree(date_str); + + return true; } diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 6ec7ebafb8..7bd01cc38a 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -75,6 +75,10 @@ static void reltime2tm(RelativeTime time, struct pg_tm * tm); static void parsetinterval(char *i_string, AbsoluteTime *i_start, AbsoluteTime *i_end); +static bool parsetinterval_safe(char *i_string, + AbsoluteTime *i_start, + AbsoluteTime *i_end, + Node *escontext); /* @@ -213,9 +217,11 @@ abstimein(PG_FUNCTION_ARGS) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) - dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); + if (!DecodeDateTimeSafe(field, ftype, nf, &dtype, tm, &fsec, &tz, &dterr, fcinfo->context)) + PG_RETURN_NULL(); if (dterr != 0) - DateTimeParseError(dterr, str, "abstime"); + if (!DateTimeParseErrorSafe(dterr, str, "abstime", fcinfo->context)) + PG_RETURN_NULL(); switch (dtype) { @@ -453,7 +459,7 @@ timestamp_abstime(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); result = INVALID_ABSTIME; @@ -479,7 +485,7 @@ abstime_timestamp(PG_FUNCTION_ARGS) switch (abstime) { case INVALID_ABSTIME: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert abstime \"invalid\" to timestamp"))); TIMESTAMP_NOBEGIN(result); @@ -496,7 +502,7 @@ abstime_timestamp(PG_FUNCTION_ARGS) default: abstime2tm(abstime, &tz, tm, &tzn); if (tm2timestamp(tm, 0, NULL, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); break; @@ -526,7 +532,7 @@ timestamptz_abstime(PG_FUNCTION_ARGS) result = tm2abstime(tm, 0); else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); result = INVALID_ABSTIME; @@ -552,7 +558,7 @@ abstime_timestamptz(PG_FUNCTION_ARGS) switch (abstime) { case INVALID_ABSTIME: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert abstime \"invalid\" to timestamp"))); TIMESTAMP_NOBEGIN(result); @@ -569,7 +575,7 @@ abstime_timestamptz(PG_FUNCTION_ARGS) default: abstime2tm(abstime, &tz, tm, &tzn); if (tm2timestamp(tm, 0, &tz, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); break; @@ -616,7 +622,8 @@ reltimein(PG_FUNCTION_ARGS) { if (dterr == DTERR_FIELD_OVERFLOW) dterr = DTERR_INTERVAL_OVERFLOW; - DateTimeParseError(dterr, str, "reltime"); + if (!DateTimeParseErrorSafe(dterr, str, "reltime", fcinfo->context)) + PG_RETURN_NULL(); } switch (dtype) @@ -708,7 +715,8 @@ tintervalin(PG_FUNCTION_ARGS) t1, t2; - parsetinterval(tintervalstr, &t1, &t2); + if (!parsetinterval_safe(tintervalstr, &t1, &t2, fcinfo->context)) + PG_RETURN_NULL(); tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData)); @@ -779,7 +787,7 @@ tintervalrecv(PG_FUNCTION_ARGS) status = T_INTERVAL_VALID; if (status != tinterval->status) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid status in external \"tinterval\" value"))); @@ -853,7 +861,7 @@ reltime_interval(PG_FUNCTION_ARGS) switch (reltime) { case INVALID_RELTIME: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert reltime \"invalid\" to interval"))); result->time = 0; @@ -1446,6 +1454,14 @@ static void parsetinterval(char *i_string, AbsoluteTime *i_start, AbsoluteTime *i_end) +{ + (void) parsetinterval_safe(i_string, i_start, i_end, NULL); +} +static bool +parsetinterval_safe(char *i_string, + AbsoluteTime *i_start, + AbsoluteTime *i_end, + Node *escontext) { char *p, *p1; @@ -1545,14 +1561,15 @@ parsetinterval(char *i_string, goto bogus; /* syntax error */ /* it seems to be a valid tinterval */ - return; + return true; bogus: - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid input syntax for type tinterval: \"%s\"", i_string))); *i_start = *i_end = INVALID_ABSTIME; /* keep compiler quiet */ + return false; } diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 522ea2d2ec..bfc6551b6b 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -33,6 +33,7 @@ #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "nodes/execnodes.h" +#include "nodes/miscnodes.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/int8.h" @@ -405,6 +406,7 @@ static void alloc_var(NumericVar *var, int ndigits); static void zero_var(NumericVar *var); static const char *init_var_from_str(const char *str, const char *cp, NumericVar *dest); +static bool init_var_from_str_safe(const char *str, const char *cp, NumericVar *dest, const char **endptr, Node* escontext); static void set_var_from_var(NumericVar *value, NumericVar *dest); static void init_var_from_var(NumericVar *value, NumericVar *dest); static void init_ro_var_from_var(NumericVar *value, NumericVar *dest); @@ -421,16 +423,16 @@ static Numeric make_result(NumericVar *var); * ---------- */ -static void apply_typmod(NumericVar *var, int32 typmod); +static bool apply_typmod(NumericVar *var, int32 typmod, Node *escontext); -static int32 numericvar_to_int32(NumericVar *var); +static bool numericvar_to_int32(NumericVar *var, int32 *result, Node* escontext); static bool numericvar_to_int64(NumericVar *var, int64 *result); static void int64_to_numericvar(int64 val, NumericVar *var); #ifdef HAVE_INT128 static bool numericvar_to_int128(NumericVar *var, int128 *result); static void int128_to_numericvar(int128 val, NumericVar *var); #endif -static double numericvar_to_double_no_overflow(NumericVar *var); +static bool numericvar_to_double_no_overflow(NumericVar *var, double *result, Node *escontext); static int cmp_var(NumericVar *var1, NumericVar *var2); static int cmp_var_common(const NumericDigit *var1digits, int var1ndigits, @@ -497,6 +499,7 @@ numeric_in(PG_FUNCTION_ARGS) int32 typmod = PG_GETARG_INT32(2); Numeric res; const char *cp; + Node *escontext = fcinfo->context; /* Skip leading spaces */ cp = str; @@ -519,7 +522,7 @@ numeric_in(PG_FUNCTION_ARGS) while (*cp) { if (!isspace((unsigned char) *cp)) - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type numeric: \"%s\"", str))); @@ -534,7 +537,8 @@ numeric_in(PG_FUNCTION_ARGS) */ NumericVar value; - cp = init_var_from_str(str, cp, &value); + if(!init_var_from_str_safe(str, cp, &value, &cp, escontext)) + PG_RETURN_NULL(); /* * We duplicate a few lines of code here because we would like to @@ -545,14 +549,15 @@ numeric_in(PG_FUNCTION_ARGS) while (*cp) { if (!isspace((unsigned char) *cp)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type numeric: \"%s\"", str))); cp++; } - apply_typmod(&value, typmod); + if(!apply_typmod(&value, typmod, fcinfo->context)) + PG_RETURN_NULL(); res = make_result(&value); free_var(&value); @@ -765,13 +770,13 @@ numeric_recv(PG_FUNCTION_ARGS) if (!(value.sign == NUMERIC_POS || value.sign == NUMERIC_NEG || value.sign == NUMERIC_NAN)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid sign in external \"numeric\" value"))); value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16)); if ((value.dscale & NUMERIC_DSCALE_MASK) != value.dscale) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid scale in external \"numeric\" value"))); @@ -780,7 +785,7 @@ numeric_recv(PG_FUNCTION_ARGS) NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit)); if (d < 0 || d >= NBASE) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid digit in external \"numeric\" value"))); value.digits[i] = d; @@ -794,7 +799,7 @@ numeric_recv(PG_FUNCTION_ARGS) */ trunc_var(&value, value.dscale); - apply_typmod(&value, typmod); + apply_typmod(&value, typmod, NULL); res = make_result(&value); @@ -949,7 +954,8 @@ numeric (PG_FUNCTION_ARGS) init_var(&var); set_var_from_num(num, &var); - apply_typmod(&var, typmod); + if(!apply_typmod(&var, typmod, fcinfo->context)) + PG_RETURN_NULL(); new = make_result(&var); free_var(&var); @@ -970,12 +976,12 @@ numerictypmodin(PG_FUNCTION_ARGS) if (n == 2) { if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("NUMERIC precision %d must be between 1 and %d", tl[0], NUMERIC_MAX_PRECISION))); if (tl[1] < 0 || tl[1] > tl[0]) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("NUMERIC scale %d must be between 0 and precision %d", tl[1], tl[0]))); @@ -984,7 +990,7 @@ numerictypmodin(PG_FUNCTION_ARGS) else if (n == 1) { if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("NUMERIC precision %d must be between 1 and %d", tl[0], NUMERIC_MAX_PRECISION))); @@ -993,7 +999,7 @@ numerictypmodin(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid NUMERIC type modifier"))); typmod = 0; /* keep compiler quiet */ @@ -1313,7 +1319,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS) int32 count = PG_GETARG_INT32(3); NumericVar count_var; NumericVar result_var; - int32 result; + int32 result = 0; if (count <= 0) ereport(ERROR, @@ -1366,7 +1372,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS) } /* if result exceeds the range of a legal int4, we ereport here */ - result = numericvar_to_int32(&result_var); + (void) numericvar_to_int32(&result_var, &result, NULL); free_var(&count_var); free_var(&result_var); @@ -2141,7 +2147,7 @@ numeric_exp(PG_FUNCTION_ARGS) quick_init_var(&result); /* convert input to float8, ignoring overflow */ - val = numericvar_to_double_no_overflow(&arg); + (void) numericvar_to_double_no_overflow(&arg, &val, NULL); /* * log10(result) = num * log10(e), so this is approximately the decimal @@ -2447,7 +2453,7 @@ numeric_li_fraction(Numeric x, Numeric x0, Numeric x1, set_var_from_var(&const_zero, &v); } - result = numericvar_to_double_no_overflow(&v); + (void) numericvar_to_double_no_overflow(&v, &result, NULL); } return result; @@ -2478,6 +2484,7 @@ numeric_li_value(float8 f, Numeric y0, Numeric y1) NumericVar v1; NumericVar vf; char buf[DBL_DIG + 100]; + const char *endptr; init_var_from_num(y0, &v0); init_var_from_num(y1, &v1); @@ -2487,7 +2494,7 @@ numeric_li_value(float8 f, Numeric y0, Numeric y1) snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, f); /* Assume we need not worry about leading/trailing spaces */ - (void) init_var_from_str(buf, buf, &vf); + (void) init_var_from_str_safe(buf, buf, &vf, &endptr, NULL); mul_var(&vf, &v1, &v1, vf.dscale + v1.dscale); add_var(&v0, &v1, &v1); @@ -2596,42 +2603,43 @@ numeric_int4(PG_FUNCTION_ARGS) /* XXX would it be better to return NULL? */ if (NUMERIC_IS_NAN(num)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert NaN to integer"))); /* Convert to variable format, then convert to int4 */ init_var_from_num(num, &x); - result = numericvar_to_int32(&x); + if(!numericvar_to_int32(&x, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(result); } /* * Given a NumericVar, convert it to an int32. If the NumericVar * exceeds the range of an int32, raise the appropriate error via - * ereport(). The input NumericVar is *not* free'd. + * ereport() or if escontext is ErrorSaveContext saves error and + * returns false. The input NumericVar is *not* free'd. */ -static int32 -numericvar_to_int32(NumericVar *var) +static bool +numericvar_to_int32(NumericVar *var, int32 *result, Node* escontext) { - int32 result; int64 val = 0; if (!numericvar_to_int64(var, &val)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); /* Down-convert to int4 */ - result = (int32) val; + *result = (int32) val; /* Test for overflow by reverse-conversion. */ - if ((int64) result != val) - ereport(ERROR, + if ((int64) *result != val) + ereturn(escontext, false, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); - return result; + return true; } Datum @@ -2660,7 +2668,7 @@ numeric_int8(PG_FUNCTION_ARGS) /* XXX would it be better to return NULL? */ if (NUMERIC_IS_NAN(num)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert NaN to bigint"))); @@ -2668,7 +2676,7 @@ numeric_int8(PG_FUNCTION_ARGS) init_var_from_num(num, &x); if (!numericvar_to_int64(&x, &result)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range"))); @@ -2703,7 +2711,7 @@ numeric_int2(PG_FUNCTION_ARGS) /* XXX would it be better to return NULL? */ if (NUMERIC_IS_NAN(num)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert NaN to smallint"))); @@ -2711,7 +2719,7 @@ numeric_int2(PG_FUNCTION_ARGS) init_var_from_num(num, &x); if (!numericvar_to_int64(&x, &val)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); @@ -2720,7 +2728,7 @@ numeric_int2(PG_FUNCTION_ARGS) /* Test for overflow by reverse-conversion. */ if ((int64) result != val) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); @@ -2735,19 +2743,21 @@ float8_numeric(PG_FUNCTION_ARGS) Numeric res; NumericVar result; char buf[DBL_DIG + 100]; + const char *endptr; if (isnan(val)) PG_RETURN_NUMERIC(make_result(&const_nan)); if (isinf(val)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert infinity to numeric"))); snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val); /* Assume we need not worry about leading/trailing spaces */ - (void) init_var_from_str(buf, buf, &result); + if(!init_var_from_str_safe(buf, buf, &result, &endptr, fcinfo->context)) + PG_RETURN_NULL(); res = make_result(&result); @@ -2759,19 +2769,28 @@ Datum numeric_float8(PG_FUNCTION_ARGS) { Numeric num = PG_GETARG_NUMERIC(0); + Datum tmp_datum; char *tmp; Datum result; + Node *escontext = fcinfo->context; if (NUMERIC_IS_NAN(num)) PG_RETURN_FLOAT8(get_float8_nan()); - tmp = DatumGetCString(DirectFunctionCall1(numeric_out, - NumericGetDatum(num))); + tmp_datum = DirectFunctionCall1Safe(numeric_out, NumericGetDatum(num), escontext); - result = DirectFunctionCall1(float8in, CStringGetDatum(tmp)); + if (SOFT_ERROR_OCCURRED(escontext)) + PG_RETURN_NULL(); + + tmp = DatumGetCString(tmp_datum); + + result = DirectFunctionCall1Safe(float8in, CStringGetDatum(tmp), escontext); pfree(tmp); + if (SOFT_ERROR_OCCURRED(escontext)) + PG_RETURN_NULL(); + PG_RETURN_DATUM(result); } @@ -2798,19 +2817,21 @@ float4_numeric(PG_FUNCTION_ARGS) Numeric res; NumericVar result; char buf[FLT_DIG + 100]; + const char *endptr; if (isnan(val)) PG_RETURN_NUMERIC(make_result(&const_nan)); if (isinf(val)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert infinity to numeric"))); snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val); /* Assume we need not worry about leading/trailing spaces */ - (void) init_var_from_str(buf, buf, &result); + if(!init_var_from_str_safe(buf, buf, &result, &endptr, fcinfo->context)) + PG_RETURN_NULL(); res = make_result(&result); @@ -2822,19 +2843,28 @@ Datum numeric_float4(PG_FUNCTION_ARGS) { Numeric num = PG_GETARG_NUMERIC(0); + Datum tmp_datum; char *tmp; Datum result; + Node *escontext = fcinfo->context; if (NUMERIC_IS_NAN(num)) PG_RETURN_FLOAT4(get_float4_nan()); - tmp = DatumGetCString(DirectFunctionCall1(numeric_out, - NumericGetDatum(num))); + tmp_datum = DirectFunctionCall1Safe(numeric_out, NumericGetDatum(num), escontext); + + if (SOFT_ERROR_OCCURRED(escontext)) + PG_RETURN_NULL(); + + tmp = DatumGetCString(tmp_datum); - result = DirectFunctionCall1(float4in, CStringGetDatum(tmp)); + result = DirectFunctionCall1Safe(float4in, CStringGetDatum(tmp), escontext); pfree(tmp); + if (SOFT_ERROR_OCCURRED(escontext)) + PG_RETURN_NULL(); + PG_RETURN_DATUM(result); } @@ -5130,14 +5160,22 @@ zero_var(NumericVar *var) * Parse a string and put the number into a variable * * This function does not handle leading or trailing spaces, and it doesn't - * accept "NaN" either. It returns the end+1 position so that caller can - * check for trailing spaces/garbage if deemed necessary. + * accept "NaN" either. It returns the end+1 position into *endptr + * so that caller can check for trailing spaces/garbage if deemed necessary. * * cp is the place to actually start parsing; str is what to use in error * reports. (Typically cp would be the same except advanced over spaces.) */ static const char * init_var_from_str(const char *str, const char *cp, NumericVar *dest) +{ + const char *result; + (void) init_var_from_str_safe(str, cp, dest, &result, NULL); + return result; +} + +static bool +init_var_from_str_safe(const char *str, const char *cp, NumericVar *dest, const char **endptr, Node *escontext) { bool have_dp = FALSE; int i; @@ -5175,7 +5213,7 @@ init_var_from_str(const char *str, const char *cp, NumericVar *dest) } if (!isdigit((unsigned char) *cp)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type numeric: \"%s\"", str))); @@ -5201,7 +5239,7 @@ init_var_from_str(const char *str, const char *cp, NumericVar *dest) else if (*cp == '.') { if (have_dp) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type numeric: \"%s\"", str))); @@ -5225,7 +5263,7 @@ init_var_from_str(const char *str, const char *cp, NumericVar *dest) cp++; exponent = strtol(cp, &endptr, 10); if (endptr == cp) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type numeric: \"%s\"", str))); @@ -5240,7 +5278,7 @@ init_var_from_str(const char *str, const char *cp, NumericVar *dest) * for consistency use the same ereport errcode/text as make_result(). */ if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value overflows numeric format"))); dweight += (int) exponent; @@ -5290,7 +5328,8 @@ init_var_from_str(const char *str, const char *cp, NumericVar *dest) pfree(decdigits); /* Return end+1 position for caller */ - return cp; + *endptr = cp; + return true; } @@ -5733,9 +5772,12 @@ make_result(NumericVar *var) * * Do bounds checking and rounding according to the attributes * typmod field. + + * Returns true on success, false on failure (if escontext points to an + * ErrorSaveContext; otherwise errors are thrown). */ -static void -apply_typmod(NumericVar *var, int32 typmod) +static bool +apply_typmod(NumericVar *var, int32 typmod, Node *escontext) { int precision; int scale; @@ -5745,7 +5787,7 @@ apply_typmod(NumericVar *var, int32 typmod) /* Do nothing if we have a default typmod (-1) */ if (typmod < (int32) (VARHDRSZ)) - return; + return true; typmod -= VARHDRSZ; precision = (typmod >> 16) & 0xffff; @@ -5789,7 +5831,7 @@ apply_typmod(NumericVar *var, int32 typmod) #error unsupported NBASE #endif if (ddigits > maxdigits) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("numeric field overflow"), errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.", @@ -5803,6 +5845,7 @@ apply_typmod(NumericVar *var, int32 typmod) ddigits -= DEC_DIGITS; } } + return true; } /* @@ -6073,8 +6116,8 @@ numeric_to_double_no_overflow(Numeric num) } /* As above, but work from a NumericVar */ -static double -numericvar_to_double_no_overflow(NumericVar *var) +static bool +numericvar_to_double_no_overflow(NumericVar *var, double *result, Node *escontext) { char *tmp; double val; @@ -6087,15 +6130,18 @@ numericvar_to_double_no_overflow(NumericVar *var) if (*endptr != '\0') { /* shouldn't happen ... */ - ereport(ERROR, + errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type double precision: \"%s\"", tmp))); + pfree(tmp); + return false; } pfree(tmp); - return val; + *result = val; + return true; } @@ -7729,7 +7775,7 @@ power_var(NumericVar *base, NumericVar *exp, NumericVar *result) /* Set scale for exp() -- compare numeric_exp() */ /* convert input to float8, ignoring overflow */ - val = numericvar_to_double_no_overflow(&ln_num); + (void) numericvar_to_double_no_overflow(&ln_num, &val, NULL); /* * log10(result) = num * log10(e), so this is approximately the weight: diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index 2badb558f0..597daffee4 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -31,14 +31,14 @@ *****************************************************************************/ static Oid -oidin_subr(const char *s, char **endloc) +oidin_subr_safe(const char *s, char **endloc, Oid *res, Node *escontext) { unsigned long cvt; char *endptr; Oid result; if (*s == '\0') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type oid: \"%s\"", s))); @@ -52,19 +52,19 @@ oidin_subr(const char *s, char **endloc) * handled by the second "if" consistent across platforms. */ if (errno && errno != ERANGE && errno != EINVAL) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type oid: \"%s\"", s))); if (endptr == s && *s != '\0') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type oid: \"%s\"", s))); if (errno == ERANGE) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type oid", s))); @@ -79,7 +79,7 @@ oidin_subr(const char *s, char **endloc) while (*endptr && isspace((unsigned char) *endptr)) endptr++; if (*endptr) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type oid: \"%s\"", s))); @@ -102,11 +102,20 @@ oidin_subr(const char *s, char **endloc) #if OID_MAX != ULONG_MAX if (cvt != (unsigned long) result && cvt != (unsigned long) ((int) result)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type oid", s))); #endif + *res = result; + return true; +} + +static Oid +oidin_subr(const char *s, char **endloc) +{ + Oid result; + (void) oidin_subr_safe(s, endloc, &result, NULL); return result; } @@ -116,7 +125,8 @@ oidin(PG_FUNCTION_ARGS) char *s = PG_GETARG_CSTRING(0); Oid result; - result = oidin_subr(s, NULL); + if (!oidin_subr_safe(s, NULL, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_OID(result); } @@ -202,12 +212,13 @@ oidvectorin(PG_FUNCTION_ARGS) oidString++; if (*oidString == '\0') break; - result->values[n] = oidin_subr(oidString, &oidString); + if (!oidin_subr_safe(oidString, &oidString, &result->values[n], fcinfo->context)) + PG_RETURN_NULL(); } while (*oidString && isspace((unsigned char) *oidString)) oidString++; if (*oidString) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("oidvector has too many elements"))); @@ -282,13 +293,13 @@ oidvectorrecv(PG_FUNCTION_ARGS) ARR_HASNULL(result) || ARR_ELEMTYPE(result) != OIDOID || ARR_LBOUND(result)[0] != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid oidvector data"))); /* check length for consistency with oidvectorin() */ if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("oidvector has too many elements"))); @@ -307,13 +318,14 @@ oidvectorsend(PG_FUNCTION_ARGS) /* * oidparse - get OID from IConst/FConst node */ -Oid -oidparse(Node *node) +bool +oidparse_safe(Node *node, Oid *result, Node *escontext) { switch (nodeTag(node)) { case T_Integer: - return intVal(node); + *result = intVal(node); + return true; case T_Float: /* @@ -321,11 +333,22 @@ oidparse(Node *node) * constants by the lexer. Accept these if they are valid OID * strings. */ - return oidin_subr(strVal(node), NULL); + if (!oidin_subr_safe(strVal(node), NULL, result, escontext)) + return false; + return true; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); } - return InvalidOid; /* keep compiler quiet */ + *result = InvalidOid; + return true; /* keep compiler quiet */ +} + +Oid +oidparse(Node *node) +{ + Oid result = 0; + (void) oidparse_safe(node, &result, NULL); + return result; } diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index ad9ba7ccb6..12e8b860dd 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -47,6 +47,8 @@ static char *format_operator_internal(Oid operator_oid, bool force_qualify); static char *format_procedure_internal(Oid procedure_oid, bool force_qualify); static void parseNameAndArgTypes(const char *string, bool allowNone, List **names, int *nargs, Oid *argtypes); +static bool parseNameAndArgTypesSafe(const char *string, bool allowNone, + List **names, int *nargs, Oid *argtypes, Node *escontext); /***************************************************************************** @@ -119,12 +121,12 @@ regprocin(PG_FUNCTION_ARGS) heap_close(hdesc, AccessShareLock); if (matches == 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); else if (matches > 1) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one function named \"%s\"", pro_name_or_oid))); @@ -136,15 +138,16 @@ regprocin(PG_FUNCTION_ARGS) * Normal case: parse the name into components and see if it matches any * pg_proc entries in the current search path. */ - names = stringToQualifiedNameList(pro_name_or_oid); + if (!stringToQualifiedNameListSafe(pro_name_or_oid, &names, fcinfo->context)) + PG_RETURN_NULL(); clist = FuncnameGetCandidates(names, -1, NIL, false, false, false); if (clist == NULL) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); else if (clist->next != NULL) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one function named \"%s\"", pro_name_or_oid))); @@ -170,7 +173,8 @@ to_regproc(PG_FUNCTION_ARGS) * Parse the name into components and see if it matches any pg_proc * entries in the current search path. */ - names = stringToQualifiedNameList(pro_name); + if (!stringToQualifiedNameListSafe(pro_name, &names, fcinfo->context)) + PG_RETURN_NULL(); clist = FuncnameGetCandidates(names, -1, NIL, false, false, true); if (clist == NULL || clist->next != NULL) @@ -304,7 +308,8 @@ regprocedurein(PG_FUNCTION_ARGS) * datatype cannot be used for any system column that needs to receive * data during bootstrap. */ - parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes); + if (!parseNameAndArgTypesSafe(pro_name_or_oid, false, &names, &nargs, argtypes, fcinfo->context)) + PG_RETURN_NULL(); clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false); @@ -315,7 +320,7 @@ regprocedurein(PG_FUNCTION_ARGS) } if (clist == NULL) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); @@ -343,7 +348,8 @@ to_regprocedure(PG_FUNCTION_ARGS) * namespace search list, and scan to see which one exactly matches the * given argument types. (There will not be more than one match.) */ - parseNameAndArgTypes(pro_name, false, &names, &nargs, argtypes); + if (!parseNameAndArgTypesSafe(pro_name, false, &names, &nargs, argtypes, fcinfo->context)) + PG_RETURN_NULL(); clist = FuncnameGetCandidates(names, nargs, NIL, false, false, true); @@ -540,11 +546,11 @@ regoperin(PG_FUNCTION_ARGS) break; } if (matches == 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", opr_name_or_oid))); else if (matches > 1) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one operator named %s", opr_name_or_oid))); @@ -556,15 +562,16 @@ regoperin(PG_FUNCTION_ARGS) * Normal case: parse the name into components and see if it matches any * pg_operator entries in the current search path. */ - names = stringToQualifiedNameList(opr_name_or_oid); + if (!stringToQualifiedNameListSafe(opr_name_or_oid, &names, fcinfo->context)) + PG_RETURN_NULL(); clist = OpernameGetCandidates(names, '\0', false); if (clist == NULL) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", opr_name_or_oid))); else if (clist->next != NULL) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one operator named %s", opr_name_or_oid))); @@ -590,7 +597,8 @@ to_regoper(PG_FUNCTION_ARGS) * Parse the name into components and see if it matches any pg_operator * entries in the current search path. */ - names = stringToQualifiedNameList(opr_name); + if (!stringToQualifiedNameListSafe(opr_name, &names, fcinfo->context)) + PG_RETURN_NULL(); clist = OpernameGetCandidates(names, '\0', true); if (clist == NULL || clist->next != NULL) @@ -729,14 +737,15 @@ regoperatorin(PG_FUNCTION_ARGS) * datatype cannot be used for any system column that needs to receive * data during bootstrap. */ - parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes); + if (!parseNameAndArgTypesSafe(opr_name_or_oid, true, &names, &nargs, argtypes, fcinfo->context)) + PG_RETURN_NULL(); if (nargs == 1) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("missing argument"), errhint("Use NONE to denote the missing argument of a unary operator."))); if (nargs != 2) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("too many arguments"), errhint("Provide two argument types for operator."))); @@ -744,7 +753,7 @@ regoperatorin(PG_FUNCTION_ARGS) result = OpernameGetOprid(names, argtypes[0], argtypes[1]); if (!OidIsValid(result)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", opr_name_or_oid))); @@ -770,14 +779,15 @@ to_regoperator(PG_FUNCTION_ARGS) * namespace search list, and scan to see which one exactly matches the * given argument types. (There will not be more than one match.) */ - parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes); + if (!parseNameAndArgTypesSafe(opr_name_or_oid, true, &names, &nargs, argtypes, fcinfo->context)) + PG_RETURN_NULL(); if (nargs == 1) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("missing argument"), errhint("Use NONE to denote the missing argument of a unary operator."))); if (nargs != 2) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("too many arguments"), errhint("Provide two argument types for operator."))); @@ -967,7 +977,7 @@ regclassin(PG_FUNCTION_ARGS) if (HeapTupleIsValid(tuple = systable_getnext(sysscan))) result = HeapTupleGetOid(tuple); else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", class_name_or_oid))); @@ -983,7 +993,8 @@ regclassin(PG_FUNCTION_ARGS) * Normal case: parse the name into components and see if it matches any * pg_class entries in the current search path. */ - names = stringToQualifiedNameList(class_name_or_oid); + if (!stringToQualifiedNameListSafe(class_name_or_oid, &names, fcinfo->context)) + PG_RETURN_NULL(); /* We might not even have permissions on this relation; don't lock it. */ result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false); @@ -1007,7 +1018,8 @@ to_regclass(PG_FUNCTION_ARGS) * Parse the name into components and see if it matches any pg_class * entries in the current search path. */ - names = stringToQualifiedNameList(class_name); + if (!stringToQualifiedNameListSafe(class_name, &names, fcinfo->context)) + PG_RETURN_NULL(); /* We might not even have permissions on this relation; don't lock it. */ result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); @@ -1158,7 +1170,7 @@ regtypein(PG_FUNCTION_ARGS) if (HeapTupleIsValid(tuple = systable_getnext(sysscan))) result = HeapTupleGetOid(tuple); else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", typ_name_or_oid))); @@ -1307,7 +1319,8 @@ regconfigin(PG_FUNCTION_ARGS) * Normal case: parse the name into components and see if it matches any * pg_ts_config entries in the current search path. */ - names = stringToQualifiedNameList(cfg_name_or_oid); + if (!stringToQualifiedNameListSafe(cfg_name_or_oid, &names, fcinfo->context)) + PG_RETURN_NULL(); result = get_ts_config_oid(names, false); @@ -1417,7 +1430,8 @@ regdictionaryin(PG_FUNCTION_ARGS) * Normal case: parse the name into components and see if it matches any * pg_ts_dict entries in the current search path. */ - names = stringToQualifiedNameList(dict_name_or_oid); + if (!stringToQualifiedNameListSafe(dict_name_or_oid, &names, fcinfo->context)) + PG_RETURN_NULL(); result = get_ts_dict_oid(names, false); @@ -1623,6 +1637,14 @@ text_regclass(PG_FUNCTION_ARGS) */ List * stringToQualifiedNameList(const char *string) +{ + List *result; + (void) stringToQualifiedNameListSafe(string, &result, NULL); + return result; +} + +bool +stringToQualifiedNameListSafe(const char *string, List **res, Node *escontext) { char *rawname; List *result = NIL; @@ -1633,12 +1655,12 @@ stringToQualifiedNameList(const char *string) rawname = pstrdup(string); if (!SplitIdentifierString(rawname, '.', &namelist)) - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); if (namelist == NIL) - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); @@ -1652,7 +1674,7 @@ stringToQualifiedNameList(const char *string) pfree(rawname); list_free(namelist); - return result; + *res = result; } /***************************************************************************** @@ -1669,9 +1691,9 @@ stringToQualifiedNameList(const char *string) * If allowNone is TRUE, accept "NONE" and return it as InvalidOid (this is * for unary operators). */ -static void -parseNameAndArgTypes(const char *string, bool allowNone, List **names, - int *nargs, Oid *argtypes) +static bool +parseNameAndArgTypesSafe(const char *string, bool allowNone, List **names, + int *nargs, Oid *argtypes, Node *escontext) { char *rawname; char *ptr; @@ -1696,7 +1718,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, break; } if (*ptr == '\0') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("expected a left parenthesis"))); @@ -1712,7 +1734,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, break; } if (*ptr2 != ')') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("expected a right parenthesis"))); @@ -1731,7 +1753,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, { /* End of string. Okay unless we had a comma before. */ if (had_comma) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("expected a type name"))); break; @@ -1763,7 +1785,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, } } if (in_quote || paren_count != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("improper type name"))); @@ -1798,7 +1820,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, parseTypeString(typename, &typeid, &typmod, false); } if (*nargs >= FUNC_MAX_ARGS) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("too many arguments"))); @@ -1807,4 +1829,13 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, } pfree(rawname); + + return true; +} + +static void +parseNameAndArgTypes(const char *string, bool allowNone, List **names, + int *nargs, Oid *argtypes) +{ + (void) parseNameAndArgTypesSafe(string, allowNone, nargs, names, argtypes, NULL); } diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 4f374aac22..8c3a7670fb 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -70,25 +70,47 @@ typedef struct static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec); static Timestamp dt2local(Timestamp dt, int timezone); -static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod); -static void AdjustIntervalForTypmod(Interval *interval, int32 typmod); +// static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod); +static bool AdjustTimestampForTypmodSafe(Timestamp *time, int32 typmod, Node *escontext); +// static void AdjustIntervalForTypmod(Interval *interval, int32 typmod); +static bool AdjustIntervalForTypmodSafe(Interval *interval, int32 typmod, Node *escontext); static TimestampTz timestamp2timestamptz(Timestamp timestamp); -static inline Timestamp timestamp_offset_internal(Timestamp timestamp, - Interval *span); -static inline Timestamp timestamp_offset_multiple(Timestamp base, Interval *unit, - int64 mul); -static inline TimestampTz timestamptz_offset_internal(TimestampTz timestamp, - Interval *span); +static bool timestamp2timestamptz_safe(Timestamp timestamp, Timestamp *result, Node *escontext); +// static inline Timestamp timestamp_offset_internal(Timestamp timestamp, +// Interval *span); +static inline bool timestamp_offset_internal_safe(Timestamp timestamp, + Interval *span, Timestamp *result, Node* escontext); +// static inline Timestamp timestamp_offset_multiple(Timestamp base, Interval *unit, +// int64 mul); +static inline bool timestamp_offset_multiple_safe(Timestamp base, Interval *unit, + int64 mul, Timestamp *result, Node *escontext); +// static inline TimestampTz timestamptz_offset_internal(TimestampTz timestamp, +// Interval *span); +static inline bool timestamptz_offset_internal_safe(TimestampTz timestamp, + Interval *span, TimestampTz *result, Node *escontext); static inline TimestampTz timestamptz_offset_multiple(TimestampTz base, Interval *unit, int64 mul); +static inline bool timestamptz_offset_multiple_safe(TimestampTz base, + Interval *unit, int64 mul, TimestampTz *result, Node *escontext); /* Handy for comparisons. */ static const Interval IntervalZero = {0, 0, 0}; /* common code for timestamptypmodin and timestamptztypmodin */ +static int32 +anytimestamp_typmodin_safe(bool istz, ArrayType *ta, int32 *result, Node *escontext); + static int32 anytimestamp_typmodin(bool istz, ArrayType *ta) +{ + int32 result; + (void) anytimestamp_typmodin_safe(istz, ta, &result, NULL); + return result; +} + +static int32 +anytimestamp_typmodin_safe(bool istz, ArrayType *ta, int32 *result, Node *escontext) { int32 typmod; int32 *tl; @@ -101,12 +123,12 @@ anytimestamp_typmodin(bool istz, ArrayType *ta) * shouldn't allow wrong number of modifiers for TIMESTAMP */ if (n != 1) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid type modifier"))); if (*tl < 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("TIMESTAMP(%d)%s precision must not be negative", *tl, (istz ? " WITH TIME ZONE" : "")))); @@ -122,7 +144,8 @@ anytimestamp_typmodin(bool istz, ArrayType *ta) else typmod = *tl; - return typmod; + *result = typmod; + return true; } /* common code for timestamptypmodout and timestamptztypmodout */ @@ -169,15 +192,17 @@ timestamp_in(PG_FUNCTION_ARGS) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) - dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); + if (!DecodeDateTimeSafe(field, ftype, nf, &dtype, tm, &fsec, &tz, &dterr, fcinfo->context)) + PG_RETURN_NULL(); if (dterr != 0) - DateTimeParseError(dterr, str, "timestamp"); + if (!DateTimeParseErrorSafe(dterr, str, "timestamp", fcinfo->context)) + PG_RETURN_NULL(); switch (dtype) { case DTK_DATE: if (tm2timestamp(tm, fsec, NULL, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: \"%s\"", str))); break; @@ -195,7 +220,7 @@ timestamp_in(PG_FUNCTION_ARGS) break; case DTK_INVALID: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"%s\" is no longer supported", str))); @@ -208,7 +233,8 @@ timestamp_in(PG_FUNCTION_ARGS) TIMESTAMP_NOEND(result); } - AdjustTimestampForTypmod(&result, typmod); + if (!AdjustTimestampForTypmodSafe(&result, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -231,7 +257,7 @@ timestamp_out(PG_FUNCTION_ARGS) else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -265,7 +291,7 @@ timestamp_recv(PG_FUNCTION_ARGS) timestamp = (Timestamp) pq_getmsgfloat8(buf); if (isnan(timestamp)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp cannot be NaN"))); #endif @@ -274,11 +300,12 @@ timestamp_recv(PG_FUNCTION_ARGS) if (TIMESTAMP_NOT_FINITE(timestamp)) /* ok */ ; else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - AdjustTimestampForTypmod(×tamp, typmod); + if (!AdjustTimestampForTypmodSafe(×tamp, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(timestamp); } @@ -306,7 +333,11 @@ timestamptypmodin(PG_FUNCTION_ARGS) { ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); - PG_RETURN_INT32(anytimestamp_typmodin(false, ta)); + int32 typmod = 0; + if(!anytimestamp_typmodin_safe(false, ta, &typmod, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_INT32(typmod); } Datum @@ -324,9 +355,22 @@ timestamptypmodout(PG_FUNCTION_ARGS) * interval_bound(timestamp, interval, int, timestamp) * returns timestamp */ +static bool +timestamp_interval_bound_common_safe(Timestamp val, Interval *width, + int32 shift, Timestamp reg, Timestamp *result, Node *escontext); + static Timestamp timestamp_interval_bound_common(Timestamp val, Interval *width, int32 shift, Timestamp reg) +{ + Timestamp result; + (void) timestamp_interval_bound_common_safe(val, width, shift, reg, &result, NULL); + return result; +} + +static bool +timestamp_interval_bound_common_safe(Timestamp val, Interval *width, + int32 shift, Timestamp reg, Timestamp *result, Node *escontext) { int64 index = 0; float8 quo = 0.0; @@ -337,16 +381,18 @@ timestamp_interval_bound_common(Timestamp val, Interval *width, /* Insist on positive, interval width. */ if (interval_cmp_internal(width, &IntervalZero) <= 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_INTERVAL_WIDTH), errmsg("width of time interval not positive"))); /* Just return non-finite timestamp. */ - if (TIMESTAMP_NOT_FINITE(val)) - return val; + if (TIMESTAMP_NOT_FINITE(val)) { + *result = val; + return true; + } if (TIMESTAMP_NOT_FINITE(reg)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("bound for registration is not finite"))); @@ -366,8 +412,10 @@ timestamp_interval_bound_common(Timestamp val, Interval *width, if (safety <= 0) elog(ERROR, "interval_bound failed to converge"); - low = timestamp_offset_multiple(reg, width, index); - high = timestamp_offset_multiple(low, width, 1); + if (!timestamp_offset_multiple_safe(reg, width, index, &low, escontext)) + return false; + if (!timestamp_offset_multiple_safe(low, width, 1, &high, escontext)) + return false; Assert(high > low); @@ -405,9 +453,11 @@ timestamp_interval_bound_common(Timestamp val, Interval *width, /* If necessary, shift the interval. */ if (shift) - low = timestamp_offset_multiple(reg, width, index + shift); + if (!timestamp_offset_multiple_safe(reg, width, index + shift, &low, escontext)) + return false; - return low; + *result = low; + return true; } /* @@ -420,10 +470,13 @@ timestamp_interval_bound(PG_FUNCTION_ARGS) Interval *width = PG_GETARG_INTERVAL_P(1); int32 shift = 0; Timestamp reg = SetEpochTimestamp(); + Timestamp result; - PG_RETURN_TIMESTAMP( - timestamp_interval_bound_common( - val, width, shift, reg)); + if(!timestamp_interval_bound_common_safe( + val, width, shift, reg, &result, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMP(result); } /* @@ -436,6 +489,7 @@ timestamp_interval_bound_shift(PG_FUNCTION_ARGS) Interval *width; int32 shift = 0; Timestamp reg; + Timestamp result; /* NULL, if either of the first two arguments is NULL. */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) @@ -450,9 +504,9 @@ timestamp_interval_bound_shift(PG_FUNCTION_ARGS) reg = SetEpochTimestamp(); - PG_RETURN_TIMESTAMP( - timestamp_interval_bound_common( - val, width, shift, reg)); + if(!timestamp_interval_bound_common_safe( + val, width, shift, reg, &result, fcinfo->context)) + PG_RETURN_NULL(); } /* @@ -465,6 +519,7 @@ timestamp_interval_bound_shift_reg(PG_FUNCTION_ARGS) Interval *width; int32 shift = 0; Timestamp reg; + Timestamp result; /* NULL, if either of the first two arguments is NULL. */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) @@ -483,9 +538,9 @@ timestamp_interval_bound_shift_reg(PG_FUNCTION_ARGS) else reg = SetEpochTimestamp(); - PG_RETURN_TIMESTAMP( - timestamp_interval_bound_common( - val, width, shift, reg)); + if(!timestamp_interval_bound_common_safe( + val, width, shift, reg, &result, fcinfo->context)) + PG_RETURN_NULL(); } /* @@ -495,29 +550,44 @@ timestamp_interval_bound_shift_reg(PG_FUNCTION_ARGS) * interval_bound(timestamptz, interval, int, timestamptz) * returns timestamptz */ +static bool +timestamptz_interval_bound_common_safe(TimestampTz val, Interval *width, + int32 shift, TimestampTz reg, TimestampTz *result, Node *escontext); + static TimestampTz timestamptz_interval_bound_common(TimestampTz val, Interval *width, int32 shift, TimestampTz reg) +{ + TimestampTz result; + (void) timestamptz_interval_bound_common_safe(val, width, shift, reg, &result, NULL); + return result; +} + +static bool +timestamptz_interval_bound_common_safe(TimestampTz val, Interval *width, + int32 shift, TimestampTz reg, TimestampTz *result, Node *escontext) { int64 index = 0; float8 quo = 0.0; Interval span; TimestampTz low; - TimestampTz high; + TimestampTz high = 0; int safety; /* Insist on positive, interval width. */ if (interval_cmp_internal(width, &IntervalZero) <= 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_INTERVAL_WIDTH), errmsg("width of time interval not positive"))); /* Just return non-finite timestamp. */ - if (TIMESTAMP_NOT_FINITE(val)) - return val; + if (TIMESTAMP_NOT_FINITE(val)){ + *result = val; + return true; + } if (TIMESTAMP_NOT_FINITE(reg)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("bound for registration is not finite"))); @@ -537,8 +607,10 @@ timestamptz_interval_bound_common(TimestampTz val, Interval *width, if (safety <= 0) elog(ERROR, "interval_bound failed to converge"); - low = timestamptz_offset_multiple(reg, width, index); - high = timestamptz_offset_multiple(low, width, 1); + if(!timestamptz_offset_multiple_safe(reg, width, index, &low, escontext)) + return false; + if(!timestamptz_offset_multiple_safe(low, width, 1, &high, escontext)) + return false; Assert(high > low); @@ -576,9 +648,11 @@ timestamptz_interval_bound_common(TimestampTz val, Interval *width, /* If necessary, shift the interval. */ if (shift) - low = timestamptz_offset_multiple(reg, width, index + shift); + if (!timestamptz_offset_multiple_safe(reg, width, index + shift, &low, escontext)) + return false; - return low; + *result = low; + return true; } /* @@ -591,10 +665,13 @@ timestamptz_interval_bound(PG_FUNCTION_ARGS) Interval *width = PG_GETARG_INTERVAL_P(1); int32 shift = 0; TimestampTz reg = SetEpochTimestamp(); + TimestampTz result; - PG_RETURN_TIMESTAMPTZ( - timestamptz_interval_bound_common( - val, width, shift, reg)); + if (!timestamptz_interval_bound_common_safe( + val, width, shift, reg, &result, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result); } @@ -608,6 +685,7 @@ timestamptz_interval_bound_shift(PG_FUNCTION_ARGS) Interval *width; int32 shift = 0; TimestampTz reg; + TimestampTz result; /* NULL, if either of the first two arguments is NULL. */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) @@ -622,9 +700,11 @@ timestamptz_interval_bound_shift(PG_FUNCTION_ARGS) reg = SetEpochTimestamp(); - PG_RETURN_TIMESTAMPTZ( - timestamptz_interval_bound_common( - val, width, shift, reg)); + if (!timestamptz_interval_bound_common_safe( + val, width, shift, reg, &result, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result); } /* @@ -637,6 +717,7 @@ timestamptz_interval_bound_shift_reg(PG_FUNCTION_ARGS) Interval *width; int32 shift = 0; TimestampTz reg; + TimestampTz result; /* NULL, if either of the first two arguments is NULL. */ if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) @@ -655,9 +736,11 @@ timestamptz_interval_bound_shift_reg(PG_FUNCTION_ARGS) else reg = SetEpochTimestamp(); - PG_RETURN_TIMESTAMPTZ( - timestamptz_interval_bound_common( - val, width, shift, reg)); + if (!timestamptz_interval_bound_common_safe( + val, width, shift, reg, &result, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result); } /* timestamp_transform() @@ -684,13 +767,20 @@ timestamp_scale(PG_FUNCTION_ARGS) result = timestamp; - AdjustTimestampForTypmod(&result, typmod); + if (!AdjustTimestampForTypmodSafe(&result, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod) +{ + (void) AdjustTimestampForTypmodSafe(time, typmod, NULL); +} + +static bool +AdjustTimestampForTypmodSafe(Timestamp *time, int32 typmod, Node *escontext) { #ifdef HAVE_INT64_TIMESTAMP static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { @@ -728,7 +818,7 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION)) { if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp(%d) precision must be between %d and %d", typmod, 0, MAX_TIMESTAMP_PRECISION))); @@ -755,6 +845,7 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) *time = rint((double) *time * TimestampScales[typmod]) / TimestampScales[typmod]; #endif } + return true; } @@ -785,15 +876,17 @@ timestamptz_in(PG_FUNCTION_ARGS) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) - dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); + if (!DecodeDateTimeSafe(field, ftype, nf, &dtype, tm, &fsec, &tz, &dterr, fcinfo->context)) + PG_RETURN_NULL(); if (dterr != 0) - DateTimeParseError(dterr, str, "timestamp with time zone"); + if (!DateTimeParseErrorSafe(dterr, str, "timestamp with time zone", fcinfo->context)) + PG_RETURN_NULL(); switch (dtype) { case DTK_DATE: if (tm2timestamp(tm, fsec, &tz, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: \"%s\"", str))); break; @@ -811,7 +904,7 @@ timestamptz_in(PG_FUNCTION_ARGS) break; case DTK_INVALID: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"%s\" is no longer supported", str))); @@ -824,7 +917,8 @@ timestamptz_in(PG_FUNCTION_ARGS) TIMESTAMP_NOEND(result); } - AdjustTimestampForTypmod(&result, typmod); + if (!AdjustTimestampForTypmodSafe(&result, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMPTZ(result); } @@ -836,8 +930,19 @@ timestamptz_in(PG_FUNCTION_ARGS) * Note: some code paths update tm->tm_isdst, and some don't; current callers * don't care, so we don't bother being consistent. */ +static bool +parse_sane_timezone_safe(struct pg_tm * tm, text *zone, int *result, Node *escontext); + static int parse_sane_timezone(struct pg_tm * tm, text *zone) +{ + int result; + (void) parse_sane_timezone_safe(tm, zone, &result, NULL); + return result; +} + +static bool +parse_sane_timezone_safe(struct pg_tm * tm, text *zone, int *result, Node *escontext) { char tzname[TZ_STRLEN_MAX + 1]; int rt; @@ -861,7 +966,7 @@ parse_sane_timezone(struct pg_tm * tm, text *zone) * position of our input string. */ if (isdigit((unsigned char) *tzname)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid input syntax for numeric time zone: \"%s\"", tzname), @@ -876,11 +981,11 @@ parse_sane_timezone(struct pg_tm * tm, text *zone) pg_tz *tzp; if (rt == DTERR_TZDISP_OVERFLOW) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("numeric time zone \"%s\" out of range", tzname))); else if (rt != DTERR_BAD_FORMAT) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", tzname))); @@ -888,7 +993,8 @@ parse_sane_timezone(struct pg_tm * tm, text *zone) lowzone = downcase_truncate_identifier(tzname, strlen(tzname), false); - type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp); + if (!DecodeTimezoneAbbrevSafe(0, lowzone, &val, &tzp, &type, escontext)) + return false; if (type == TZ || type == DTZ) { @@ -907,13 +1013,14 @@ parse_sane_timezone(struct pg_tm * tm, text *zone) if (tzp) tz = DetermineTimeZoneOffset(tm, tzp); else - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", tzname))); } } - return tz; + *result = tz; + return true; } /* @@ -921,8 +1028,21 @@ parse_sane_timezone(struct pg_tm * tm, text *zone) * workhorse for make_timestamp and make_timestamptz */ static Timestamp +make_timestamp_internal_safe(int year, int month, int day, + int hour, int min, double sec, Timestamp *res, Node *escontext); + +static Timestamp make_timestamp_internal(int year, int month, int day, int hour, int min, double sec) +{ + Timestamp result; + (void) make_timestamp_internal_safe(year, month, day, hour, min, sec, &result, NULL); + return result; +} + +static Timestamp +make_timestamp_internal_safe(int year, int month, int day, + int hour, int min, double sec, Timestamp *res, Node *escontext) { struct pg_tm tm; TimeOffset date; @@ -941,13 +1061,13 @@ make_timestamp_internal(int year, int month, int day, dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm); if (dterr != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), errmsg("date field value out of range: %d-%02d-%02d", year, month, day))); if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range: %d-%02d-%02d", year, month, day))); @@ -966,7 +1086,7 @@ make_timestamp_internal(int year, int month, int day, hour > HOURS_PER_DAY || /* test for > 24:00:00 */ (hour == HOURS_PER_DAY && (min > 0 || sec > 0))) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), errmsg("time field value out of range: %d:%02d:%02g", hour, min, sec))); @@ -979,7 +1099,7 @@ make_timestamp_internal(int year, int month, int day, result = date * USECS_PER_DAY + time; /* check for major overflow */ if ((result - time) / USECS_PER_DAY != date) - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g", year, month, day, @@ -989,7 +1109,7 @@ make_timestamp_internal(int year, int month, int day, /* caution: we want to allow 1999-12-31 24:00:00 */ if ((result < 0 && date > 0) || (result > 0 && date < -1)) - ereport(ERROR, + ereturn(escontext, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g", year, month, day, @@ -999,7 +1119,8 @@ make_timestamp_internal(int year, int month, int day, result = date * SECS_PER_DAY + time; #endif - return result; + *res = result; + return true; } /* @@ -1016,8 +1137,9 @@ make_timestamp(PG_FUNCTION_ARGS) float8 sec = PG_GETARG_FLOAT8(5); Timestamp result; - result = make_timestamp_internal(year, month, mday, - hour, min, sec); + if(!make_timestamp_internal_safe(year, month, mday, + hour, min, sec, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -1035,11 +1157,16 @@ make_timestamptz(PG_FUNCTION_ARGS) int32 min = PG_GETARG_INT32(4); float8 sec = PG_GETARG_FLOAT8(5); Timestamp result; + TimestampTz result_tz; - result = make_timestamp_internal(year, month, mday, - hour, min, sec); + if (!make_timestamp_internal_safe(year, month, mday, + hour, min, sec, &result, fcinfo->context)) + PG_RETURN_NULL(); - PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result)); + if (!timestamp2timestamptz_safe(result, &result_tz, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result_tz); } /* @@ -1061,15 +1188,17 @@ make_timestamptz_at_timezone(PG_FUNCTION_ARGS) int tz; fsec_t fsec; - timestamp = make_timestamp_internal(year, month, mday, - hour, min, sec); + if(!make_timestamp_internal_safe(year, month, mday, + hour, min, sec, ×tamp, fcinfo->context)) + PG_RETURN_NULL(); if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - tz = parse_sane_timezone(&tt, zone); + if (!parse_sane_timezone_safe(&tt, zone, &tz, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMPTZ((TimestampTz) dt2local(timestamp, -tz)); } @@ -1094,7 +1223,7 @@ timestamptz_out(PG_FUNCTION_ARGS) else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0) EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf); else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -1133,11 +1262,12 @@ timestamptz_recv(PG_FUNCTION_ARGS) if (TIMESTAMP_NOT_FINITE(timestamp)) /* ok */ ; else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - AdjustTimestampForTypmod(×tamp, typmod); + if (!AdjustTimestampForTypmodSafe(×tamp, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMPTZ(timestamp); } @@ -1165,7 +1295,11 @@ timestamptztypmodin(PG_FUNCTION_ARGS) { ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); - PG_RETURN_INT32(anytimestamp_typmodin(true, ta)); + int32 typmod = 0; + if(!anytimestamp_typmodin_safe(true, ta, &typmod, fcinfo->context)) + PG_RETURN_NULL(); + + PG_RETURN_INT32(typmod); } Datum @@ -1190,7 +1324,8 @@ timestamptz_scale(PG_FUNCTION_ARGS) result = timestamp; - AdjustTimestampForTypmod(&result, typmod); + if (!AdjustTimestampForTypmodSafe(&result, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMPTZ(result); } @@ -1251,7 +1386,8 @@ interval_in(PG_FUNCTION_ARGS) { if (dterr == DTERR_FIELD_OVERFLOW) dterr = DTERR_INTERVAL_OVERFLOW; - DateTimeParseError(dterr, str, "interval"); + if (!DateTimeParseErrorSafe(dterr, str, "interval", fcinfo->context)) + PG_RETURN_NULL(); } result = (Interval *) palloc(sizeof(Interval)); @@ -1260,13 +1396,13 @@ interval_in(PG_FUNCTION_ARGS) { case DTK_DELTA: if (tm2interval(tm, fsec, result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); break; case DTK_INVALID: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("date/time value \"%s\" is no longer supported", str))); break; @@ -1276,7 +1412,8 @@ interval_in(PG_FUNCTION_ARGS) dtype, str); } - AdjustIntervalForTypmod(result, typmod); + if (!AdjustIntervalForTypmodSafe(result, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INTERVAL_P(result); } @@ -1291,10 +1428,10 @@ interval_out(PG_FUNCTION_ARGS) char *result; struct pg_tm tt, *tm = &tt; - fsec_t fsec; + fsec_t fsec = 0; char buf[MAXDATELEN + 1]; - if (interval2tm(*span, tm, &fsec) != 0) + if (interval2tm_safe(*span, tm, &fsec, fcinfo->context) != 0) elog(ERROR, "could not convert interval to tm"); EncodeInterval(tm, fsec, IntervalStyle, buf); @@ -1327,7 +1464,8 @@ interval_recv(PG_FUNCTION_ARGS) interval->day = pq_getmsgint(buf, sizeof(interval->day)); interval->month = pq_getmsgint(buf, sizeof(interval->month)); - AdjustIntervalForTypmod(interval, typmod); + if (!AdjustIntervalForTypmodSafe(interval, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INTERVAL_P(interval); } @@ -1401,7 +1539,7 @@ intervaltypmodin(PG_FUNCTION_ARGS) /* all OK */ break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid INTERVAL type modifier"))); } @@ -1417,7 +1555,7 @@ intervaltypmodin(PG_FUNCTION_ARGS) else if (n == 2) { if (tl[1] < 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("INTERVAL(%d) precision must not be negative", tl[1]))); @@ -1434,7 +1572,7 @@ intervaltypmodin(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid INTERVAL type modifier"))); typmod = 0; /* keep compiler quiet */ @@ -1646,7 +1784,8 @@ interval_scale(PG_FUNCTION_ARGS) result = palloc(sizeof(Interval)); *result = *interval; - AdjustIntervalForTypmod(result, typmod); + if (!AdjustIntervalForTypmodSafe(result, typmod, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INTERVAL_P(result); } @@ -1657,6 +1796,12 @@ interval_scale(PG_FUNCTION_ARGS) */ static void AdjustIntervalForTypmod(Interval *interval, int32 typmod) +{ + (void) AdjustIntervalForTypmodSafe(interval, typmod, NULL); +} + +static bool +AdjustIntervalForTypmodSafe(Interval *interval, int32 typmod, Node* escontext) { #ifdef HAVE_INT64_TIMESTAMP static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = { @@ -1828,7 +1973,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) if (precision != INTERVAL_FULL_PRECISION) { if (precision < 0 || precision > MAX_INTERVAL_PRECISION) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval(%d) precision must be between %d and %d", precision, 0, MAX_INTERVAL_PRECISION))); @@ -1862,6 +2007,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) #endif } } + return true; } /* @@ -1884,7 +2030,7 @@ make_interval(PG_FUNCTION_ARGS) * inputs as well, but it's not entirely clear what limits to apply. */ if (isinf(secs) || isnan(secs)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); @@ -2375,7 +2521,15 @@ tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *result) * Convert a interval data type to a tm structure. */ int -interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec) +interval2tm_safe(Interval span, struct pg_tm * tm, fsec_t *fsec, Node* escontext); + +int +interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec) { + return interval2tm_safe(span, tm, fsec, NULL); +} + +int +interval2tm_safe(Interval span, struct pg_tm * tm, fsec_t *fsec, Node* escontext) { TimeOffset time; TimeOffset tfrac; @@ -2390,7 +2544,7 @@ 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)) - ereport(ERROR, + ereturn(escontext, -1, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); tfrac = time / USECS_PER_MINUTE; @@ -2674,7 +2828,8 @@ timestamp_eq_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0); } @@ -2686,7 +2841,8 @@ timestamp_ne_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0); } @@ -2698,7 +2854,8 @@ timestamp_lt_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0); } @@ -2710,7 +2867,8 @@ timestamp_gt_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0); } @@ -2722,7 +2880,8 @@ timestamp_le_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0); } @@ -2734,7 +2893,8 @@ timestamp_ge_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0); } @@ -2746,7 +2906,8 @@ timestamp_cmp_timestamptz(PG_FUNCTION_ARGS) TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz dt1; - dt1 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt1, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2)); } @@ -2758,7 +2919,8 @@ timestamptz_eq_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0); } @@ -2770,7 +2932,8 @@ timestamptz_ne_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0); } @@ -2782,7 +2945,8 @@ timestamptz_lt_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0); } @@ -2794,7 +2958,8 @@ timestamptz_gt_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0); } @@ -2806,7 +2971,8 @@ timestamptz_le_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0); } @@ -2818,7 +2984,8 @@ timestamptz_ge_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0); } @@ -2830,7 +2997,8 @@ timestamptz_cmp_timestamp(PG_FUNCTION_ARGS) Timestamp timestampVal = PG_GETARG_TIMESTAMP(1); TimestampTz dt2; - dt2 = timestamp2timestamptz(timestampVal); + if (!timestamp2timestamptz_safe(timestampVal, &dt2, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2)); } @@ -2955,8 +3123,18 @@ interval_div_internal(Interval *interval1, Interval *interval2, static inline Timestamp timestamp_offset_internal(Timestamp timestamp, Interval *span) { - if (TIMESTAMP_NOT_FINITE(timestamp)) - return timestamp; + Timestamp result; + (void) timestamp_offset_internal_safe(timestamp, span, &result, NULL); + return result; +} + +static inline bool +timestamp_offset_internal_safe(Timestamp timestamp, Interval *span, Timestamp *result, Node *escontext) +{ + if (TIMESTAMP_NOT_FINITE(timestamp)) { + *result = timestamp; + return true; + } if (span->month != 0) { @@ -2965,7 +3143,7 @@ timestamp_offset_internal(Timestamp timestamp, Interval *span) fsec_t fsec = 0; if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -2986,7 +3164,7 @@ timestamp_offset_internal(Timestamp timestamp, Interval *span) tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } @@ -2999,7 +3177,7 @@ timestamp_offset_internal(Timestamp timestamp, Interval *span) int julian; if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -3008,13 +3186,14 @@ timestamp_offset_internal(Timestamp timestamp, Interval *span) j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } timestamp += span->time; - return timestamp; + *result = timestamp; + return true; } /* @@ -3022,6 +3201,14 @@ timestamp_offset_internal(Timestamp timestamp, Interval *span) */ static inline Timestamp timestamp_offset_multiple(Timestamp base, Interval *unit, int64 mul) +{ + Timestamp result; + (void) timestamp_offset_multiple_safe(base, unit, mul, &result, NULL); + return result; +} + +static inline bool +timestamp_offset_multiple_safe(Timestamp base, Interval *unit, int64 mul, Timestamp *result, Node *escontext) { Interval span; @@ -3029,7 +3216,10 @@ timestamp_offset_multiple(Timestamp base, Interval *unit, int64 mul) span.month = unit->month * mul; span.day = unit->day * mul; - return timestamp_offset_internal(base, &span); + if (!timestamp_offset_internal_safe(base, &span, result, escontext)) + return false; + + return true; } /* @@ -3048,6 +3238,14 @@ timestamp_offset_multiple(Timestamp base, Interval *unit, int64 mul) */ static inline TimestampTz timestamptz_offset_internal(TimestampTz timestamp, Interval *span) +{ + TimestampTz result; + (void) timestamptz_offset_internal_safe(timestamp, span, &result, NULL); + return result; +} + +static inline bool +timestamptz_offset_internal_safe(TimestampTz timestamp, Interval *span, TimestampTz *result, Node *escontext) { int tz; @@ -3061,7 +3259,7 @@ timestamptz_offset_internal(TimestampTz timestamp, Interval *span) fsec_t fsec = 0; if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -3084,7 +3282,7 @@ timestamptz_offset_internal(TimestampTz timestamp, Interval *span) tz = DetermineTimeZoneOffset(tm, session_timezone); if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } @@ -3097,7 +3295,7 @@ timestamptz_offset_internal(TimestampTz timestamp, Interval *span) int julian; if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -3108,13 +3306,14 @@ timestamptz_offset_internal(TimestampTz timestamp, Interval *span) tz = DetermineTimeZoneOffset(tm, session_timezone); if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } timestamp += span->time; - return timestamp; + *result = timestamp; + return true; } @@ -3123,6 +3322,14 @@ timestamptz_offset_internal(TimestampTz timestamp, Interval *span) */ static inline TimestampTz timestamptz_offset_multiple(TimestampTz base, Interval *unit, int64 mul) +{ + TimestampTz result; + (void) timestamptz_offset_multiple_safe(base, unit, mul, &result, NULL); + return result; +} + +static inline bool +timestamptz_offset_multiple_safe(TimestampTz base, Interval *unit, int64 mul, TimestampTz *result, Node *escontext) { Interval span; @@ -3130,7 +3337,10 @@ timestamptz_offset_multiple(TimestampTz base, Interval *unit, int64 mul) span.month = unit->month * mul; span.day = unit->day * mul; - return timestamptz_offset_internal(base, &span); + if (!timestamptz_offset_internal_safe(base, &span, result, escontext)) + return false; + + return true; } @@ -3399,7 +3609,7 @@ timestamp_mi(PG_FUNCTION_ARGS) result = (Interval *) palloc(sizeof(Interval)); if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("cannot subtract infinite timestamps"))); @@ -3605,7 +3815,8 @@ timestamp_pl_interval(PG_FUNCTION_ARGS) Interval *span = PG_GETARG_INTERVAL_P(1); Timestamp result; - result = timestamp_offset_internal(timestamp, span); + if (!timestamp_offset_internal_safe(timestamp, span, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -3622,7 +3833,8 @@ timestamp_mi_interval(PG_FUNCTION_ARGS) tspan.day = -span->day; tspan.time = -span->time; - result = timestamp_offset_internal(timestamp, &tspan); + if (!timestamp_offset_internal_safe(timestamp, &tspan, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -3636,7 +3848,9 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS) { TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); Interval *span = PG_GETARG_INTERVAL_P(1); - TimestampTz result = timestamptz_offset_internal(timestamp, span); + TimestampTz result = 0; + if (!timestamptz_offset_internal_safe(timestamp, span, &result, fcinfo->context)) + PG_RETURN_NULL(); PG_RETURN_TIMESTAMP(result); } @@ -3647,13 +3861,15 @@ timestamptz_mi_interval(PG_FUNCTION_ARGS) TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); Interval *span = PG_GETARG_INTERVAL_P(1); Interval tspan; - TimestampTz result; + TimestampTz result = 0; tspan.month = -span->month; tspan.day = -span->day; tspan.time = -span->time; - result = timestamptz_offset_internal(timestamp, &tspan); + if (!timestamptz_offset_internal_safe(timestamp, &tspan, &result, fcinfo->context)) + PG_RETURN_NULL(); + PG_RETURN_TIMESTAMP(result); } @@ -3669,17 +3885,17 @@ interval_um(PG_FUNCTION_ARGS) result->time = -interval->time; /* overflow check copied from int4um */ if (interval->time != 0 && SAMESIGN(result->time, interval->time)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->day = -interval->day; if (interval->day != 0 && SAMESIGN(result->day, interval->day)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->month = -interval->month; if (interval->month != 0 && SAMESIGN(result->month, interval->month)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); @@ -3729,21 +3945,21 @@ interval_pl(PG_FUNCTION_ARGS) /* overflow check copied from int4pl */ if (SAMESIGN(span1->month, span2->month) && !SAMESIGN(result->month, span1->month)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->day = span1->day + span2->day; if (SAMESIGN(span1->day, span2->day) && !SAMESIGN(result->day, span1->day)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->time = span1->time + span2->time; if (SAMESIGN(span1->time, span2->time) && !SAMESIGN(result->time, span1->time)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); @@ -3763,21 +3979,21 @@ interval_mi(PG_FUNCTION_ARGS) /* overflow check copied from int4mi */ if (!SAMESIGN(span1->month, span2->month) && !SAMESIGN(result->month, span1->month)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->day = span1->day - span2->day; if (!SAMESIGN(span1->day, span2->day) && !SAMESIGN(result->day, span1->day)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->time = span1->time - span2->time; if (!SAMESIGN(span1->time, span2->time) && !SAMESIGN(result->time, span1->time)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); @@ -3806,14 +4022,14 @@ interval_mul(PG_FUNCTION_ARGS) result_double = span->month * factor; if (result_double > INT_MAX || result_double < INT_MIN) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->month = (int32) result_double; result_double = span->day * factor; if (result_double > INT_MAX || result_double < INT_MIN) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->day = (int32) result_double; @@ -3858,7 +4074,7 @@ interval_mul(PG_FUNCTION_ARGS) #ifdef HAVE_INT64_TIMESTAMP result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC); if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double)) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); result->time = (int64) result_double; @@ -3958,7 +4174,7 @@ interval_div(PG_FUNCTION_ARGS) result = (Interval *) palloc(sizeof(Interval)); if (factor == 0.0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); @@ -4000,7 +4216,7 @@ interval_interval_div(PG_FUNCTION_ARGS) float8 result = 0.0; if (interval_cmp_internal(divisor, &IntervalZero) == 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); @@ -4023,7 +4239,7 @@ interval_interval_mod(PG_FUNCTION_ARGS) Interval *result = (Interval *) palloc0(sizeof(Interval)); if (interval_cmp_internal(divisor, &IntervalZero) == 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); @@ -4305,12 +4521,12 @@ timestamp_age(PG_FUNCTION_ARGS) } if (tm2interval(tm, fsec, result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); } else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -4434,12 +4650,12 @@ timestamptz_age(PG_FUNCTION_ARGS) } if (tm2interval(tm, fsec, result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); } else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -4502,6 +4718,14 @@ timestamp_li_fraction(Timestamp x, Timestamp x0, Timestamp x1, */ Timestamp timestamp_li_value(float8 f, Timestamp y0, Timestamp y1) +{ + Timestamp result = 0; + (void) timestamp_li_value_safe(f, y0, y1, &result, NULL); + return result; +} + +bool +timestamp_li_value_safe(float8 f, Timestamp y0, Timestamp y1, Timestamp *result, Node *escontext) { Timestamp y; Interval diffy; @@ -4513,10 +4737,14 @@ timestamp_li_value(float8 f, Timestamp y0, Timestamp y1) offset = DatumGetIntervalP(DirectFunctionCall2(interval_mul, IntervalPGetDatum(&diffy), Float8GetDatum(f))); - y = timestamp_offset_internal(y0, offset); + if (!timestamp_offset_internal_safe(y0, offset, result, escontext)) { + pfree(offset); + return false; + } + pfree(offset); - return y; + return true; } /* @@ -4544,9 +4772,17 @@ timestamptz_li_fraction(TimestampTz x, TimestampTz x0, TimestampTz x1, */ Timestamp timestamptz_li_value(float8 f, TimestampTz y0, TimestampTz y1) +{ + Timestamp result; + (void) timestamptz_li_value_safe(f, y0, y1, &result, NULL); + return result; +} + +bool +timestamptz_li_value_safe(float8 f, TimestampTz y0, TimestampTz y1, Timestamp *result, Node *escontext) { /* Internally identical to Timestamp */ - return timestamp_li_value(f, y0, y1); + return timestamptz_li_value_safe(f, y0, y1, result, escontext); } /*---------------------------------------------------------- @@ -4582,7 +4818,7 @@ timestamp_trunc(PG_FUNCTION_ARGS) if (type == UNITS) { if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -4671,7 +4907,7 @@ timestamp_trunc(PG_FUNCTION_ARGS) break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("timestamp units \"%s\" not supported", lowunits))); @@ -4679,13 +4915,13 @@ timestamp_trunc(PG_FUNCTION_ARGS) } if (tm2timestamp(tm, fsec, NULL, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp units \"%s\" not recognized", lowunits))); @@ -4725,7 +4961,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS) if (type == UNITS) { if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -4825,7 +5061,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS) break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("timestamp with time zone units \"%s\" not " "supported", lowunits))); @@ -4836,13 +5072,13 @@ timestamptz_trunc(PG_FUNCTION_ARGS) tz = DetermineTimeZoneOffset(tm, session_timezone); if (tm2timestamp(tm, fsec, &tz, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp with time zone units \"%s\" not recognized", lowunits))); @@ -4878,7 +5114,7 @@ interval_trunc(PG_FUNCTION_ARGS) if (type == UNITS) { - if (interval2tm(*interval, tm, &fsec) == 0) + if (interval2tm_safe(*interval, tm, &fsec, fcinfo->context) == 0) { switch (val) { @@ -4932,20 +5168,20 @@ interval_trunc(PG_FUNCTION_ARGS) default: if (val == DTK_WEEK) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("interval units \"%s\" not supported " "because months usually have fractional weeks", lowunits))); else - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("interval units \"%s\" not supported", lowunits))); } if (tm2interval(tm, fsec, result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); } @@ -4954,7 +5190,7 @@ interval_trunc(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval units \"%s\" not recognized", lowunits))); @@ -5170,7 +5406,7 @@ timestamp_part(PG_FUNCTION_ARGS) if (type == UNITS) { if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -5302,7 +5538,7 @@ timestamp_part(PG_FUNCTION_ARGS) case DTK_TZ_MINUTE: case DTK_TZ_HOUR: default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("timestamp units \"%s\" not supported", lowunits))); @@ -5322,7 +5558,7 @@ timestamp_part(PG_FUNCTION_ARGS) break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("timestamp units \"%s\" not supported", lowunits))); @@ -5332,7 +5568,7 @@ timestamp_part(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp units \"%s\" not recognized", lowunits))); result = 0; @@ -5376,7 +5612,7 @@ timestamptz_part(PG_FUNCTION_ARGS) if (type == UNITS) { if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); @@ -5508,7 +5744,7 @@ timestamptz_part(PG_FUNCTION_ARGS) break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("timestamp with time zone units \"%s\" not supported", lowunits))); @@ -5529,7 +5765,7 @@ timestamptz_part(PG_FUNCTION_ARGS) break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("timestamp with time zone units \"%s\" not supported", lowunits))); @@ -5538,7 +5774,7 @@ timestamptz_part(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp with time zone units \"%s\" not recognized", lowunits))); @@ -5576,7 +5812,7 @@ interval_part(PG_FUNCTION_ARGS) if (type == UNITS) { - if (interval2tm(*interval, tm, &fsec) == 0) + if (interval2tm_safe(*interval, tm, &fsec, fcinfo->context) == 0) { switch (val) { @@ -5644,7 +5880,7 @@ interval_part(PG_FUNCTION_ARGS) break; default: - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("interval units \"%s\" not supported", lowunits))); @@ -5671,7 +5907,7 @@ interval_part(PG_FUNCTION_ARGS) } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval units \"%s\" not recognized", lowunits))); @@ -5723,7 +5959,8 @@ timestamp_zone(PG_FUNCTION_ARGS) strlen(tzname), false); - type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp); + if (!DecodeTimezoneAbbrevSafe(0, lowzone, &val, &tzp, &type, fcinfo->context)) + PG_RETURN_NULL(); if (type == TZ || type == DTZ) { @@ -5735,7 +5972,7 @@ timestamp_zone(PG_FUNCTION_ARGS) { /* dynamic-offset abbreviation, resolve using specified time */ if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp); @@ -5749,19 +5986,19 @@ timestamp_zone(PG_FUNCTION_ARGS) { /* Apply the timezone change */ if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tz = DetermineTimeZoneOffset(&tm, tzp); if (tm2timestamp(&tm, fsec, &tz, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not convert to time zone \"%s\"", tzname))); } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", tzname))); result = 0; /* keep compiler quiet */ @@ -5786,7 +6023,7 @@ timestamp_izone(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMPTZ(timestamp); if (zone->month != 0 || zone->day != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval time zone \"%s\" must not include months or days", DatumGetCString(DirectFunctionCall1(interval_out, @@ -5810,12 +6047,27 @@ Datum timestamp_timestamptz(PG_FUNCTION_ARGS) { Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + TimestampTz result; + + if (!timestamp2timestamptz_safe(timestamp, &result, fcinfo->context)) + PG_RETURN_NULL(); - PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp)); + PG_RETURN_TIMESTAMPTZ(result); } +static bool +timestamp2timestamptz_safe(Timestamp timestamp, TimestampTz *res, Node *escontext); + static TimestampTz timestamp2timestamptz(Timestamp timestamp) +{ + TimestampTz result; + (void) timestamp2timestamptz_safe(timestamp, &result, NULL); + return result; +} + +static bool +timestamp2timestamptz_safe(Timestamp timestamp, TimestampTz *res, Node *escontext) { TimestampTz result; struct pg_tm tt, @@ -5828,19 +6080,20 @@ timestamp2timestamptz(Timestamp timestamp) else { if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); tz = DetermineTimeZoneOffset(tm, session_timezone); if (tm2timestamp(tm, fsec, &tz, &result) != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } - return result; + *res = result; + return true; } /* timestamptz_timestamp() @@ -5861,11 +6114,11 @@ timestamptz_timestamp(PG_FUNCTION_ARGS) else { if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); if (tm2timestamp(tm, fsec, NULL, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } @@ -5907,7 +6160,8 @@ timestamptz_zone(PG_FUNCTION_ARGS) strlen(tzname), false); - type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp); + if (!DecodeTimezoneAbbrevSafe(0, lowzone, &val, &tzp, &type, fcinfo->context)) + PG_RETURN_NULL(); if (type == TZ || type == DTZ) { @@ -5920,7 +6174,8 @@ timestamptz_zone(PG_FUNCTION_ARGS) /* dynamic-offset abbreviation, resolve using specified time */ int isdst; - tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst); + if (!DetermineTimeZoneAbbrevOffsetTSSafe(timestamp, tzname, tzp, &isdst, &tz, fcinfo->context)) + PG_RETURN_NULL(); result = dt2local(timestamp, tz); } else @@ -5934,18 +6189,18 @@ timestamptz_zone(PG_FUNCTION_ARGS) fsec_t fsec = 0; if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); if (tm2timestamp(&tm, fsec, NULL, &result) != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not convert to time zone \"%s\"", tzname))); } else { - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("time zone \"%s\" not recognized", tzname))); result = 0; /* keep compiler quiet */ @@ -5971,7 +6226,7 @@ timestamptz_izone(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMP(timestamp); if (zone->month != 0 || zone->day != 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("interval time zone \"%s\" must not include months or days", DatumGetCString(DirectFunctionCall1(interval_out, @@ -6032,7 +6287,7 @@ generate_series_timestamp(PG_FUNCTION_ARGS) fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero); if (fctx->step_sign == 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("step size cannot equal zero"))); @@ -6113,7 +6368,7 @@ generate_series_timestamptz(PG_FUNCTION_ARGS) fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero); if (fctx->step_sign == 0) - ereport(ERROR, + ereturn(fcinfo->context, 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("step size cannot equal zero"))); diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 65380ef9b0..30d01a781b 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -1888,6 +1888,30 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, return result; } +Datum +DirectFunctionCall1CollSafe(PGFunction func, Oid collation, Datum arg1, fmNodePtr escontext) +{ + FunctionCallInfoData fcinfo; + Datum result; + + InitFunctionCallInfoData(fcinfo, NULL, 1, collation, escontext, NULL); + + fcinfo.arg[0] = arg1; + fcinfo.argnull[0] = false; + + result = (*func) (&fcinfo); + + /* Result value is garbage, and could be null, if an error was reported */ + if (SOFT_ERROR_OCCURRED(escontext)) + return (Datum) 0; + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "function %p returned NULL", (void *) func); + + return result; +} + /* * Call a previously-looked-up OidFunctionCallNColl function, with non-exception * handling of "soft" errors. diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 8764b6ee19..6670487c12 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -579,6 +579,8 @@ extern Datum OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg6, Datum arg7, Datum arg8, Datum arg9); +extern Datum DirectFunctionCall1CollSafe(PGFunction func, Oid collation, + Datum arg1, fmNodePtr escontext); extern Datum OidFunctionCall3CollSafe(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, fmNodePtr escontext); @@ -644,7 +646,8 @@ extern Datum OidFunctionCall3CollSafe(Oid functionId, Oid collation, #define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) - +#define DirectFunctionCall1Safe(func, arg1, context) \ + DirectFunctionCall1CollSafe(func, InvalidOid, arg1, context) #define OidFunctionCall3Safe(functionId, arg1, arg2, arg3, escontext) \ OidFunctionCall3CollSafe(functionId, InvalidOid, arg1, arg2, arg3, escontext) diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 98e7458128..ffaaf46f0a 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -684,6 +684,7 @@ extern Datum regdictionaryrecv(PG_FUNCTION_ARGS); extern Datum regdictionarysend(PG_FUNCTION_ARGS); extern Datum text_regclass(PG_FUNCTION_ARGS); extern List *stringToQualifiedNameList(const char *string); +extern bool stringToQualifiedNameListSafe(const char *string, List **result, Node *escotext); extern char *format_procedure(Oid procedure_oid); extern char *format_procedure_qualified(Oid procedure_oid); extern char *format_operator(Oid operator_oid); diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index a091f6fa04..f5ca0f5bbc 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -298,10 +298,16 @@ extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, extern int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp); +extern bool DecodeDateTimeSafe(char **field, int *ftype, + int nf, int *dtype, + struct pg_tm * tm, fsec_t *fsec, int *tzp, int *result, Node *escontext); extern int DecodeTimezone(char *str, int *tzp); extern int DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp); +extern bool DecodeTimeOnlySafe(char **field, int *ftype, + int nf, int *dtype, + struct pg_tm * tm, fsec_t *fsec, int *tzp, int *result, Node *escontext); extern int DecodeInterval(char **field, int *ftype, int nf, int range, int *dtype, struct pg_tm * tm, fsec_t *fsec); extern int DecodeISO8601Interval(char *str, @@ -309,11 +315,15 @@ extern int DecodeISO8601Interval(char *str, extern void DateTimeParseError(int dterr, const char *str, const char *datatype) __attribute__((noreturn)); +extern bool DateTimeParseErrorSafe(int dterr, const char *str, + const char *datatype, Node *escontext); extern int DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp); extern int DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp); extern int DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst); +extern bool DetermineTimeZoneAbbrevOffsetTSSafe(TimestampTz ts, const char *abbr, + pg_tz *tzp, int *isdst, int *result, Node *escontext); extern void EncodeDateOnly(struct pg_tm * tm, int style, char *str); extern void EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str); @@ -326,6 +336,8 @@ extern int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, extern int DecodeTimezoneAbbrev(int field, char *lowtoken, int *offset, pg_tz **tz); +extern bool DecodeTimezoneAbbrevSafe(int field, char *lowtoken, + int *offset, pg_tz **tz, int *result, Node *escontext); extern int DecodeSpecial(int field, char *lowtoken, int *val); extern int DecodeUnits(int field, char *lowtoken, int *val); diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 7ee4db00be..14fa1dc3b5 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -235,10 +235,12 @@ extern Datum timestamptz_part(PG_FUNCTION_ARGS); extern float8 timestamp_li_fraction(Timestamp x, Timestamp x0, Timestamp x1, bool *eq_bounds, bool *eq_abscissas); extern Timestamp timestamp_li_value(float8 f, Timestamp y0, Timestamp y1); +extern bool timestamp_li_value_safe(float8 f, Timestamp y0, Timestamp y1, Timestamp *result, Node *escontext); extern float8 timestamptz_li_fraction(TimestampTz x, TimestampTz x0, TimestampTz x1, bool *eq_bounds, bool *eq_abscissas); extern Timestamp timestamptz_li_value(float8 f, TimestampTz y0, TimestampTz y1); +extern bool timestamptz_li_value_safe(float8 f, TimestampTz y0, TimestampTz y1, Timestamp *result, Node *escontext); extern Datum now(PG_FUNCTION_ARGS); extern Datum statement_timestamp(PG_FUNCTION_ARGS); @@ -282,6 +284,7 @@ extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec); extern int interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec); +extern int interval2tm_safe(Interval span, struct pg_tm * tm, fsec_t *fsec, Node *escontext); extern int tm2interval(struct pg_tm * tm, fsec_t fsec, Interval *span); extern Timestamp SetEpochTimestamp(void);