|
1 | 1 | /*
|
2 |
| - * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.15 1997/09/18 20:22:54 momjian Exp $ |
| 2 | + * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.16 1997/09/24 08:35:10 vadim Exp $ |
3 | 3 | */
|
4 | 4 |
|
5 | 5 | #include<float.h>/* faked on sunos */
|
@@ -411,3 +411,232 @@ funny_dup17()
|
411 | 411 |
|
412 | 412 | return (tuple);
|
413 | 413 | }
|
| 414 | + |
| 415 | +#include<ctype.h>/* tolower () */ |
| 416 | + |
| 417 | +HeapTuplettdummy(void); |
| 418 | +int32set_ttdummy(int32on); |
| 419 | + |
| 420 | +externint4nextval(structvarlena*seqin); |
| 421 | + |
| 422 | +#defineTTDUMMY_INFINITY999999 |
| 423 | + |
| 424 | +staticvoid*splan=NULL; |
| 425 | +staticboolttoff= false; |
| 426 | + |
| 427 | +HeapTuple |
| 428 | +ttdummy() |
| 429 | +{ |
| 430 | +Trigger*trigger;/* to get trigger name */ |
| 431 | +char**args;/* arguments */ |
| 432 | +intattnum[2];/* fnumbers of start/stop columns */ |
| 433 | +Datumoldon,oldoff; |
| 434 | +Datumnewon,newoff; |
| 435 | +Datum*cvals;/* column values */ |
| 436 | +char*cnulls;/* column nulls */ |
| 437 | +char*relname;/* triggered relation name */ |
| 438 | +Relationrel;/* triggered relation */ |
| 439 | +HeapTupletrigtuple; |
| 440 | +HeapTuplenewtuple=NULL; |
| 441 | +HeapTuplerettuple; |
| 442 | +TupleDesctupdesc;/* tuple description */ |
| 443 | +intnatts;/* # of attributes */ |
| 444 | +boolisnull;/* to know is some column NULL or not */ |
| 445 | +intret; |
| 446 | +inti; |
| 447 | + |
| 448 | +if (!CurrentTriggerData) |
| 449 | +elog(WARN,"ttdummy: triggers are not initialized"); |
| 450 | +if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event)) |
| 451 | +elog(WARN,"ttdummy: can't process STATEMENT events"); |
| 452 | +if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event)) |
| 453 | +elog(WARN,"ttdummy: must be fired before event"); |
| 454 | +if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event)) |
| 455 | +elog (WARN,"ttdummy: can't process INSERT event"); |
| 456 | +if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event)) |
| 457 | +newtuple=CurrentTriggerData->tg_newtuple; |
| 458 | + |
| 459 | +trigtuple=CurrentTriggerData->tg_trigtuple; |
| 460 | + |
| 461 | +rel=CurrentTriggerData->tg_relation; |
| 462 | +relname=SPI_getrelname(rel); |
| 463 | + |
| 464 | +/* check if TT is OFF for this relation */ |
| 465 | +if (ttoff)/* OFF - nothing to do */ |
| 466 | +{ |
| 467 | +pfree (relname); |
| 468 | +return ((newtuple!=NULL) ?newtuple :trigtuple); |
| 469 | +} |
| 470 | + |
| 471 | +trigger=CurrentTriggerData->tg_trigger; |
| 472 | + |
| 473 | +if (trigger->tgnargs!=2) |
| 474 | +elog(WARN,"ttdummy (%s): invalid (!= 2) number of arguments %d", |
| 475 | +relname,trigger->tgnargs); |
| 476 | + |
| 477 | +args=trigger->tgargs; |
| 478 | +tupdesc=rel->rd_att; |
| 479 | +natts=tupdesc->natts; |
| 480 | + |
| 481 | +CurrentTriggerData=NULL; |
| 482 | + |
| 483 | +for (i=0;i<2;i++ ) |
| 484 | +{ |
| 485 | +attnum[i]=SPI_fnumber (tupdesc,args[i]); |
| 486 | +if (attnum[i]<0 ) |
| 487 | +elog(WARN,"ttdummy (%s): there is no attribute %s",relname,args[i]); |
| 488 | +if (SPI_gettypeid (tupdesc,attnum[i])!=INT4OID) |
| 489 | +elog(WARN,"ttdummy (%s): attributes %s and %s must be of abstime type", |
| 490 | +relname,args[0],args[1]); |
| 491 | +} |
| 492 | + |
| 493 | +oldon=SPI_getbinval (trigtuple,tupdesc,attnum[0],&isnull); |
| 494 | +if (isnull) |
| 495 | +elog(WARN,"ttdummy (%s): %s must be NOT NULL",relname,args[0]); |
| 496 | + |
| 497 | +oldoff=SPI_getbinval (trigtuple,tupdesc,attnum[1],&isnull); |
| 498 | +if (isnull) |
| 499 | +elog(WARN,"ttdummy (%s): %s must be NOT NULL",relname,args[1]); |
| 500 | + |
| 501 | +if (newtuple!=NULL)/* UPDATE */ |
| 502 | +{ |
| 503 | +newon=SPI_getbinval (newtuple,tupdesc,attnum[0],&isnull); |
| 504 | +if (isnull) |
| 505 | +elog(WARN,"ttdummy (%s): %s must be NOT NULL",relname,args[0]); |
| 506 | +newoff=SPI_getbinval (newtuple,tupdesc,attnum[1],&isnull); |
| 507 | +if (isnull) |
| 508 | +elog(WARN,"ttdummy (%s): %s must be NOT NULL",relname,args[1]); |
| 509 | + |
| 510 | +if (oldon!=newon||oldoff!=newoff ) |
| 511 | +elog (WARN,"ttdummy (%s): you can't change %s and/or %s columns (use set_ttdummy)", |
| 512 | +relname,args[0],args[1]); |
| 513 | + |
| 514 | +if (newoff!=TTDUMMY_INFINITY ) |
| 515 | +{ |
| 516 | +pfree (relname);/* allocated in upper executor context */ |
| 517 | +return (NULL); |
| 518 | +} |
| 519 | +} |
| 520 | +elseif (oldoff!=TTDUMMY_INFINITY)/* DELETE */ |
| 521 | +{ |
| 522 | +pfree (relname); |
| 523 | +return (NULL); |
| 524 | +} |
| 525 | + |
| 526 | +{ |
| 527 | +structvarlena*seqname=textin ("ttdummy_seq"); |
| 528 | + |
| 529 | +newoff=nextval (seqname); |
| 530 | +pfree (seqname); |
| 531 | +} |
| 532 | + |
| 533 | +/* Connect to SPI manager */ |
| 534 | +if ((ret=SPI_connect())<0) |
| 535 | +elog(WARN,"ttdummy (%s): SPI_connect returned %d",relname,ret); |
| 536 | + |
| 537 | +/* Fetch tuple values and nulls */ |
| 538 | +cvals= (Datum*)palloc (natts*sizeof (Datum)); |
| 539 | +cnulls= (char*)palloc (natts*sizeof (char)); |
| 540 | +for (i=0;i<natts;i++) |
| 541 | +{ |
| 542 | +cvals[i]=SPI_getbinval ((newtuple!=NULL) ?newtuple :trigtuple, |
| 543 | +tupdesc,i+1,&isnull); |
| 544 | +cnulls[i]= (isnull) ?'n' :' '; |
| 545 | +} |
| 546 | + |
| 547 | +/* change date column(s) */ |
| 548 | +if (newtuple)/* UPDATE */ |
| 549 | +{ |
| 550 | +cvals[attnum[0]-1]=newoff;/* start_date eq current date */ |
| 551 | +cnulls[attnum[0]-1]=' '; |
| 552 | +cvals[attnum[1]-1]=TTDUMMY_INFINITY;/* stop_date eq INFINITY */ |
| 553 | +cnulls[attnum[1]-1]=' '; |
| 554 | +} |
| 555 | +else/* DELETE */ |
| 556 | +{ |
| 557 | +cvals[attnum[1]-1]=newoff;/* stop_date eq current date */ |
| 558 | +cnulls[attnum[1]-1]=' '; |
| 559 | +} |
| 560 | + |
| 561 | +/* if there is no plan ... */ |
| 562 | +if (splan==NULL) |
| 563 | +{ |
| 564 | +void*pplan; |
| 565 | +Oid*ctypes; |
| 566 | +charsql[8192]; |
| 567 | + |
| 568 | +/* allocate ctypes for preparation */ |
| 569 | +ctypes= (Oid*)palloc(natts*sizeof(Oid)); |
| 570 | + |
| 571 | +/* |
| 572 | + * Construct query: |
| 573 | + * INSERT INTO _relation_ VALUES ($1, ...) |
| 574 | + */ |
| 575 | +sprintf(sql,"INSERT INTO %s VALUES (",relname); |
| 576 | +for (i=1;i <=natts;i++) |
| 577 | +{ |
| 578 | +sprintf(sql+strlen(sql),"$%d%s", |
| 579 | +i, (i<natts) ?", " :")"); |
| 580 | +ctypes[i-1]=SPI_gettypeid(tupdesc,i); |
| 581 | +} |
| 582 | + |
| 583 | +/* Prepare plan for query */ |
| 584 | +pplan=SPI_prepare(sql,natts,ctypes); |
| 585 | +if (pplan==NULL) |
| 586 | +elog(WARN,"ttdummy (%s): SPI_prepare returned %d",relname,SPI_result); |
| 587 | + |
| 588 | +pplan=SPI_saveplan(pplan); |
| 589 | +if (pplan==NULL) |
| 590 | +elog(WARN,"ttdummy (%s): SPI_saveplan returned %d",relname,SPI_result); |
| 591 | + |
| 592 | +splan=pplan; |
| 593 | +} |
| 594 | + |
| 595 | +ret=SPI_execp(splan,cvals,cnulls,0); |
| 596 | + |
| 597 | +if (ret<0) |
| 598 | +elog(WARN,"ttdummy (%s): SPI_execp returned %d",relname,ret); |
| 599 | + |
| 600 | +/* Tuple to return to upper Executor ... */ |
| 601 | +if (newtuple)/* UPDATE */ |
| 602 | +{ |
| 603 | +HeapTupletmptuple; |
| 604 | + |
| 605 | +tmptuple=SPI_copytuple (trigtuple); |
| 606 | +rettuple=SPI_modifytuple (rel,tmptuple,1,&(attnum[1]),&newoff,NULL); |
| 607 | +SPI_pfree (tmptuple); |
| 608 | +} |
| 609 | +else/* DELETE */ |
| 610 | +rettuple=trigtuple; |
| 611 | + |
| 612 | +SPI_finish();/* don't forget say Bye to SPI mgr */ |
| 613 | + |
| 614 | +pfree (relname); |
| 615 | + |
| 616 | +return (rettuple); |
| 617 | +} |
| 618 | + |
| 619 | +int32 |
| 620 | +set_ttdummy(int32on) |
| 621 | +{ |
| 622 | + |
| 623 | +if (ttoff)/* OFF currently */ |
| 624 | +{ |
| 625 | +if (on==0) |
| 626 | +return (0); |
| 627 | + |
| 628 | +/* turn ON */ |
| 629 | +ttoff= false; |
| 630 | +return (0); |
| 631 | +} |
| 632 | + |
| 633 | +/* ON currently */ |
| 634 | +if (on!=0) |
| 635 | +return (1); |
| 636 | + |
| 637 | +/* turn OFF */ |
| 638 | +ttoff= true; |
| 639 | + |
| 640 | +return (1); |
| 641 | + |
| 642 | +} |