http://www.postgresql.org/docs/current/static/plpgsql-trigger.html
example 36-4 has a race condition in the code that checks to see if a
row exists. It should use the code from example 36-1. This patch fixes
that. It also adds some commands to show what the summary table output
looks like. Unfortunately gamke html is bombing with some kind of
library error, so I can't verify that I didn't break the sgml.

BTW, should this have gone to -docs instead?
-- 
Jim C. Nasby, Sr. Engineering Consultant      [EMAIL PROTECTED]
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461
Index: doc/src/sgml/plpgsql.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v
retrieving revision 1.83
diff -u -r1.83 plpgsql.sgml
--- doc/src/sgml/plpgsql.sgml   29 Dec 2005 04:02:32 -0000      1.83
+++ doc/src/sgml/plpgsql.sgml   5 Jan 2006 21:36:14 -0000
@@ -3017,31 +3017,33 @@
 
         -- There might have been no row with this time_key (e.g new data!).
         IF (NOT FOUND) THEN
-            BEGIN
-                INSERT INTO sales_summary_bytime (
-                            time_key, 
-                            amount_sold, 
-                            units_sold, 
-                            amount_cost)
-                    VALUES ( 
-                            delta_time_key,
-                            delta_amount_sold,
-                            delta_units_sold,
-                            delta_amount_cost
-                           );
-            EXCEPTION
-                --
-                -- Catch race condition when two transactions are adding data
-                -- for a new time_key.
-                --
-                WHEN UNIQUE_VIOLATION THEN
-                    UPDATE sales_summary_bytime
-                        SET amount_sold = amount_sold + delta_amount_sold,
-                            units_sold = units_sold + delta_units_sold,
-                            amount_cost = amount_cost + delta_amount_cost
-                        WHERE time_key = delta_time_key;
-
-            END;
+            <<insert_update>>
+            LOOP
+                UPDATE sales_summary_bytime
+                    SET amount_sold = amount_sold + delta_amount_sold,
+                        units_sold = units_sold + delta_units_sold,
+                        amount_cost = amount_cost + delta_amount_cost
+                    WHERE time_key = delta_time_key;
+
+                EXIT insert_update WHEN found;    
+
+                BEGIN
+                    INSERT INTO sales_summary_bytime (
+                                time_key, 
+                                amount_sold, 
+                                units_sold, 
+                                amount_cost)
+                        VALUES ( 
+                                delta_time_key,
+                                delta_amount_sold,
+                                delta_units_sold,
+                                delta_amount_cost
+                               );
+                EXCEPTION
+                    WHEN UNIQUE_VIOLATION THEN
+                        -- do nothing
+                END;
+            END LOOP insert_update;
         END IF;
         RETURN NULL;
 
@@ -3051,6 +3053,16 @@
 CREATE TRIGGER maint_sales_summary_bytime
 AFTER INSERT OR UPDATE OR DELETE ON sales_fact
     FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime();
+
+INSERT INTO sales_fact VALUES(1,1,1,10,3,15);
+INSERT INTO sales_fact VALUES(1,2,1,20,5,35);
+INSERT INTO sales_fact VALUES(2,2,1,40,15,135);
+INSERT INTO sales_fact VALUES(2,3,1,10,1,13);
+SELECT * FROM sales_summary_bytime;
+DELETE FROM sales_fact WHERE product_key = 1;
+SELECT * FROM sales_summary_bytime;
+UPDATE sales_fact SET units_sold = units_sold * 2;
+SELECT * FROM sales_summary_bytime;
 </programlisting>
    </example>
 
---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
       subscribe-nomail command to [EMAIL PROTECTED] so that your
       message can get through to the mailing list cleanly

Reply via email to