CHECK constraint fails when it's not supposed to

Started by Richard Yenover 16 years ago2 messagesgeneral
Jump to latest
#1Richard Yen
richyen3@gmail.com

Hi All,

I encountered an odd issue regarding check constraints complaining
when they're not really violated.

For this particular machine, I am running 8.3.7, but on a machine
running 8.3.5, it seems to have succeeded. I also upgraded a third
machine from 8.3.5 to 8.3.7, and the query succeeded (so I'm
thinking
it's not related to different postgres versions)

I have a table called "m_class" and the definition is something like
this:

tii=# \d m_class
Table "public.m_class"
Column          |           Type
|                          Modifiers
-------------------------+--------------------------
+--------------------------------------------------------------
id                      | integer                  | not null
default nextval(('m_class_id_seq'::text)::regclass)
class_type              | smallint                 | not null
title                   | character varying(100)   | not null
...snip...
date_setup              | timestamp with time zone | not null
default ('now'::text)::date
date_start              | timestamp with time zone | not null
date_end                | timestamp with time zone | not null
term_length             | interval                 | not null
default '5 years'::interval
...snip...
max_portfolio_file_size | integer                  |
Indexes:
"m_class_pkey" PRIMARY KEY, btree (id)
"m_class_account_idx" btree (account)
"m_class_instructor_idx" btree (instructor)
Check constraints:
"end_after_start_check" CHECK (date_end >= date_start)
"end_within_term_length" CHECK (date_end <= (date_start +
term_length))
"min_password_length_check" CHECK
(length(enrollment_password::text) >= 4)
"positive_term_length" CHECK (term_length > '00:00:00'::interval)
"start_after_setup_check" CHECK (date_start >= date_setup)
...snip...

When I run my update, it fails:

tii=# begin; update only "public"."m_class" set date_end='2009-09-03
05:38:24.030331-07',term_length='177 days 17:59:09.868431' where
id='2652020';
BEGIN
ERROR: new row for relation "m_class" violates check constraint
"end_within_term_length"
tii=# rollback;
ROLLBACK

The data reads:

tii=# select date_start, date_end, term_length, '2009-09-03
05:38:24.030331-07'::timestamptz - date_start AS new_term_length
from m_class where id = 2652020;
date_start          |          date_end           |
term_length |     new_term_length
-----------------------------+-----------------------------
+-------------+--------------------------
2009-03-09 11:39:14.1619-07 | 2009-04-08 11:39:14.1619-07 | 30
days     | 177 days 17:59:09.868431

Based on new_term_length, the update should succeed. However, it
doesn't. Would anyone have an explanation?

Thanks for your help!
--Richard

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Richard Yen (#1)
Re: CHECK constraint fails when it's not supposed to

Richard Yen <richyen3@gmail.com> writes:

When I run my update, it fails:

tii=# begin; update only "public"."m_class" set date_end='2009-09-03
05:38:24.030331-07',term_length='177 days 17:59:09.868431' where
id='2652020';
BEGIN
ERROR: new row for relation "m_class" violates check constraint
"end_within_term_length"
tii=# rollback;

Hmm, I get this:

regression=# select '2009-03-09 11:39:14.1619-07'::timestamptz + '177 days 17:59:09.868431'::interval;
?column?
-------------------------------
2009-09-03 05:38:24.030331-07
(1 row)

which is apparently exactly the same as your date_end value, but I bet
it's not quite the same after allowing for floating-point roundoff error.
If this database wasn't built with the exact-integer-timestamps option
then you can't assume that timestamp calculations are exact to the
microsecond.

regards, tom lane