ERROR: integer out of range (SQLSTATE 22003) means a value or a calculation went
past 2,147,483,647, the largest value of PostgreSQL's integer. Change the column
to bigint, or cast one side of the calculation to bigint.
In the test the column views integer held 2147483647, and both an insert of
2147483648 and views + 1 failed. After
ALTER TABLE page_view ALTER COLUMN views TYPE bigint both worked. A
multiplication of two integer literals failed the same way until one side was cast.
The error
INSERT INTO page_view (page, views) VALUES ('/home', 2147483647);
INSERT 0 1
INSERT INTO page_view (page, views) VALUES ('/blog', 2147483648);
psql:/tmp/f22003.sql:4: ERROR: 22003: integer out of range
LOCATION: int84, int8.c:1254
UPDATE page_view SET views = views + 1 WHERE page = '/home';
psql:/tmp/f22003.sql:5: ERROR: 22003: integer out of range
LOCATION: int4pl, int.c:827
SELECT 50000 * 50000 AS product;
psql:/tmp/f22003.sql:6: ERROR: 22003: integer out of range
LOCATION: int4mul, int.c:855
Why it happens
In the integer column 2147483647 was stored and 2147483648 was not. The
three failures in the test are three ways to reach the limit. The insert sent a number too
large for the column. The update added 1 to a value already at the top. The
SELECT never touched a table: 50000 * 50000 is 2,500,000,000, and
with both literals typed as integer the product was computed as an integer and overflowed.
The message does not name the column, so look at the statement on the line psql reports.
The update case is the one that surprises: views + 1 is harmless SQL, and it
failed here because the stored value sat at 2147483647, the top of the range.
The fix
SELECT 50000::bigint * 50000 AS product;
product
------------
2500000000
(1 row)
ALTER TABLE page_view ALTER COLUMN views TYPE bigint;
ALTER TABLE
UPDATE page_view SET views = views + 1 WHERE page = '/home';
UPDATE 1
INSERT INTO page_view (page, views) VALUES ('/blog', 2147483648);
INSERT 0 1
SELECT page, views FROM page_view ORDER BY id;
page | views
-------+------------
/home | 2147483648
/blog | 2147483648
(2 rows)
Casting one operand with ::bigint made the multiplication a bigint
multiplication, and the result came back. For a column, ALTER COLUMN ... TYPE
bigint widened it and the update and insert that had failed then went through. The
test table had one row at that point; time the change on a large table before running it in
production. In application code, map the widened column to a 64-bit type such as C#
long.
How it was reproduced
A postgres:18 container (PostgreSQL 18.4, Debian 18.4-1.pgdg13+1) on Docker
Engine 29.9.2, database lab, table
page_view (id serial, page text, views integer). The script
f22003.sql ran with
docker exec fix8-pg3 sh -c "psql -U postgres -d lab -e -f /tmp/f22003.sql 2>&1"
and \set VERBOSITY verbose at its top for the SQLSTATE. The container name is
the test's own.
Frequently asked
- What is the maximum value of an integer column in PostgreSQL?
- 2147483647 was stored in the test and 2147483648 failed with 22003 integer out of range. A bigint column took 2147483648.
- How do I fix integer out of range in a PostgreSQL calculation?
- Cast one operand to bigint. SELECT 50000 * 50000 failed with 22003 in the test and SELECT 50000::bigint * 50000 returned 2500000000.
- How do I change a PostgreSQL column from integer to bigint?
- Run ALTER TABLE page_view ALTER COLUMN views TYPE bigint. In the test the update and insert that had failed with integer out of range worked right after it.
More decoded errors in the Fixes category.