I was having an issue inserting the value 32767 into a smallint
column in Postgres, which would yield the error smallint out of range. This was odd because I could do:
SELECT 32767::int2;
Which would work just fine. After a little hair pulling, I finally tracked this down to an index on the column in question. First, here's the schema (Well, not really but I've simplified this down to a repro case):
CREATE TABLE Test
(
id uuid NOT NULL,
cooktime smallint,
preptime smallint,
CONSTRAINT test_pkey PRIMARY KEY (id )
)
WITH (
OIDS=FALSE
);
I now create the following index:
CREATE INDEX idx_test_totaltime
ON Test
USING btree
((cooktime + preptime) );
Next, I try to create the following row:
INSERT INTO Test (CookTime, PrepTime, Id)
VALUES (
(32767)::int2,
(10)::int2,
(E'fd47dc1e-c3c6-42c1-b058-689e926a72a4')::uuid
);
I get the error:
ERROR: smallint out of range SQL state: 22003
It seems that idx_test_totaltime
is expecting a maximum value of int2
, even though the index is applied on the sum of two smallints.
Is this a Postgres bug, or am I missing something simple? Is there a way to work around this limitation, or would I need to make these columns int4
and use a CHECK constraint to limit each value to 32767? I'm using Postgres 9.0.0 (Yes, I need to upgrade!) but I've created a SQL Fiddle which demonstrates this error on 9.1.4.
Your problem is that int2 + int2
is another int2
so the expression in your index, (cooktime + preptime)
, overflows for (32767, 10)
. You can get around this problem with a bit of casting in the index expression:
CREATE INDEX idx_test_totaltime
ON Test
USING btree
((cooktime::int4 + preptime::int4));
You only need one of the casts but using both doesn't hurt.
Why don't you use an INTERVAL for a time interval? It's a perfect solution for your problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With