diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 6a831875f7..5b745cff5c 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -48,8 +48,14 @@ static void AdjustTimeForTypmod(TimeADT *time, int32 typmod); /* common code for timetypmodin and timetztypmodin */ -static int32 -anytime_typmodin(bool istz, ArrayType *ta) +// 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 +68,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 +89,8 @@ anytime_typmodin(bool istz, ArrayType *ta) else typmod = *tl; - return typmod; + *result = typmod; + return true; } /* common code for timetypmodout and timetztypmodout */ @@ -136,7 +143,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"))); @@ -161,7 +168,7 @@ date_in(PG_FUNCTION_ARGS) } 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 +218,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 +260,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 +419,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 +459,14 @@ date_mii(PG_FUNCTION_ARGS) * Internal routines for promoting date to timestamp and timestamp with * time zone */ +// static Timestamp +// date2timestamp(DateADT dateVal) +// { + +// } -static Timestamp -date2timestamp(DateADT dateVal) +static bool +date2timestamp_safe(DateADT dateVal, Timestamp *res, Node *escontext) { Timestamp result; @@ -469,7 +481,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 +490,17 @@ date2timestamp(DateADT dateVal) #endif } - return result; + *res = result; + return true; } -static TimestampTz -date2timestamptz(DateADT dateVal) +// static TimestampTz +// date2timestamptz(DateADT dateVal) +// { +// } + +static bool +date2timestamptz_safe(DateADT dateVal, TimestampTz *res, Node *escontext) { TimestampTz result; struct pg_tm tt, @@ -506,7 +524,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,7 +532,8 @@ date2timestamptz(DateADT dateVal) #endif } - return result; + *res = result; + return true; } /* @@ -562,7 +581,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 +594,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 +607,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 +620,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 +633,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 +646,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 +659,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 +672,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 +685,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 +698,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 +711,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 +724,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 +737,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 +750,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 +763,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 +776,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 +789,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 +802,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 +815,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 +828,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 +841,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 +854,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 +867,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 +880,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 +893,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 +906,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 +919,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 +932,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 +952,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 +973,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 +990,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 +1015,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 +1035,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 +1062,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 +1088,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 */ @@ -1191,14 +1242,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 +1282,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 +1315,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 +1667,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 +1703,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 +1732,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 +2018,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 +2035,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))); @@ -2083,14 +2140,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 +2156,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 +2189,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 +2655,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 +2785,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 +2802,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))); @@ -2813,7 +2875,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 +2915,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..08902ab58e 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] = @@ -797,9 +798,15 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen, * happen if pg_time_t is just 32 bits), then assume UTC time zone - thomas * 1997-05-27 */ -int -DecodeDateTime(char **field, int *ftype, int nf, - int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp) +// int +// DecodeDateTime(char **field, int *ftype, int nf, +// int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp) +// { +// } + +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 +856,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 +898,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 +910,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 +922,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 +948,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 +969,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 +982,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 +997,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 +1017,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 +1055,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 +1072,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 +1128,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 +1139,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 +1162,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 +1185,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 +1220,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 +1236,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 +1257,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 +1269,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; @@ -1230,11 +1293,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 +1373,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 +1388,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 +1441,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 +1455,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 +1470,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 +1516,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 +1531,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 +1546,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 +1561,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; } @@ -1692,9 +1786,15 @@ DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp) * As above but the probe time is specified as a TimestampTz (hence, UTC time), * and DST status is returned into *isdst rather than into tm->tm_isdst. */ -int -DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, - pg_tz *tzp, int *isdst) +// int +// DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, +// pg_tz *tzp, int *isdst) +// { +// } + +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 +1807,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; } @@ -1769,9 +1872,16 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, * Allow specifying date to get a better time zone, * if time zones are allowed. - thomas 2001-12-26 */ -int -DecodeTimeOnly(char **field, int *ftype, int nf, - int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp) +// int +// DecodeTimeOnly(char **field, int *ftype, int nf, +// int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp) +// { + +// } + +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 +1920,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 +1931,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 +1947,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 +1976,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 +1994,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 +2010,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 +2053,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 +2080,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 +2136,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 +2147,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 +2169,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 +2192,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 +2232,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 +2249,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 +2266,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 +2280,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; @@ -2146,10 +2304,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 +2327,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf, break; default: - return DTERR_BAD_FORMAT; + *result = DTERR_BAD_FORMAT; + return true; } break; @@ -2181,8 +2341,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 +2356,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 +2411,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 +2426,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 +2483,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 +2502,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 +2515,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 +2534,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 +2568,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 +2593,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf, tm->tm_isdst = tmp->tm_isdst; } - return 0; + *result = 0; + return true; } /* DecodeDate() @@ -3067,9 +3264,15 @@ DecodeTimezone(char *str, int *tzp) * Implement a cache lookup since it is likely that dates * will be related in format. */ -int -DecodeTimezoneAbbrev(int field, char *lowtoken, - int *offset, pg_tz **tz) +// int +// DecodeTimezoneAbbrev(int field, char *lowtoken, +// int *offset, pg_tz **tz) +// { +// } + +bool +DecodeTimezoneAbbrevSafe(int field, char *lowtoken, + int *offset, pg_tz **tz, int *result, Node *escontext) { int type; const datetkn *tp; @@ -3097,7 +3300,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 +3310,8 @@ DecodeTimezoneAbbrev(int field, char *lowtoken, } } - return type; + *result = type; + return true; } @@ -3866,40 +4071,46 @@ DecodeUnits(int field, char *lowtoken, int *val) * DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three * separate SQLSTATE codes, so ... */ -void -DateTimeParseError(int dterr, const char *str, const char *datatype) +// 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))); @@ -4714,8 +4925,13 @@ InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl) /* * Helper subroutine to locate pg_tz timezone for a dynamic abbreviation. */ -static pg_tz * -FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp) +// static pg_tz * +// FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp) +// { +// } + +static bool +FetchDynamicTimeZoneSafe(TimeZoneAbbrevTable *tbl, const datetkn *tp, pg_tz **result, Node *escontext) { DynamicZoneAbbrev *dtza; @@ -4735,14 +4951,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; } @@ -4829,7 +5046,8 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS) TimestampTz now; int isdst; - tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp); + if (!FetchDynamicTimeZoneSafe(zoneabbrevtbl, tp, &tzp, fcinfo->context)) + PG_RETURN_NULL(); now = GetCurrentTransactionStartTimestamp(); gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now, tp->token,