|
3 | 3 | *back to source text
|
4 | 4 | *
|
5 | 5 | * IDENTIFICATION
|
6 |
| - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.136 2003/02/16 02:30:39 tgl Exp $ |
| 6 | + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.137 2003/03/20 18:58:02 momjian Exp $ |
7 | 7 | *
|
8 | 8 | * This software is copyrighted by Jan Wieck - Hamburg.
|
9 | 9 | *
|
|
49 | 49 | #include"catalog/pg_cast.h"
|
50 | 50 | #include"catalog/pg_constraint.h"
|
51 | 51 | #include"catalog/pg_index.h"
|
| 52 | +#include"catalog/pg_trigger.h" |
52 | 53 | #include"catalog/pg_opclass.h"
|
53 | 54 | #include"catalog/pg_operator.h"
|
54 | 55 | #include"catalog/pg_shadow.h"
|
@@ -369,6 +370,188 @@ pg_do_getviewdef(Oid viewoid)
|
369 | 370 | returnruledef;
|
370 | 371 | }
|
371 | 372 |
|
| 373 | +/* ---------- |
| 374 | + * get_triggerdef- Get the definition of a trigger |
| 375 | + * ---------- |
| 376 | + */ |
| 377 | +Datum |
| 378 | +pg_get_triggerdef(PG_FUNCTION_ARGS) |
| 379 | +{ |
| 380 | +Oidtrigid=PG_GETARG_OID(0); |
| 381 | +text*trigdef; |
| 382 | +HeapTupleht_trig; |
| 383 | +HeapTupleht_proc; |
| 384 | +Form_pg_triggertrigrec; |
| 385 | +intlen; |
| 386 | +StringInfoDatabuf; |
| 387 | +Relationtgrel; |
| 388 | +ScanKeyDataskey[1]; |
| 389 | +SysScanDesctgscan; |
| 390 | +intfindx=0; |
| 391 | +constchar*tgargs; |
| 392 | +constchar*p; |
| 393 | +char*tgfname; |
| 394 | +char*tgname; |
| 395 | + |
| 396 | +/* |
| 397 | + * Fetch the pg_trigger tuple by the Oid of the trigger |
| 398 | + */ |
| 399 | +tgrel=heap_openr(TriggerRelationName,AccessShareLock); |
| 400 | + |
| 401 | +/* |
| 402 | + * Find the trigger |
| 403 | + */ |
| 404 | +ScanKeyEntryInitialize(&skey[0],0x0, |
| 405 | +ObjectIdAttributeNumber,F_OIDEQ, |
| 406 | +ObjectIdGetDatum(trigid)); |
| 407 | + |
| 408 | +tgscan=systable_beginscan(tgrel,TriggerOidIndex, true, |
| 409 | +SnapshotNow,1,skey); |
| 410 | + |
| 411 | +ht_trig=systable_getnext(tgscan); |
| 412 | + |
| 413 | +if (!HeapTupleIsValid(ht_trig)) |
| 414 | +elog(ERROR,"pg_get_triggerdef: there is no trigger with oid %u", |
| 415 | +trigid); |
| 416 | + |
| 417 | +trigrec= (Form_pg_trigger)GETSTRUCT(ht_trig); |
| 418 | +systable_endscan(tgscan); |
| 419 | + |
| 420 | +/* |
| 421 | + * Fetch the pg_proc tuple of the trigger's function |
| 422 | + */ |
| 423 | +ht_proc=SearchSysCache(PROCOID, |
| 424 | +ObjectIdGetDatum(trigrec->tgfoid), |
| 425 | +0,0,0); |
| 426 | +if (!HeapTupleIsValid(ht_proc)) |
| 427 | +elog(ERROR,"syscache lookup for function %u failed",trigrec->tgfoid); |
| 428 | + |
| 429 | +tgfname=NameStr(((Form_pg_proc)GETSTRUCT(ht_proc))->proname); |
| 430 | + |
| 431 | +/* |
| 432 | + * Start the trigger definition. Note that the trigger's name should |
| 433 | + * never be schema-qualified, but the trigger rel's name may be. |
| 434 | + */ |
| 435 | +initStringInfo(&buf); |
| 436 | + |
| 437 | +tgname=NameStr(trigrec->tgname); |
| 438 | +appendStringInfo(&buf,"CREATE %sTRIGGER %s ", |
| 439 | +trigrec->tgisconstraint ?"CONSTRAINT " :"", |
| 440 | +quote_identifier(tgname)); |
| 441 | + |
| 442 | +if (TRIGGER_FOR_BEFORE(trigrec->tgtype)) |
| 443 | +appendStringInfo(&buf,"BEFORE"); |
| 444 | +else |
| 445 | +appendStringInfo(&buf,"AFTER"); |
| 446 | +if (TRIGGER_FOR_INSERT(trigrec->tgtype)) |
| 447 | +{ |
| 448 | +appendStringInfo(&buf," INSERT"); |
| 449 | +findx++; |
| 450 | +} |
| 451 | +if (TRIGGER_FOR_DELETE(trigrec->tgtype)) |
| 452 | +{ |
| 453 | +if (findx>0) |
| 454 | +appendStringInfo(&buf," OR DELETE"); |
| 455 | +else |
| 456 | +appendStringInfo(&buf," DELETE"); |
| 457 | +findx++; |
| 458 | +} |
| 459 | +if (TRIGGER_FOR_UPDATE(trigrec->tgtype)) |
| 460 | +{ |
| 461 | +if (findx>0) |
| 462 | +appendStringInfo(&buf," OR UPDATE"); |
| 463 | +else |
| 464 | +appendStringInfo(&buf," UPDATE"); |
| 465 | +} |
| 466 | +appendStringInfo(&buf," ON %s ", |
| 467 | +generate_relation_name(trigrec->tgrelid)); |
| 468 | + |
| 469 | + |
| 470 | +if (trigrec->tgisconstraint) |
| 471 | +{ |
| 472 | +if (trigrec->tgconstrrelid!=0) |
| 473 | +{ |
| 474 | +appendStringInfo(&buf,"FROM %s ", |
| 475 | +generate_relation_name(trigrec->tgconstrrelid)); |
| 476 | +} |
| 477 | +if (!trigrec->tgdeferrable) |
| 478 | +appendStringInfo(&buf,"NOT "); |
| 479 | +appendStringInfo(&buf,"DEFERRABLE INITIALLY "); |
| 480 | +if (trigrec->tginitdeferred) |
| 481 | +appendStringInfo(&buf,"DEFERRED "); |
| 482 | +else |
| 483 | +appendStringInfo(&buf,"IMMEDIATE "); |
| 484 | + |
| 485 | +} |
| 486 | + |
| 487 | +if (TRIGGER_FOR_ROW(trigrec->tgtype)) |
| 488 | +appendStringInfo(&buf,"FOR EACH ROW "); |
| 489 | +else |
| 490 | +appendStringInfo(&buf,"FOR EACH STATEMENT "); |
| 491 | + |
| 492 | +appendStringInfo(&buf,"EXECUTE PROCEDURE %s(", |
| 493 | +quote_identifier(tgfname)); |
| 494 | + |
| 495 | +/* Get args string */ |
| 496 | +tgargs=DatumGetCString(DirectFunctionCall1(byteaout, |
| 497 | +PointerGetDatum(&trigrec->tgargs))); |
| 498 | +/* If it's NULL, fail */ |
| 499 | +if (tgargs==NULL) |
| 500 | +elog(ERROR,"pg_get_triggerdef: tgargs is NULL"); |
| 501 | + |
| 502 | +for (findx=0;findx<trigrec->tgnargs;findx++) |
| 503 | +{ |
| 504 | +constchar*s; |
| 505 | + |
| 506 | +for (p=tgargs;;) |
| 507 | +{ |
| 508 | +p=strchr(p,'\\'); |
| 509 | +if (p==NULL) |
| 510 | +{ |
| 511 | +elog(ERROR,"pg_get_triggerdef: bad argument string for trigger"); |
| 512 | +} |
| 513 | +p++; |
| 514 | +if (*p=='\\') |
| 515 | +{ |
| 516 | +p++; |
| 517 | +continue; |
| 518 | +} |
| 519 | +if (p[0]=='0'&&p[1]=='0'&&p[2]=='0') |
| 520 | +break; |
| 521 | +} |
| 522 | +p--; |
| 523 | +appendStringInfoChar(&buf,'\''); |
| 524 | +for (s=tgargs;s<p;) |
| 525 | +{ |
| 526 | +/* If character is an apostrophe, escape it */ |
| 527 | +if (*s=='\'') |
| 528 | +appendStringInfoChar(&buf,'\\'); |
| 529 | +appendStringInfoChar(&buf,*s++); |
| 530 | +} |
| 531 | +appendStringInfoChar(&buf,'\''); |
| 532 | +appendStringInfo(&buf, (findx<trigrec->tgnargs-1) ?", " :""); |
| 533 | +tgargs=p+4; |
| 534 | +} |
| 535 | + |
| 536 | +/* Deliberately omit semi-colon */ |
| 537 | +appendStringInfo(&buf,")"); |
| 538 | + |
| 539 | +/* |
| 540 | + * Create the result as a TEXT datum, and free working data |
| 541 | + */ |
| 542 | +len=buf.len+VARHDRSZ; |
| 543 | +trigdef= (text*)palloc(len); |
| 544 | +VARATT_SIZEP(trigdef)=len; |
| 545 | +memcpy(VARDATA(trigdef),buf.data,buf.len); |
| 546 | + |
| 547 | +pfree(buf.data); |
| 548 | + |
| 549 | +ReleaseSysCache(ht_trig); |
| 550 | +ReleaseSysCache(ht_proc); |
| 551 | +heap_close(tgrel,AccessShareLock); |
| 552 | + |
| 553 | +PG_RETURN_TEXT_P(trigdef); |
| 554 | +} |
372 | 555 |
|
373 | 556 | /* ----------
|
374 | 557 | * get_indexdef- Get the definition of an index
|
|