diff options
-rw-r--r-- | doc/src/sgml/func.sgml | 19 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 185 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 4 | ||||
-rw-r--r-- | src/include/utils/builtins.h | 3 |
4 files changed, 203 insertions, 8 deletions
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 256b0fa3fae..27966276d0e 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.144 2003/03/20 03:34:55 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.145 2003/03/20 18:58:02 momjian Exp $ PostgreSQL documentation --> @@ -6796,6 +6796,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); </indexterm> <indexterm zone="functions-misc"> + <primary>pg_get_triggerdef</primary> + </indexterm> + + <indexterm zone="functions-misc"> <primary>pg_get_constraintdef</primary> </indexterm> @@ -6808,13 +6812,13 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); extract information from the system catalogs. <function>pg_get_viewdef</function>, <function>pg_get_ruledef</function>, - <function>pg_get_indexdef</function>, and + <function>pg_get_indexdef()</function>, + <function>pg_get_triggerdef()</function>, and <function>pg_get_constraintdef</function> respectively reconstruct the creating command for a view, rule, index, or constraint. (Note that this is a decompiled reconstruction, not - the verbatim text of the command.) At present - <function>pg_get_constraintdef</function> only works for - foreign-key constraints. <function>pg_get_userbyid</function> + the verbatim text of the command.) + <function>pg_get_userbyid</function> extracts a user's name given a user ID number. </para> @@ -6847,6 +6851,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); <entry>get <command>CREATE INDEX</> command for index</entry> </row> <row> + <entry><function>pg_get_triggerdef</function>(<parameter>triggerOID</parameter>)</entry> + <entry><type>text</type></entry> + <entry>Get <command>CREATE [ CONSTRAINT ] TRIGGER</> command for trigger</entry> + </row> + <row> <entry><literal><function>pg_get_constraintdef</function>(<parameter>constraint_oid</parameter>)</literal></entry> <entry><type>text</type></entry> <entry>get definition of a constraint</entry> diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index dfed27f89da..9b34544a387 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * back to source text * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.136 2003/02/16 02:30:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.137 2003/03/20 18:58:02 momjian Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -49,6 +49,7 @@ #include "catalog/pg_cast.h" #include "catalog/pg_constraint.h" #include "catalog/pg_index.h" +#include "catalog/pg_trigger.h" #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" #include "catalog/pg_shadow.h" @@ -369,6 +370,188 @@ pg_do_getviewdef(Oid viewoid) return ruledef; } +/* ---------- + * get_triggerdef - Get the definition of a trigger + * ---------- + */ +Datum +pg_get_triggerdef(PG_FUNCTION_ARGS) +{ + Oid trigid = PG_GETARG_OID(0); + text *trigdef; + HeapTuple ht_trig; + HeapTuple ht_proc; + Form_pg_trigger trigrec; + int len; + StringInfoData buf; + Relation tgrel; + ScanKeyData skey[1]; + SysScanDesc tgscan; + int findx = 0; + const char *tgargs; + const char *p; + char *tgfname; + char *tgname; + + /* + * Fetch the pg_trigger tuple by the Oid of the trigger + */ + tgrel = heap_openr(TriggerRelationName, AccessShareLock); + + /* + * Find the trigger + */ + ScanKeyEntryInitialize(&skey[0], 0x0, + ObjectIdAttributeNumber, F_OIDEQ, + ObjectIdGetDatum(trigid)); + + tgscan = systable_beginscan(tgrel, TriggerOidIndex, true, + SnapshotNow, 1, skey); + + ht_trig = systable_getnext(tgscan); + + if (!HeapTupleIsValid(ht_trig)) + elog(ERROR, "pg_get_triggerdef: there is no trigger with oid %u", + trigid); + + trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig); + systable_endscan(tgscan); + + /* + * Fetch the pg_proc tuple of the trigger's function + */ + ht_proc = SearchSysCache(PROCOID, + ObjectIdGetDatum(trigrec->tgfoid), + 0, 0, 0); + if (!HeapTupleIsValid(ht_proc)) + elog(ERROR, "syscache lookup for function %u failed", trigrec->tgfoid); + + tgfname = NameStr(((Form_pg_proc) GETSTRUCT(ht_proc))->proname); + + /* + * Start the trigger definition. Note that the trigger's name should + * never be schema-qualified, but the trigger rel's name may be. + */ + initStringInfo(&buf); + + tgname = NameStr(trigrec->tgname); + appendStringInfo(&buf, "CREATE %sTRIGGER %s ", + trigrec->tgisconstraint ? "CONSTRAINT " : "", + quote_identifier(tgname)); + + if (TRIGGER_FOR_BEFORE(trigrec->tgtype)) + appendStringInfo(&buf, "BEFORE"); + else + appendStringInfo(&buf, "AFTER"); + if (TRIGGER_FOR_INSERT(trigrec->tgtype)) + { + appendStringInfo(&buf, " INSERT"); + findx++; + } + if (TRIGGER_FOR_DELETE(trigrec->tgtype)) + { + if (findx > 0) + appendStringInfo(&buf, " OR DELETE"); + else + appendStringInfo(&buf, " DELETE"); + findx++; + } + if (TRIGGER_FOR_UPDATE(trigrec->tgtype)) + { + if (findx > 0) + appendStringInfo(&buf, " OR UPDATE"); + else + appendStringInfo(&buf, " UPDATE"); + } + appendStringInfo(&buf, " ON %s ", + generate_relation_name(trigrec->tgrelid)); + + + if (trigrec->tgisconstraint) + { + if (trigrec->tgconstrrelid != 0) + { + appendStringInfo(&buf, "FROM %s ", + generate_relation_name(trigrec->tgconstrrelid)); + } + if (!trigrec->tgdeferrable) + appendStringInfo(&buf, "NOT "); + appendStringInfo(&buf, "DEFERRABLE INITIALLY "); + if (trigrec->tginitdeferred) + appendStringInfo(&buf, "DEFERRED "); + else + appendStringInfo(&buf, "IMMEDIATE "); + + } + + if (TRIGGER_FOR_ROW(trigrec->tgtype)) + appendStringInfo(&buf, "FOR EACH ROW "); + else + appendStringInfo(&buf, "FOR EACH STATEMENT "); + + appendStringInfo(&buf, "EXECUTE PROCEDURE %s(", + quote_identifier(tgfname)); + + /* Get args string */ + tgargs = DatumGetCString(DirectFunctionCall1(byteaout, + PointerGetDatum(&trigrec->tgargs))); + /* If it's NULL, fail */ + if (tgargs == NULL) + elog(ERROR, "pg_get_triggerdef: tgargs is NULL"); + + for (findx = 0; findx < trigrec->tgnargs; findx++) + { + const char *s; + + for (p = tgargs;;) + { + p = strchr(p, '\\'); + if (p == NULL) + { + elog(ERROR, "pg_get_triggerdef: bad argument string for trigger"); + } + p++; + if (*p == '\\') + { + p++; + continue; + } + if (p[0] == '0' && p[1] == '0' && p[2] == '0') + break; + } + p--; + appendStringInfoChar(&buf, '\''); + for (s = tgargs; s < p;) + { + /* If character is an apostrophe, escape it */ + if (*s == '\'') + appendStringInfoChar(&buf, '\\'); + appendStringInfoChar(&buf, *s++); + } + appendStringInfoChar(&buf, '\''); + appendStringInfo(&buf, (findx < trigrec->tgnargs - 1) ? ", " : ""); + tgargs = p + 4; + } + + /* Deliberately omit semi-colon */ + appendStringInfo(&buf, ")"); + + /* + * Create the result as a TEXT datum, and free working data + */ + len = buf.len + VARHDRSZ; + trigdef = (text *) palloc(len); + VARATT_SIZEP(trigdef) = len; + memcpy(VARDATA(trigdef), buf.data, buf.len); + + pfree(buf.data); + + ReleaseSysCache(ht_trig); + ReleaseSysCache(ht_proc); + heap_close(tgrel, AccessShareLock); + + PG_RETURN_TEXT_P(trigdef); +} /* ---------- * get_indexdef - Get the definition of an index diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 0938ba0b476..835d6f2b5bb 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.288 2003/03/20 03:34:56 momjian Exp $ + * $Id: pg_proc.h,v 1.289 2003/03/20 18:58:02 momjian Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2194,6 +2194,8 @@ DATA(insert OID = 1642 ( pg_get_userbyid PGNSP PGUID 12 f f t f s 1 19 "23" DESCR("user name by UID (with fallback)"); DATA(insert OID = 1643 ( pg_get_indexdef PGNSP PGUID 12 f f t f s 1 25 "26" pg_get_indexdef - _null_ )); DESCR("index description"); +DATA(insert OID = 1662 ( pg_get_triggerdef PGNSP PGUID 12 f f t f s 1 25 "26" pg_get_triggerdef - _null_ )); +DESCR("trigger description"); DATA(insert OID = 1387 ( pg_get_constraintdef PGNSP PGUID 12 f f t f s 1 25 "26" pg_get_constraintdef - _null_ )); DESCR("constraint description"); DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 f f t f s 2 25 "25 26" pg_get_expr - _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index e956f54fef6..3a2b20eacbd 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.208 2003/02/13 05:24:04 momjian Exp $ + * $Id: builtins.h,v 1.209 2003/03/20 18:58:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -399,6 +399,7 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS); extern Datum pg_get_indexdef(PG_FUNCTION_ARGS); +extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS); extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS); extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); extern Datum pg_get_expr(PG_FUNCTION_ARGS); |