Thread: confounding, incorrect constraint error

confounding, incorrect constraint error

From
Kevin Way
Date:
I've hit some really evil nastiness that is either a Postgres 7.1.3 bug,
or signs of early-onset senility for me.  I was having trouble with my
database dying while inserting some values, and running some PL/pgSQL.

The schema is as listed below, and I'm getting 
psql:fuck.sql:175: ERROR:  ExecReplace: rejected due to CHECK constraint users_logged_in
while inserting values into the uservote table.  If I had a few columns to
the users table, postgres crashes instead of giving this (nonsensical)
error.

I'd greatly appreciate any insight, even if it involves a 2x4.

Below is a significantly simplified version of my schema, which exhibits
the above problem.

DROP RULE uservote_update_item_mod;
DROP RULE uservote_delete_item_dec;
DROP RULE uservote_insert_item_inc;

DROP RULE itemvote_update_item_mod;
DROP RULE itemvote_delete_item_dec;
DROP RULE itemvote_insert_item_inc;

DROP FUNCTION mod_node_vote_count(INT4, INT2, INT2);

DROP TABLE uservote;
DROP TABLE itemvote;

DROP TABLE item;
DROP TABLE users;
DROP TABLE node;

DROP SEQUENCE node_id_seq;

CREATE SEQUENCE node_id_seq;

CREATE TABLE node (       node_id         INT4 UNIQUE NOT NULL DEFAULT nextval('node_id_seq'),       name
TEXTNOT NULL,       nays           INT4 NOT NULL DEFAULT 0                           CHECK ( nays >= 0 ),       yays
      INT4 NOT NULL DEFAULT 0,                           CHECK ( yays >= 0 ),       rating          INT2 NOT NULL
DEFAULT50                           CHECK ( rating >= 0 AND rating <= 100 ),       PRIMARY KEY (node_id)
 
);       
CREATE TABLE users (       node_id         INT4 UNIQUE NOT NULL,email           TEXT NOT NULL,realname    TEXT NOT
NULL,pass_hash   VARCHAR(32) NOT NULL,       logged_in    INT2 NOT NULL DEFAULT 0                            CHECK
(logged_in= 0 OR logged_in = 1)
 
) INHERITS (node);

CREATE TABLE item (       node_id         INT4 UNIQUE NOT NULL,creator_id    INT4 NOT NULL
REFERENCESusers (node_id)                           ON DELETE CASCADE                           ON UPDATE CASCADE,
reason       TEXT NOT NULL
 
) INHERITS (node);    

CREATE TABLE itemvote (vote_date    TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,target_id       INT4 NOT NULL
                REFERENCES item (node_id)                            ON DELETE CASCADE                           ON
UPDATECASCADE,       user_id         INT4 NOT NULL            REFERENCES users (node_id)            ON DELETE CASCADE
             ON UPDATE CASCADE,nays        INT2 NOT NULL                           CHECK (nays = 0 OR nays = 1),
 
PRIMARY KEY (user_id, target_id)
);

CREATE TABLE uservote (vote_date    TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,target_id       INT4 NOT NULL
                REFERENCES users (node_id)                            ON DELETE CASCADE                           ON
UPDATECASCADE,       user_id         INT4 NOT NULL            REFERENCES users (node_id)            ON DELETE CASCADE
             ON UPDATE CASCADE,nays        INT2 NOT NULL                           CHECK (nays = 0 OR nays = 1),
 
PRIMARY KEY (user_id, target_id)
);

-- modifies an items nays/yays count totals as appropriate
-- first arg: item number
-- second arg: 1 or 0, nays or yays.
-- third arg: 1 or 0, add a vote, or remove a vote
CREATE FUNCTION mod_node_vote_count (INT4, INT2, INT2) RETURNS INT2 AS '   DECLARE       node_num ALIAS for $1;
nay_statusALIAS for $2;       add ALIAS for $3;
 
       nay_tot INT4 NOT NULL DEFAULT 0;       yay_tot INT4 NOT NULL DEFAULT 0;   BEGIN       IF add = 1       THEN
    IF nay_status = 1           THEN               UPDATE node SET nays = nays + 1 WHERE node_id = node_num;
ELSE              UPDATE node SET yays = yays + 1 WHERE node_id = node_num;           END IF;       ELSE           IF
nay_status= 1           THEN               UPDATE node SET nays = nays - 1 WHERE node_id = node_num;           ELSE
         UPDATE node SET yays = yays - 1 WHERE node_id = node_num;           END IF;       END IF;       SELECT nays
INTOnay_tot FROM node WHERE node_id = node_num;       SELECT yays INTO yay_tot FROM node WHERE node_id = node_num;
 
       IF nay_tot + yay_tot != 0       THEN           UPDATE node SET rating = CEIL( (yay_tot * 100)/(yay_tot +
nay_tot)) WHERE node_id = node_num;       ELSE           UPDATE node SET rating = 50 WHERE node_id = node_num;
ENDIF;
 
       RETURN 1;   END;
' LANGUAGE 'plpgsql';

------------------------------------------------------------------------
-- vote totalling rules

-- vote insertion
CREATE RULE itemvote_insert_item_inc AS   ON INSERT TO itemvote DO       SELECT mod_node_vote_count(NEW.target_id,
NEW.nays,1);
 

CREATE RULE uservote_insert_item_inc AS   ON INSERT TO uservote DO       SELECT mod_node_vote_count(NEW.target_id,
NEW.nays,1);
 

-- vote deletion
CREATE RULE itemvote_delete_item_dec AS   ON DELETE TO itemvote DO       SELECT mod_node_vote_count(OLD.target_id,
OLD.nays,0);
 

CREATE RULE uservote_delete_item_dec AS   ON DELETE TO uservote DO       SELECT mod_node_vote_count(OLD.target_id,
OLD.nays,0);
 

-- vote updates
CREATE RULE itemvote_update_item_mod AS   ON UPDATE TO itemvote WHERE OLD.nays != NEW.nays DO       (SELECT
mod_node_vote_count(OLD.target_id,OLD.nays, 1);        SELECT mod_node_vote_count(NEW.target_id, NEW.nays, 0););
 

CREATE RULE uservote_update_item_mod AS   ON UPDATE TO uservote WHERE OLD.nays != NEW.nays DO       (SELECT
mod_node_vote_count(OLD.target_id,OLD.nays, 1);        SELECT mod_node_vote_count(NEW.target_id, NEW.nays, 0););
 

-- users
INSERT INTO users (name, pass_hash, realname, email) VALUES ('mosch', 'dafe001b7733b0f3236aa95e00f8ed88', 'Kevin',
'monica@whitehouse.gov');
INSERT INTO users (name,  pass_hash, realname, email) VALUES ('Wakko', 'c6ef90fcf92bf703c3cc79a679c192a3', 'Alex',
'wakko@bitey.net');

-- items
INSERT INTO item (name, creator_id, reason) VALUES ('slashdot.org', 2, 'Because it\'s a pile of turd.');
INSERT INTO item (name, creator_id, reason) VALUES ('Yahoo!', 2, 'Because it\'s ugly.');
INSERT INTO item (name, creator_id, reason) VALUES ('memepool', 1, 'Because it\'s phat phat phat phat phat.');
INSERT INTO item (name, creator_id, reason) VALUES ('blow!!??!!', 1, 'this record nays nays nays');

-- item votes
INSERT INTO itemvote (target_id, user_id, nays) VALUES (3, 1, 1);
INSERT INTO itemvote (target_id, user_id, nays) VALUES (4, 1, 0);
INSERT INTO itemvote (target_id, user_id, nays) VALUES (5, 2, 1);

-- user votes
INSERT INTO uservote (target_id, user_id, nays) VALUES (2, 1, 0);
INSERT INTO uservote (target_id, user_id, nays) VALUES (1, 2, 1);


Re: confounding, incorrect constraint error

From
Kevin Way
Date:
> > Below is a significantly simplified version of my schema, which
> > exhibits
> > the above problem.
>
> Unfortunately, even a simplified version of your schema would take me
> some hours to understand.  As your rule-setting is quite complex, my
> first instinct would be to hunt for circular procedural logic in your
> rules.  Try to pursue, step by step, everything that happens from the
> moment you send the insert command to uservotes.  You may find that the
> logic cascades back to the beginning.  I've done this to myself on
> occasion, causing the DB to hang on a seemingly simple request.

I'm fairly certain that there's no circular procedural logic.

The errors can be turned on/off by turning on/off the uservote_ series
of rules, which are attached to the uservote table.  These rules call
mod_node_vote_count which only touches the node table.  There are no
rules or triggers associated with the node table, so there is no circular
logic there.

Additional strangeness is that the itemvote_ series of rules works perfectly
despite the fact that the only difference between uservote_ and itemvote_
rules is the table that triggers them, they both call the same procedure on
the nodes table.

My current thinking is that something is stomping on some memory, because
you can vary the effect of the error from being an incorrectly failed CHECK
constraint, to crashing the database, by varying the number of columns in
the tables in question.

I'm unemployed at the moment and this is a pet project, so I can't offer
much in the way of financial compensation, but I'll start the bidding at
$50 donation in your name to your choice of the EFF, the Red Cross, or the
American Cancer Society, in return for a fix.  (If none of these charities
are acceptable, surely one can be found later that is acceptable to both
parties).

Again, I greatly appreciate any help, and I apologize that my test case is
still fairly sizeable, despite being about 10% the size of the original
code.

-Kevin Way

Re: confounding, incorrect constraint error

From
Jan Wieck
Date:
Kevin Way wrote:
> I'm unemployed at the moment and this is a pet project, so I can't offer
> much in the way of financial compensation, but I'll start the bidding at
> $50 donation in your name to your choice of the EFF, the Red Cross, or the
> American Cancer Society, in return for a fix.  (If none of these charities
> are acceptable, surely one can be found later that is acceptable to both
> parties).
   Sorry,  I missed the original post of the problem. If you can   send it to me again and change your offer into
donatingblood   at the Red Cross, I would take a look at it.
 


Jan

--

#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #



_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com



CHECK problem really OK now...

From
Kovacs Baldvin
Date:
Hi everybody!

I tried, and it works: the current CVS version really runs
happily the query what sent to heaven our 7.1 version of the
backend.

Kevin: your original complex schema also runs smoothly.

Thanks for our mindful developers!

Regards,
Baldvin

I think Jan wrote:
>     Sorry,  I missed the original post of the problem. If you can
>     send it to me again and change your offer into donating blood
>     at the Red Cross, I would take a look at it.

Probably the chances for a prize went... :-(( However, is there
still a shortage of blod???

Baldvin




Re: CHECK problem really OK now...

From
"Josh Berkus"
Date:
Baldvin,

> Probably the chances for a prize went... :-(( However, is there
> still a shortage of blod???

Last I checked, the American Red Cross does not want your blood right
now -- they want it two weeks from now.  Currently blood stores are
full, but they get depleted pretty fast.  Of course, what they really
want is for you to make a commitment to donate twice a year, every year.

-Josh

______AGLIO DATABASE SOLUTIONS___________________________                                      Josh Berkus Complete
informationtechnology      josh@agliodbs.com  and data management solutions       (415) 565-7293 for law firms, small
businesses       fax 621-2533   and non-profit organizations.      San Francisco
 


Re: CHECK problem really OK now...

From
Jan Wieck
Date:
Kovacs Baldvin wrote:
> Hi everybody!
>
> I tried, and it works: the current CVS version really runs
> happily the query what sent to heaven our 7.1 version of the
> backend.
>
> Kevin: your original complex schema also runs smoothly.
>
> Thanks for our mindful developers!
>
> Regards,
> Baldvin
>
> I think Jan wrote:
> >     Sorry,  I missed the original post of the problem. If you can
> >     send it to me again and change your offer into donating blood
> >     at the Red Cross, I would take a look at it.
>
> Probably the chances for a prize went... :-(( However, is there
> still a shortage of blod???
   Well, for the NY disaster they probably have more than enough   - not that many injured people there - sad enough
though.But   what's wrong with using the current wave of patriotism to get   as much as they can get?
 
   It help's saving life! Using the  victims  for  that  purpose   isn't  abuse.   It  is  turning grief, anger and
sadnessinto   help and hope.
 
   Let blood become "Open Source". Give it for free  and  you'll   get plenty of it when you need some.


Jan

--

#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #



_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com



Re: CHECK problem really OK now...

From
Roberto Mello
Date:
On Mon, Sep 24, 2001 at 03:23:13PM -0400, Jan Wieck wrote:
> 
>     It help's saving life! Using the  victims  for  that  purpose
>     isn't  abuse.   It  is  turning grief, anger and sadness into
>     help and hope.
> 
>     Let blood become "Open Source". Give it for free  and  you'll
>     get plenty of it when you need some.
I couldn't agree more!
-Roberto
-- 
+------------| Roberto Mello - http://www.brasileiro.net |------------+
Computer Science, Utah State University  -    http://www.usu.edu
USU Free Software & GNU/Linux Club       -    http://fslc.usu.edu
Space Dynamics Lab, Developer            -    http://www.sdl.usu.edu
OpenACS - Enterprise free web toolkit    -    http://openacs.org
TAFB -> Text Above Fullquote Below 


Re: CHECK problem really OK now...

From
Tom Lane
Date:
Kovacs Baldvin <kb136@hszk.bme.hu> writes:
> I tried, and it works: the current CVS version really runs
> happily the query what sent to heaven our 7.1 version of the
> backend.

I believe this traces to a fix I made in May:

2001-05-27 16:48  tgl
* src/: backend/executor/execJunk.c, backend/executor/execMain.c,include/executor/executor.h,
include/nodes/execnodes.h:When usinga junkfilter, the output tuple should NOT be stored back into thesame tuple slot
thatthe raw tuple came from, because that slot hasthe wrong tuple descriptor.  Store it into its own slot with
thecorrectdescriptor, instead.  This repairs problems with SPIfunctions seeing inappropriate tuple descriptors --- for
example,plpgsqlcode failing to cope with SELECT FOR UPDATE.
 

I didn't realize at the time that the error would also affect updates of
child tables, but tracing through your example with 7.1 shows clearly
that the CHECK is being applied to a slot that contains a four-column
tuple and only a three-column descriptor.  Ooops.
        regards, tom lane