[PATCH] Avoid internal error for invalid interval typmods

Started by Feng Wu25 days ago10 messageshackers
Jump to latest
#1Feng Wu
wufengwufengwufeng@gmail.com

Hi,

While fuzzing PostgreSQL, I noticed that the interval length-coercion
function can report an internal error for user-supplied input:

SELECT pg_catalog.interval(interval '1 day', 1539);

Currently this fails with:

ERROR: unrecognized interval typmod: 1539

The error is raised with elog(ERROR) in AdjustIntervalForTypmod(), so it
is reported as SQLSTATE XX000. Since pg_catalog.interval(interval, int4)
is callable from SQL, arbitrary typmod values can reach this path.

The patch below changes that case to report
ERRCODE_INVALID_PARAMETER_VALUE instead, matching the nearby precision
validation in the same function. It also adds a regression test that
catches the error as invalid_parameter_value.

Tested with the interval regression test.

Regards,
Feng

---
src/backend/utils/adt/timestamp.c | 4 +++-
src/test/regress/expected/interval.out | 10 ++++++++++
src/test/regress/sql/interval.sql | 9 +++++++++
3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/adt/timestamp.c
b/src/backend/utils/adt/timestamp.c
index a20e7ea1..01b9ed52 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -1489,7 +1489,9 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod,
 			/* fractional-second rounding will be dealt with below */
 		}
 		else
-			elog(ERROR, "unrecognized interval typmod: %d", typmod);
+			ereturn(escontext, false,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("unrecognized interval typmod: %d", typmod)));
 		/* Need to adjust sub-second precision? */
 		if (precision != INTERVAL_FULL_PRECISION)
diff --git a/src/test/regress/expected/interval.out
b/src/test/regress/expected/interval.out
index a16e3ccd..c5e10482 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -857,6 +857,16 @@ SELECT interval(2) '1 day 01:23:45.6789';
  1 day 01:23:45.68
 (1 row)
+-- invalid typmods passed to the length-coercion function are user errors,
+-- not internal errors
+DO $$
+BEGIN
+  PERFORM pg_catalog.interval(interval '1 day', 1539);
+EXCEPTION WHEN invalid_parameter_value THEN
+  RAISE NOTICE 'invalid interval typmod rejected';
+END
+$$;
+NOTICE:  invalid interval typmod rejected
 SELECT interval '12:34.5678' minute to second(2);  -- per SQL spec
   interval
 -------------
diff --git a/src/test/regress/sql/interval.sql
b/src/test/regress/sql/interval.sql
index 43bc7939..88794c21 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -257,6 +257,15 @@ SELECT interval '123 2:03 -2:04'; -- not ok,
redundant hh:mm fields
 -- test syntaxes for restricted precision
 SELECT interval(0) '1 day 01:23:45.6789';
 SELECT interval(2) '1 day 01:23:45.6789';
+-- invalid typmods passed to the length-coercion function are user errors,
+-- not internal errors
+DO $$
+BEGIN
+  PERFORM pg_catalog.interval(interval '1 day', 1539);
+EXCEPTION WHEN invalid_parameter_value THEN
+  RAISE NOTICE 'invalid interval typmod rejected';
+END
+$$;
 SELECT interval '12:34.5678' minute to second(2);  -- per SQL spec
 SELECT interval '1.234' second;
 SELECT interval '1.234' second(2);
-- 
2.50.1 (Apple Git-155)
#2Feng Wu
wufengwufengwufeng@gmail.com
In reply to: Feng Wu (#1)
Re: [PATCH] Avoid internal error for invalid interval typmods

Apologies for the duplicate email. I sent the patch twice by mistake
from two different clients. The two copies are identical, so either one
can be used.

Regards,
Feng

#3Haibo Yan
tristan.yim@gmail.com
In reply to: Feng Wu (#1)
Re: [PATCH] Avoid internal error for invalid interval typmods

On Mon, Jun 29, 2026 at 9:26 PM Feng Wu <wufengwufengwufeng@gmail.com> wrote:

Hi,

While fuzzing PostgreSQL, I noticed that the interval length-coercion
function can report an internal error for user-supplied input:

SELECT pg_catalog.interval(interval '1 day', 1539);

Currently this fails with:

ERROR: unrecognized interval typmod: 1539

The error is raised with elog(ERROR) in AdjustIntervalForTypmod(), so it
is reported as SQLSTATE XX000. Since pg_catalog.interval(interval, int4)
is callable from SQL, arbitrary typmod values can reach this path.

The patch below changes that case to report
ERRCODE_INVALID_PARAMETER_VALUE instead, matching the nearby precision
validation in the same function. It also adds a regression test that
catches the error as invalid_parameter_value.

I wonder whether AdjustIntervalForTypmod() should be changed too.
pg_catalog.interval(interval, int4) is SQL-callable, so users can pass
arbitrary typmod values directly. If such an invalid typmod reaches
AdjustIntervalForTypmod(), reporting XX000 seems inappropriate, since
it is not really an internal error but invalid user input.

Tested with the interval regression test.

Could we use ERRCODE_INVALID_PARAMETER_VALUE for this case and add a
regression test covering a direct call to
pg_catalog.interval(interval, int4) with an invalid typmod?

Regards,
Feng

---
src/backend/utils/adt/timestamp.c | 4 +++-
src/test/regress/expected/interval.out | 10 ++++++++++
src/test/regress/sql/interval.sql | 9 +++++++++
3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/adt/timestamp.c
b/src/backend/utils/adt/timestamp.c
index a20e7ea1..01b9ed52 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -1489,7 +1489,9 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod,
/* fractional-second rounding will be dealt with below */
}
else
-                       elog(ERROR, "unrecognized interval typmod: %d", typmod);
+                       ereturn(escontext, false,
+                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                        errmsg("unrecognized interval typmod: %d", typmod)));
/* Need to adjust sub-second precision? */
if (precision != INTERVAL_FULL_PRECISION)
diff --git a/src/test/regress/expected/interval.out
b/src/test/regress/expected/interval.out
index a16e3ccd..c5e10482 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -857,6 +857,16 @@ SELECT interval(2) '1 day 01:23:45.6789';
1 day 01:23:45.68
(1 row)
+-- invalid typmods passed to the length-coercion function are user errors,
+-- not internal errors
+DO $$
+BEGIN
+  PERFORM pg_catalog.interval(interval '1 day', 1539);
+EXCEPTION WHEN invalid_parameter_value THEN
+  RAISE NOTICE 'invalid interval typmod rejected';
+END
+$$;
+NOTICE:  invalid interval typmod rejected
SELECT interval '12:34.5678' minute to second(2);  -- per SQL spec
interval
-------------
diff --git a/src/test/regress/sql/interval.sql
b/src/test/regress/sql/interval.sql
index 43bc7939..88794c21 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -257,6 +257,15 @@ SELECT interval '123 2:03 -2:04'; -- not ok,
redundant hh:mm fields
-- test syntaxes for restricted precision
SELECT interval(0) '1 day 01:23:45.6789';
SELECT interval(2) '1 day 01:23:45.6789';
+-- invalid typmods passed to the length-coercion function are user errors,
+-- not internal errors
+DO $$
+BEGIN
+  PERFORM pg_catalog.interval(interval '1 day', 1539);
+EXCEPTION WHEN invalid_parameter_value THEN
+  RAISE NOTICE 'invalid interval typmod rejected';
+END
+$$;
SELECT interval '12:34.5678' minute to second(2);  -- per SQL spec
SELECT interval '1.234' second;
SELECT interval '1.234' second(2);
--
2.50.1 (Apple Git-155)

Regards
Haibo

#4Feng Wu
wufengwufengwufeng@gmail.com
In reply to: Haibo Yan (#3)
Re: [PATCH v2] Avoid internal error for invalid interval typmods

Hi Haibo,

Thanks for reviewing.

I agree that the SQL-callable pg_catalog.interval(interval, int4) path is the
important case to cover here. The v1 test was already exercising that direct
call, but it used a DO block intentionally so that the regression test checks
the SQLSTATE is invalid_parameter_value, rather than only matching the error
message text.

In v2, I kept that structure and updated the test comment to make this clearer.

Regards,
Feng

Attachments:

v2-0001-Avoid-internal-error-for-invalid-interval-typmods.patchtext/x-patch; charset=US-ASCII; name=v2-0001-Avoid-internal-error-for-invalid-interval-typmods.patchDownload+22-2
#5Haibo Yan
tristan.yim@gmail.com
In reply to: Feng Wu (#4)
Re: [PATCH v2] Avoid internal error for invalid interval typmods

On Tue, Jun 30, 2026 at 6:49 PM Feng Wu <wufengwufengwufeng@gmail.com> wrote:

Hi Haibo,

Thanks for reviewing.

I agree that the SQL-callable pg_catalog.interval(interval, int4) path is the
important case to cover here. The v1 test was already exercising that direct
call, but it used a DO block intentionally so that the regression test checks
the SQLSTATE is invalid_parameter_value, rather than only matching the error
message text.

In v2, I kept that structure and updated the test comment to make this clearer.

Regards,
Feng

Thank you for fixing this. v2 looks good to me.

Regards
Haibo

#6Feng Wu
wufengwufengwufeng@gmail.com
In reply to: Haibo Yan (#5)
Re: [PATCH v2] Avoid internal error for invalid interval typmods

Thanks.

I tried to add this patch to the CommitFest, but my community account is still
within the cool-off period for commitfest.postgresql.org login. If someone is
able to add it meanwhile, I would appreciate it.

Regards,
Feng

#7Feng Wu
wufengwufengwufeng@gmail.com
In reply to: Feng Wu (#6)
Re: [PATCH] Avoid internal error for invalid interval typmods

Haibo Yan reviewed v2 on the mailing list and said it looks good to him.

#8Feng Wu
wufengwufengwufeng@gmail.com
In reply to: Feng Wu (#6)
Re: [PATCH] Avoid internal error for invalid interval typmods

Haibo Yan reviewed v2 on the mailing list and said it looks good to him.

#9solai v
solai.cdac@gmail.com
In reply to: Feng Wu (#4)
Re: [PATCH v2] Avoid internal error for invalid interval typmods

Hi Feng,

I tested the v2 patch on PostgreSQL 20devel.
The patch applied cleanly, and I rebuilt and restarted the server successfully.

Before applying the patch, calling:
SELECT pg_catalog.interval(interval '1 day', 1539);
reported:
ERROR: unrecognized interval typmod: 1539

After applying the patch, the same DO block produced:
NOTICE: invalid interval typmod rejected
which confirms that the error is now reported as
invalid_parameter_value instead of an internal error.
I also verified that the existing interval behavior remains unchanged:
SELECT interval(0) '1 day 01:23:45.6789'; returned 1 day 01:23:46
SELECT interval(2) '1 day 01:23:45.6789'; returned 1 day 01:23:45.68

The patch worked as expected in my testing.

Regards,
solai

#10Feng Wu
wufengwufengwufeng@gmail.com
In reply to: solai v (#9)
Re: [PATCH v2] Avoid internal error for invalid interval typmods

Hi solai,

Thanks for testing the v2 patch and for moving it to Ready for Committer.

I also noticed the current CFBot failure in the Windows MinGW job, but
it appears to be an unrelated version mismatch with utf8_and_win.dll.
I will keep an eye on the next CFBot run.

Regards,
Feng