Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL - Smallint overflowing when creating index on multiple columns. Is this a bug?

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.

like image 295
Mike Christensen Avatar asked Aug 05 '12 05:08

Mike Christensen


2 Answers

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.

like image 166
mu is too short Avatar answered Oct 21 '22 11:10

mu is too short


Why don't you use an INTERVAL for a time interval? It's a perfect solution for your problem.

like image 37
Frank Heikens Avatar answered Oct 21 '22 09:10

Frank Heikens