Thread: confounding, incorrect constraint error
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);
> > 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
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
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
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
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
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
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