X-Original-To: pgsql-sql-postgresql.org@postgresql.org Received: from localhost (wm.hub.org [200.46.204.128]) by postgresql.org (Postfix) with ESMTP id 40F339FB2EB for ; Fri, 11 Aug 2006 15:41:03 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.128]) (amavisd-new, port 10024) with ESMTP id 77002-06 for ; Fri, 11 Aug 2006 18:41:00 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey- Received: from nf-out-0910.google.com (nf-out-0910.google.com [64.233.182.186]) by postgresql.org (Postfix) with ESMTP id D157C9FB1E7 for ; Fri, 11 Aug 2006 15:40:59 -0300 (ADT) Received: by nf-out-0910.google.com with SMTP id n28so1129297nfc for ; Fri, 11 Aug 2006 11:40:58 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=YtcIwkflea2eZ5lt7u5L8XQdSgl47fil2uGtFvnBdtMk8Kqhc8dV8maQ1JGYRC6InP/EjU0c6T3wEs/fIWaIIJE7GZedHVT4akmJQKWColbtdUdUmVB98iwxgp+391eX846idmeZEcwvaj4cuVGI/r+Q3lZx2aYB8LulTevFHkg= Received: by 10.78.107.8 with SMTP id f8mr2291994huc; Fri, 11 Aug 2006 11:40:58 -0700 (PDT) Received: by 10.78.153.9 with HTTP; Fri, 11 Aug 2006 11:40:58 -0700 (PDT) Message-ID: <5a0a9d6f0608111140u1034ffabgf25b94922c7fd601@mail.gmail.com> Date: Fri, 11 Aug 2006 14:40:58 -0400 From: "Andrew Hammond" To: "Aaron Bono" , pgsql-sql@postgresql.org Subject: Re: timestamp (MS SQLServer's rowversion) functionality In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <1155216510.452118.282090@h48g2000cwc.googlegroups.com> X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0.199 tagged_above=0 required=5 tests=DNS_FROM_RFC_ABUSE, SPF_PASS, UPPERCASE_25_50 X-Spam-Level: X-Archive-Number: 200608/89 X-Sequence-Number: 26047 On 8/11/06, Aaron Bono wrote: > I put a create_dt and modify_dt column on every table and set the default to > now(). Then I use this trigger: > > CREATE OR REPLACE FUNCTION "public"."modify_date_stamp_fn" () RETURNS SETOF > opaque AS > ' > BEGIN > -- if a trigger insert or update operation occurs > IF TG_OP = ''INSERT'' OR TG_OP = ''UPDATE'' THEN > -- assigns the current timestamp > -- into the mod_time column > NEW.modify_dt := now(); > > -- displays the new row on an insert/update > RETURN NEW; > END IF; > END; > ' > LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER; > > CREATE TRIGGER "mytable_modify_dt_tr" BEFORE UPDATE > ON "public"."mytable" FOR EACH ROW > EXECUTE PROCEDURE "public"."modify_date_stamp_fn"(); That's pretty close. Couple of things though. 0) Dollar quoting is readability++ so you might as well get in the habit. 1) Your trigger function should properly return trigger rather than SETOF opaque (but that's a pretty cute hack, I gotta admit). 2) While you're at it, you probably want to enforce the immutability of create_dt on updates. This requires an AFTER trigger. 3) If you're not going to call the function from anything but the insert/update, there's no reason to check if it's and insert or update (unless you want to be paranoid). You're not currently calling it for inserts, but we can change that. 4) This function is properly a security a definer. Not a big deal until (and if) someone decides to implement column level privs. 5) See http://www.postgresql.org/docs/current/static/plpgsql-trigger.html for further documentation. CREATE OR REPLACE FUNCTION "public"."modify_date_stamp_fn" () RETURNS trigger AS $modify_date_stamp$ BEGIN IF TG_OP = ''INSERT'' THEN NEW.create_dt := now(); ELSE IF NEW.create_dt <> OLD.create_dt THEN RAISE EXCEPTION 'Not allowed to change create_dt. Bad programmer!!!'; END IF; -- no changes allowed END IF; NEW.modify_dt := now(); -- always stamp updates RETURN NEW; END; $modify_date_stamp$ LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY DEFINER; CREATE TRIGGER "mytable_modify_dt_tr" AFTER INSERT OR UPDATE ON "public"."mytable" FOR EACH ROW EXECUTE PROCEDURE "public"."modify_date_stamp_fn"(); Drew