473,386 Members | 1,693 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

history tables with only one function?

Hi,

I'm looking at the logging of a database we'll put in production soon.
I've seen some posts on this list about history tables, like mentioned in http://www-106.ibm.com/developerwork...a-dbdsgn2.html .
I think I'll go that way too, but I still have some questions on the approach, and would appreciate any advice on it.

Here are some questions I have:

- is it possible to write only one function used for all logging triggers? As illustrated in http://www.varlena.com/varlena/GeneralBits/57.php , it is possible to use
one function for tracking last update times for all tables:

CREATE OR REPLACE FUNCTION setmodtime() RETURNS TRIGGER AS '
BEGIN
NEW.modified_timestamp = now();
RETURN NEW;
END
' LANGUAGE 'plpgsql';

Is it possible to create only one function to insert rows in the corresponding history table? The name of the history table can be constructed from the original table.
and I guess all fields of the table can be retrieved from the db's metadata. Would that be feasible, and more importantly, would it be usable?
-Another question I have is for those who use this approach: How often o you have to flush those history tables
and when you flush the tables, where do you put the flushed data? In another database on another server or on tape?

-Would it be possible to use the replication of Slony-I and only log in the history tables in the slave database? Or is
somthing similar possible?

Thanks.

Raph

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

Nov 23 '05 #1
5 2670
Raphael Bauduin wrote:

Hi,

I'm looking at the logging of a database we'll put in production soon.
I've seen some posts on this list about history tables, like mentioned
in http://www-106.ibm.com/developerwork...a-dbdsgn2.html .
I think I'll go that way too, but I still have some questions on the
approach, and would appreciate any advice on it.

Here are some questions I have:

- is it possible to write only one function used for all logging
triggers? As illustrated in
http://www.varlena.com/varlena/GeneralBits/57.php , it is possible to use
one function for tracking last update times for all tables:

CREATE OR REPLACE FUNCTION setmodtime() RETURNS TRIGGER AS '
BEGIN
NEW.modified_timestamp = now();
RETURN NEW;
END
' LANGUAGE 'plpgsql';

Is it possible to create only one function to insert rows in the
corresponding history table? The name of the history table can be
constructed from the original table.
and I guess all fields of the table can be retrieved from the db's
metadata. Would that be feasible, and more importantly, would it be usable?

I found a solution to this one, thanks to a post of Tom Lane on the postgres-novice mailing list:

CREATE FUNCTION "update_log"(text) RETURNS trigger AS '
BEGIN
insert into $1_log select new.*,''UPDATE'';
return new;
END;
' LANGUAGE 'plpgsql';

I can then create a trigger and pass the table name as argument (does the function know
which table fired the trigger?):

CREATE TRIGGER "customers_update_log_t" after UPDATE on "customers" for each row execute procedure "customers_update_log"('customers');

This creates entries in the customers_log table each time I update a customer.

I'll see if I use the same function for the creation log or not. For the delete log, I'll have to use another function anyway,
as new is not defined for a deletion IIRC.

Still interested in tips on this technique ;-)

Raph

-Another question I have is for those who use this approach: How often o
you have to flush those history tables
and when you flush the tables, where do you put the flushed data? In
another database on another server or on tape?

-Would it be possible to use the replication of Slony-I and only log in
the history tables in the slave database? Or is
somthing similar possible?
Thanks.

Raph
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to ma*******@postgresql.org so that your
message can get through to the mailing list cleanly

Nov 23 '05 #2
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

Raphael Bauduin wrote:
Raphael Bauduin wrote:

Hi,

I'm looking at the logging of a database we'll put in production soon.
I've seen some posts on this list about history tables, like mentioned
in http://www-106.ibm.com/developerwork...a-dbdsgn2.html .
I think I'll go that way too, but I still have some questions on the
approach, and would appreciate any advice on it.

Here are some questions I have:

- is it possible to write only one function used for all logging
triggers? As illustrated in
http://www.varlena.com/varlena/GeneralBits/57.php , it is possible to use
one function for tracking last update times for all tables:

CREATE OR REPLACE FUNCTION setmodtime() RETURNS TRIGGER AS '
BEGIN
NEW.modified_timestamp = now();
RETURN NEW;
END
' LANGUAGE 'plpgsql';

Is it possible to create only one function to insert rows in the
corresponding history table? The name of the history table can be
constructed from the original table.
and I guess all fields of the table can be retrieved from the db's
metadata. Would that be feasible, and more importantly, would it be
usable?


I found a solution to this one, thanks to a post of Tom Lane on the
postgres-novice mailing list:

CREATE FUNCTION "update_log"(text) RETURNS trigger AS '
BEGIN
insert into $1_log select new.*,''UPDATE'';
return new;
END;
' LANGUAGE 'plpgsql';

I can then create a trigger and pass the table name as argument (does
the function know
which table fired the trigger?):

CREATE TRIGGER "customers_update_log_t" after UPDATE on "customers" for
each row execute procedure "customers_update_log"('customers');

This creates entries in the customers_log table each time I update a
customer.

And this construct indeed works? I'm stunned!
Which PostgreSQL version is this?

As far as I know your function should have the following problems:

*) Trigger functions can not be declared with arguments in the
CREATE FUNCTION statement. They can have arguments when they
are used in the CREATE TRIGGER statement, but trigger functions
have to read the values of their arguments from the array TG_ARGV[]

*) You can not use variables as a placeholder for table- or column-
names in SQL statements. You would have to create the SQL statement
dynamically and execute it in your function with EXECUTE

IMHO this is true at least for PostgreSQL 7.4

See the thread "Trigger functions with dynamic SQL" on pgsql-sql
around July 24th where I described my problems with dynamically
created SQL statements. Finally I got around all the hassels with
quotation marks and my trigger functions work as expected.

Could you please confirm that your function works as you described?
I tried with similar functions and the failed with syntax errors,
so I had to use dynamically created SQL statements.

- - andreas

- --
Andreas Haumer | mailto:an*****@xss.co.at
*x Software + Systeme | http://www.xss.co.at/
Karmarschgasse 51/2/20 | Tel: +43-1-6060114-0
A-1100 Vienna, Austria | Fax: +43-1-6060114-71
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFBGdE4xJmyeGcXPhERAsbZAJ4rS3E8ng3D/Hx/ywsxKM5CVjRd3ACfcdwi
Dt5vUZsSVPbjDfjTMte/MzY=
=RAJ4
-----END PGP SIGNATURE-----
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faqs/FAQ.html

Nov 23 '05 #3
Andreas Haumer wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

Raphael Bauduin wrote:
Raphael Bauduin wrote:

Hi,

I'm looking at the logging of a database we'll put in production soon.
I've seen some posts on this list about history tables, like mentioned
in http://www-106.ibm.com/developerwork...a-dbdsgn2.html .
I think I'll go that way too, but I still have some questions on the
approach, and would appreciate any advice on it.

Here are some questions I have:

- is it possible to write only one function used for all logging
triggers? As illustrated in
http://www.varlena.com/varlena/GeneralBits/57.php , it is possible to use
one function for tracking last update times for all tables:

CREATE OR REPLACE FUNCTION setmodtime() RETURNS TRIGGER AS '
BEGIN
NEW.modified_timestamp = now();
RETURN NEW;
END
' LANGUAGE 'plpgsql';

Is it possible to create only one function to insert rows in the
corresponding history table? The name of the history table can be
constructed from the original table.
and I guess all fields of the table can be retrieved from the db's
metadata. Would that be feasible, and more importantly, would it be
usable?

I found a solution to this one, thanks to a post of Tom Lane on the
postgres-novice mailing list:

CREATE FUNCTION "update_log"(text) RETURNS trigger AS '
BEGIN
insert into $1_log select new.*,''UPDATE'';
return new;
END;
' LANGUAGE 'plpgsql';

I can then create a trigger and pass the table name as argument (does
the function know
which table fired the trigger?):

CREATE TRIGGER "customers_update_log_t" after UPDATE on "customers" for
each row execute procedure "customers_update_log"('customers');

This creates entries in the customers_log table each time I update a
customer.


And this construct indeed works? I'm stunned!
Which PostgreSQL version is this?

As far as I know your function should have the following problems:

*) Trigger functions can not be declared with arguments in the
CREATE FUNCTION statement. They can have arguments when they
are used in the CREATE TRIGGER statement, but trigger functions
have to read the values of their arguments from the array TG_ARGV[]

*) You can not use variables as a placeholder for table- or column-
names in SQL statements. You would have to create the SQL statement
dynamically and execute it in your function with EXECUTE

IMHO this is true at least for PostgreSQL 7.4

See the thread "Trigger functions with dynamic SQL" on pgsql-sql
around July 24th where I described my problems with dynamically
created SQL statements. Finally I got around all the hassels with
quotation marks and my trigger functions work as expected.

Could you please confirm that your function works as you described?

It works as expected:
log=# DROP TRIGGER "customers_update_log_t" on "customers";
DROP TRIGGER
log=# DROP FUNCTION "update_log"();
ERROR: function update_log() does not exist
log=# CREATE FUNCTION "update_log"(text) RETURNS trigger AS '
log'# BEGIN
log'# insert into $1_log select new.*,''UPDATE'';
log'# return new;
log'# END;
log'# ' LANGUAGE 'plpgsql';
CREATE FUNCTION
log=#
log=# CREATE TRIGGER "customers_update_log_t" after UPDATE on "customers" for each row execute procedure "customers_update_log"('customers');
CREATE TRIGGER
log=# select count(*) from customers_log;
count
-------
18
(1 row)

log=# update customers set name='EDITED AND LOOGED GENERIC FUNCTION NEW' where customer_id=20003;
UPDATE 1
log=# select count(*) from customers_log;
count
-------
19
(1 row)

And the row added to customers_log is absolutely correct. version is 7.4.3 (debian package)

Raph

PS: I also have a problem of quoting in a trigger (as you seem to have had from the pgsql-sql thread you refered to).
I want this to be executed:
EXECUTE ''insert into ''|| TG_RELNAME||''_log select ''||new.*||'',''||TG_OP;
but I get this output:
NOTICE: table = customers
NOTICE: operation = UPDATE
ERROR: NEW used in query that is not in a rule
CONTEXT: PL/pgSQL function "activity_log" line 4 at execute statement

I posted a message to pgsql-novice, but maybe you can help me forward also?
Thanks.

I tried with similar functions and the failed with syntax errors,
so I had to use dynamically created SQL statements.

- - andreas

- --
Andreas Haumer | mailto:an*****@xss.co.at
*x Software + Systeme | http://www.xss.co.at/
Karmarschgasse 51/2/20 | Tel: +43-1-6060114-0
A-1100 Vienna, Austria | Fax: +43-1-6060114-71
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFBGdE4xJmyeGcXPhERAsbZAJ4rS3E8ng3D/Hx/ywsxKM5CVjRd3ACfcdwi
Dt5vUZsSVPbjDfjTMte/MzY=
=RAJ4
-----END PGP SIGNATURE-----

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Nov 23 '05 #4
Raphael Bauduin <ra*************@be.easynet.net> writes:
Could you please confirm that your function works as you described?
It works as expected: log=# DROP TRIGGER "customers_update_log_t" on "customers";
DROP TRIGGER
log=# DROP FUNCTION "update_log"();
ERROR: function update_log() does not exist
log=# CREATE FUNCTION "update_log"(text) RETURNS trigger AS '
log'# BEGIN
log'# insert into $1_log select new.*,''UPDATE'';
log'# return new;
log'# END;
log'# ' LANGUAGE 'plpgsql';
CREATE FUNCTION
log=#
log=# CREATE TRIGGER "customers_update_log_t" after UPDATE on "customers" for each row execute procedure "customers_update_log"('customers');
CREATE TRIGGER


That trigger is not executing that function, and would not be executing
it even if you had used the same function name. Trigger functions are
always parameterless.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

Nov 23 '05 #5
Tom Lane wrote:
Raphael Bauduin <ra*************@be.easynet.net> writes:
Could you please confirm that your function works as you described?

It works as expected:


log=# DROP TRIGGER "customers_update_log_t" on "customers";
DROP TRIGGER
log=# DROP FUNCTION "update_log"();
ERROR: function update_log() does not exist
log=# CREATE FUNCTION "update_log"(text) RETURNS trigger AS '
log'# BEGIN
log'# insert into $1_log select new.*,''UPDATE'';
log'# return new;
log'# END;
log'# ' LANGUAGE 'plpgsql';
CREATE FUNCTION
log=#
log=# CREATE TRIGGER "customers_update_log_t" after UPDATE on "customers" for each row execute procedure "customers_update_log"('customers');
CREATE TRIGGER

That trigger is not executing that function, and would not be executing
it even if you had used the same function name. Trigger functions are
always parameterless.


I tested it again and it worked, but the fact you were as categoric made me start from scratch, and you are absolutely right.
As you can even see in the code above, the trigger uses "customers_update_log"('customers') but I define the function "update_log"().....
There was a parameterless function customers_update_log I had defined in previous tests which hadn't been dropped.... And that
was the function used by the trigger, even if I passed a parameter. The fact that it worked made me think it used the parameter.

Thanks for the clarification!

Raph

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
joining column's datatypes do not match

Nov 23 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Ron Nolan | last post by:
I have a large application that contains lots and lots of financial history data. The history data is currently set up in a table called 'TblHist' that exists inside each of these three .mdb...
7
by: RLN | last post by:
Re: Access 2000 I have three history tables. Each table contains 3 years worth of data. All three tables have a date field in them (and autonum field). Each table has the potential to contain...
1
by: Gomez | last post by:
I have set up two tables ****current and ****history. The history table contains all the fields which I want to track changes on. The current table contains just the most recent information from...
3
by: Rafael Tejera | last post by:
I would like to create an history module to my application.. I need some advice to use a duplicate database with who, when and where fields added to that new duplicate table, or create a table...
0
by: ummaria | last post by:
Hello, I have posted a question related to this problem before but I never got the full understanding of the concept. I would really appreciate if someone could help me, my deadline for the design...
0
by: Nyh | last post by:
I tried to explain the best I can but it is very difficult to do. Here it goes. I have three history tables. Teacher, student and school. School and teacher, and school and student are linked...
10
Ajm113
by: Ajm113 | last post by:
Making a History Page for BIG Sites Intro: Ok, let's say after a while your website has grown massive. We're talking search engine, forum and video hosting -- you've got a LOT of content. And you...
1
by: Neil | last post by:
When creating history tables that are appended to whenever a record is updated, should one append the corresponding child table records to their history tables at the same time (so as to have a...
3
by: thechazm | last post by:
Hello Everyone again, I have hit a brick wall and was wondering if someone could shed some light on my problem. So what I am trying to do is to create a table that stores a weekly snapshot of...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.