execMain.c 36.7 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * execMain.c--
4
 *	  top level executor interface routines
5 6
 *
 * INTERFACE ROUTINES
7 8 9
 *	ExecutorStart()
 *	ExecutorRun()
 *	ExecutorEnd()
10
 *
11 12 13 14 15 16 17 18 19 20 21 22 23
 *	The old ExecutorMain() has been replaced by ExecutorStart(),
 *	ExecutorRun() and ExecutorEnd()
 *
 *	These three procedures are the external interfaces to the executor.
 *	In each case, the query descriptor and the execution state is required
 *	 as arguments
 *
 *	ExecutorStart() must be called at the beginning of any execution of any
 *	query plan and ExecutorEnd() should always be called at the end of
 *	execution of a plan.
 *
 *	ExecutorRun accepts 'feature' and 'count' arguments that specify whether
 *	the plan is to be executed forwards, backwards, and for how many tuples.
24 25 26 27 28
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
29
 *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.65 1999/01/27 16:48:20 tgl Exp $
30 31 32
 *
 *-------------------------------------------------------------------------
 */
33
#include <string.h>
34
#include "postgres.h"
35
#include "miscadmin.h"
36

37
#include "executor/executor.h"
38 39
#include "executor/execdefs.h"
#include "executor/execdebug.h"
40
#include "executor/nodeIndexscan.h"
41 42 43
#include "utils/builtins.h"
#include "utils/palloc.h"
#include "utils/acl.h"
44
#include "utils/syscache.h"
45
#include "utils/tqual.h"
46
#include "parser/parsetree.h"	/* rt_fetch() */
47
#include "storage/bufmgr.h"
Marc G. Fournier's avatar
Marc G. Fournier committed
48
#include "storage/lmgr.h"
49
#include "storage/smgr.h"
50 51 52
#include "commands/async.h"
/* #include "access/localam.h" */
#include "optimizer/var.h"
53
#include "access/heapam.h"
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
54
#include "access/xact.h"
55
#include "catalog/heap.h"
56
#include "commands/trigger.h"
57

58
void ExecCheckPerms(CmdType operation, int resultRelation, List *rangeTable,
59
			   Query *parseTree);
60 61 62


/* decls for local routines only used within this module */
63
static TupleDesc InitPlan(CmdType operation, Query *parseTree,
64 65
		 Plan *plan, EState *estate);
static void EndPlan(Plan *plan, EState *estate);
66
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
67
			Query *parseTree, CmdType operation,
68
			int numberTuples, ScanDirection direction,
69 70 71 72
			DestReceiver *destfunc);
static void ExecRetrieve(TupleTableSlot *slot,
						 DestReceiver *destfunc,
						 EState *estate);
73
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
74
		   EState *estate);
75
static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
76
		   EState *estate);
77
static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
78
			EState *estate, Query *parseTree);
79 80 81

/* end of local decls */

Marc G. Fournier's avatar
Marc G. Fournier committed
82
#ifdef QUERY_LIMIT
83
static int	queryLimit = ALL_TUPLES;
84

Marc G. Fournier's avatar
Marc G. Fournier committed
85 86 87 88 89 90
#undef ALL_TUPLES
#define ALL_TUPLES queryLimit

int
ExecutorLimit(int limit)
{
91
	return queryLimit = limit;
Marc G. Fournier's avatar
Marc G. Fournier committed
92
}
93

Bruce Momjian's avatar
Bruce Momjian committed
94 95 96 97 98 99
int
ExecutorGetLimit()
{
	return queryLimit;
}

100
#endif
Marc G. Fournier's avatar
Marc G. Fournier committed
101

102
/* ----------------------------------------------------------------
103 104 105 106 107 108 109
 *		ExecutorStart
 *
 *		This routine must be called at the beginning of any execution of any
 *		query plan
 *
 *		returns (AttrInfo*) which describes the attributes of the tuples to
 *		be returned by the query.
110 111 112 113
 *
 * ----------------------------------------------------------------
 */
TupleDesc
114
ExecutorStart(QueryDesc *queryDesc, EState *estate)
115
{
116
	TupleDesc	result;
117 118 119

	/* sanity checks */
	Assert(queryDesc != NULL);
120

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
121 122
	if (queryDesc->plantree->nParamExec > 0)
	{
123 124 125
		estate->es_param_exec_vals = (ParamExecData *)
			palloc(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
		memset(estate->es_param_exec_vals, 0, queryDesc->plantree->nParamExec * sizeof(ParamExecData));
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
126
	}
127

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
128
	estate->es_snapshot = QuerySnapshot;
129

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	result = InitPlan(queryDesc->operation,
					  queryDesc->parsetree,
					  queryDesc->plantree,
					  estate);

	/*
	 * reset buffer refcount.  the current refcounts are saved and will be
	 * restored when ExecutorEnd is called
	 *
	 * this makes sure that when ExecutorRun's are called recursively as for
	 * postquel functions, the buffers pinned by one ExecutorRun will not
	 * be unpinned by another ExecutorRun.
	 */
	BufferRefCountReset(estate->es_refcount);

	return result;
146 147 148
}

/* ----------------------------------------------------------------
149 150 151 152 153 154 155
 *		ExecutorRun
 *
 *		This is the main routine of the executor module. It accepts
 *		the query descriptor from the traffic cop and executes the
 *		query plan.
 *
 *		ExecutorStart must have been called already.
156
 *
157 158 159 160 161 162
 *		the different features supported are:
 *			 EXEC_RUN:	retrieve all tuples in the forward direction
 *			 EXEC_FOR:	retrieve 'count' number of tuples in the forward dir
 *			 EXEC_BACK: retrieve 'count' number of tuples in the backward dir
 *			 EXEC_RETONE: return one tuple but don't 'retrieve' it
 *						   used in postquel function processing
163 164 165 166
 *
 *
 * ----------------------------------------------------------------
 */
167
TupleTableSlot *
168
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
169
{
170 171 172
	CmdType		operation;
	Query	   *parseTree;
	Plan	   *plan;
173
	TupleTableSlot *result;
174
	CommandDest dest;
175
	DestReceiver   *destfunc;
176

177
	/******************
178
	 *	sanity checks
179
	 ******************
180
	 */
181 182
	Assert(queryDesc != NULL);

183
	/******************
184 185
	 *	extract information from the query descriptor
	 *	and the query feature.
186
	 ******************
187
	 */
188 189 190 191
	operation = queryDesc->operation;
	parseTree = queryDesc->parsetree;
	plan = queryDesc->plantree;
	dest = queryDesc->dest;
192
	destfunc = DestToFunction(dest);
193 194 195
	estate->es_processed = 0;
	estate->es_lastoid = InvalidOid;

196 197 198 199 200 201 202 203 204
	/******************
	 *	FIXME: the dest setup function ought to be handed the tuple desc
	 *  for the tuples to be output, but I'm not quite sure how to get that
	 *  info at this point.  For now, passing NULL is OK because no existing
	 *  dest setup function actually uses the pointer.
	 ******************
	 */
	(*destfunc->setup) (destfunc, (TupleDesc) NULL);

205 206 207
	switch (feature)
	{

208 209 210 211 212 213 214
		case EXEC_RUN:
			result = ExecutePlan(estate,
								 plan,
								 parseTree,
								 operation,
								 ALL_TUPLES,
								 ForwardScanDirection,
215
								 destfunc);
216 217 218 219 220 221 222 223
			break;
		case EXEC_FOR:
			result = ExecutePlan(estate,
								 plan,
								 parseTree,
								 operation,
								 count,
								 ForwardScanDirection,
224
								 destfunc);
225
			break;
226

227
			/******************
228
			 *		retrieve next n "backward" tuples
229
			 ******************
230 231 232 233 234 235 236 237
			 */
		case EXEC_BACK:
			result = ExecutePlan(estate,
								 plan,
								 parseTree,
								 operation,
								 count,
								 BackwardScanDirection,
238
								 destfunc);
239
			break;
240

241
			/******************
242 243
			 *		return one tuple but don't "retrieve" it.
			 *		(this is used by the rule manager..) -cim 9/14/89
244
			 ******************
245 246 247 248 249 250 251 252
			 */
		case EXEC_RETONE:
			result = ExecutePlan(estate,
								 plan,
								 parseTree,
								 operation,
								 ONE_TUPLE,
								 ForwardScanDirection,
253
								 destfunc);
254 255 256 257 258
			break;
		default:
			result = NULL;
			elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
			break;
259 260
	}

261 262
	(*destfunc->cleanup) (destfunc);

263
	return result;
264 265 266
}

/* ----------------------------------------------------------------
267 268 269 270 271 272 273
 *		ExecutorEnd
 *
 *		This routine must be called at the end of any execution of any
 *		query plan
 *
 *		returns (AttrInfo*) which describes the attributes of the tuples to
 *		be returned by the query.
274 275 276 277
 *
 * ----------------------------------------------------------------
 */
void
278
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
279
{
280 281
	/* sanity checks */
	Assert(queryDesc != NULL);
282

283
	EndPlan(queryDesc->plantree, estate);
284

285 286
	/* restore saved refcounts. */
	BufferRefCountRestore(estate->es_refcount);
287 288
}

289
void
290
ExecCheckPerms(CmdType operation,
291
			   int resultRelation,
292 293
			   List *rangeTable,
			   Query *parseTree)
294
{
295 296
	int			i = 1;
	Oid			relid;
297
	HeapTuple	htup;
298 299 300 301 302 303 304 305
	List	   *lp;
	List	   *qvars,
			   *tvars;
	int32		ok = 1,
				aclcheck_result = -1;
	char	   *opstr;
	NameData	rname;
	char	   *userName;
306 307 308 309 310 311 312

#define CHECK(MODE)		pg_aclcheck(rname.data, userName, MODE)

	userName = GetPgUserName();

	foreach(lp, rangeTable)
	{
313
		RangeTblEntry *rte = lfirst(lp);
314

Marc G. Fournier's avatar
Marc G. Fournier committed
315 316
		if (rte->skipAcl)
		{
317

Marc G. Fournier's avatar
Marc G. Fournier committed
318
			/*
319 320 321 322
			 * This happens if the access to this table is due to a view
			 * query rewriting - the rewrite handler checked the
			 * permissions against the view owner, so we just skip this
			 * entry.
Marc G. Fournier's avatar
Marc G. Fournier committed
323 324 325 326
			 */
			continue;
		}

327
		relid = rte->relid;
328
		htup = SearchSysCacheTuple(RELOID,
329 330
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
331
		if (!HeapTupleIsValid(htup))
332
			elog(ERROR, "ExecCheckPerms: bogus RT relid: %d",
333
				 relid);
334
		StrNCpy(rname.data,
335
				((Form_pg_class) GETSTRUCT(htup))->relname.data,
336
				NAMEDATALEN);
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
		if (i == resultRelation)
		{						/* this is the result relation */
			qvars = pull_varnos(parseTree->qual);
			tvars = pull_varnos((Node *) parseTree->targetList);
			if (intMember(resultRelation, qvars) ||
				intMember(resultRelation, tvars))
			{
				/* result relation is scanned */
				ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
				opstr = "read";
				if (!ok)
					break;
			}
			switch (operation)
			{
352 353 354 355 356 357 358 359 360 361 362
				case CMD_INSERT:
					ok = ((aclcheck_result = CHECK(ACL_AP)) == ACLCHECK_OK) ||
						((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
					opstr = "append";
					break;
				case CMD_DELETE:
				case CMD_UPDATE:
					ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
					opstr = "write";
					break;
				default:
363
					elog(ERROR, "ExecCheckPerms: bogus operation %d",
364
						 operation);
365 366 367 368 369 370 371
			}
		}
		else
		{
			ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
			opstr = "read";
		}
372
		if (!ok)
373 374
			break;
		++i;
375 376
	}
	if (!ok)
377
		elog(ERROR, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
378

379
	if (parseTree != NULL && parseTree->rowMark != NULL)
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
	{
		foreach(lp, parseTree->rowMark)
		{
			RowMark	   *rm = lfirst(lp);

			if (!(rm->info & ROW_ACL_FOR_UPDATE))
				continue;

			relid = ((RangeTblEntry *)nth(rm->rti - 1, rangeTable))->relid;
			htup = SearchSysCacheTuple(RELOID,
								   ObjectIdGetDatum(relid),
								   0, 0, 0);
			if (!HeapTupleIsValid(htup))
				elog(ERROR, "ExecCheckPerms: bogus RT relid: %d",
					 relid);
			StrNCpy(rname.data,
					((Form_pg_class) GETSTRUCT(htup))->relname.data,
					NAMEDATALEN);
			ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
			opstr = "write";
			if (!ok)
				elog(ERROR, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
		}
	}
404 405
}

406 407 408 409 410 411 412
/* ===============================================================
 * ===============================================================
						 static routines follow
 * ===============================================================
 * ===============================================================
 */

413 414 415 416 417
typedef struct execRowMark
{
	Relation	relation;
	char		resname[32];
} execRowMark;
418 419

/* ----------------------------------------------------------------
420 421 422 423
 *		InitPlan
 *
 *		Initializes the query plan: open files, allocate storage
 *		and start up the rule manager
424 425
 * ----------------------------------------------------------------
 */
426
static TupleDesc
427
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
428
{
429 430 431
	List	   *rangeTable;
	int			resultRelation;
	Relation	intoRelationDesc;
432

433 434 435
	TupleDesc	tupType;
	List	   *targetList;
	int			len;
436

437
	/******************
438
	 *	get information from query descriptor
439
	 ******************
440
	 */
441 442
	rangeTable = parseTree->rtable;
	resultRelation = parseTree->resultRelation;
443

444 445 446 447
#ifndef NO_SECURITY
	ExecCheckPerms(operation, resultRelation, rangeTable, parseTree);
#endif

448
	/******************
449
	 *	initialize the node's execution state
450
	 ******************
451
	 */
452 453
	estate->es_range_table = rangeTable;

454
	/******************
455 456 457 458
	 *	initialize the BaseId counter so node base_id's
	 *	are assigned correctly.  Someday baseid's will have to
	 *	be stored someplace other than estate because they
	 *	should be unique per query planned.
459
	 ******************
460
	 */
461
	estate->es_BaseId = 1;
462

463
	/******************
464
	 *	initialize result relation stuff
465
	 ******************
466
	 */
467

468 469
	if (resultRelation != 0 && operation != CMD_SELECT)
	{
470
		/******************
471 472
		 *	  if we have a result relation, open it and
		 *	  initialize the result relation info stuff.
473
		 ******************
474
		 */
475 476 477 478 479
		RelationInfo *resultRelationInfo;
		Index		resultRelationIndex;
		RangeTblEntry *rtentry;
		Oid			resultRelationOid;
		Relation	resultRelationDesc;
480 481 482 483 484 485 486

		resultRelationIndex = resultRelation;
		rtentry = rt_fetch(resultRelationIndex, rangeTable);
		resultRelationOid = rtentry->relid;
		resultRelationDesc = heap_open(resultRelationOid);

		if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
487
			elog(ERROR, "You can't change sequence relation %s",
488 489
				 resultRelationDesc->rd_rel->relname.data);

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
490
		LockRelation(resultRelationDesc, RowExclusiveLock);
491 492 493 494 495 496 497

		resultRelationInfo = makeNode(RelationInfo);
		resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
		resultRelationInfo->ri_RelationDesc = resultRelationDesc;
		resultRelationInfo->ri_NumIndices = 0;
		resultRelationInfo->ri_IndexRelationDescs = NULL;
		resultRelationInfo->ri_IndexRelationInfo = NULL;
498

499
		/******************
500 501
		 *	open indices on result relation and save descriptors
		 *	in the result relation information..
502
		 ******************
503
		 */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
504 505
		if (operation != CMD_DELETE)
			ExecOpenIndices(resultRelationOid, resultRelationInfo);
506 507

		estate->es_result_relation_info = resultRelationInfo;
508
	}
509 510
	else
	{
511
		/******************
512
		 *		if no result relation, then set state appropriately
513
		 ******************
514 515 516 517
		 */
		estate->es_result_relation_info = NULL;
	}

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
	/*
	 * Have to lock relations selected for update
	 */
	estate->es_rowMark = NULL;
	if (parseTree->rowMark != NULL)
	{
		Relation		relation;
		Oid				relid;
		RowMark		   *rm;
		List		   *l;
		execRowMark	   *erm;

		foreach(l, parseTree->rowMark)
		{
			rm = lfirst(l);
			relid = ((RangeTblEntry *)nth(rm->rti - 1, rangeTable))->relid;
			relation = heap_open(relid);
			LockRelation(relation, RowShareLock);
			if (!(rm->info & ROW_MARK_FOR_UPDATE))
				continue;
			erm = (execRowMark*) palloc(sizeof(execRowMark));
			erm->relation = relation;
			sprintf(erm->resname, "ctid%u", rm->rti);
			estate->es_rowMark = lappend(estate->es_rowMark, erm);
		}
	}
544

545
	/******************
546
	 *	  initialize the executor "tuple" table.
547
	 ******************
548 549
	 */
	{
550 551
		int			nSlots = ExecCountSlotsNode(plan);
		TupleTable	tupleTable = ExecCreateTupleTable(nSlots + 10);		/* why add ten? - jolly */
552

553 554
		estate->es_tupleTable = tupleTable;
	}
555

556
	/******************
557 558 559 560
	 *	   initialize the private state information for
	 *	   all the nodes in the query tree.  This opens
	 *	   files, allocates storage and leaves us ready
	 *	   to start processing tuples..
561
	 ******************
562 563 564
	 */
	ExecInitNode(plan, estate, NULL);

565
	/******************
566 567 568
	 *	   get the tuple descriptor describing the type
	 *	   of tuples to return.. (this is especially important
	 *	   if we are creating a relation with "retrieve into")
569
	 ******************
570 571 572 573 574
	 */
	tupType = ExecGetTupType(plan);		/* tuple descriptor */
	targetList = plan->targetlist;
	len = ExecTargetListLength(targetList);		/* number of attributes */

575
	/******************
576 577 578 579 580 581
	 *	  now that we have the target list, initialize the junk filter
	 *	  if this is a REPLACE or a DELETE query.
	 *	  We also init the junk filter if this is an append query
	 *	  (there might be some rule lock info there...)
	 *	  NOTE: in the future we might want to initialize the junk
	 *	  filter for all queries.
582
	 ******************
583 584
	 *		  SELECT added by daveh@insightdist.com  5/20/98 to allow
	 *		  ORDER/GROUP BY have an identifier missing from the target.
585 586
	 */
	{
587 588 589
		bool		junk_filter_needed = false;
		List	   *tlist;

590
		if (operation == CMD_SELECT)
591 592 593
		{
			foreach(tlist, targetList)
			{
594 595
				TargetEntry *tle = lfirst(tlist);

596 597 598 599 600 601 602 603 604 605 606 607 608
				if (tle->resdom->resjunk)
				{
					junk_filter_needed = true;
					break;
				}
			}
		}

		if (operation == CMD_UPDATE || operation == CMD_DELETE ||
			operation == CMD_INSERT ||
			(operation == CMD_SELECT && junk_filter_needed))
		{
			JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList);
609

610
			estate->es_junkFilter = j;
611

612 613 614 615 616 617
			if (operation == CMD_SELECT)
				tupType = j->jf_cleanTupType;
		}
		else
			estate->es_junkFilter = NULL;
	}
618

619
	/******************
620
	 *	initialize the "into" relation
621
	 ******************
622 623 624 625 626
	 */
	intoRelationDesc = (Relation) NULL;

	if (operation == CMD_SELECT)
	{
627 628 629
		char	   *intoName;
		Oid			intoRelationId;
		TupleDesc	tupdesc;
630 631 632 633 634 635 636 637 638

		if (!parseTree->isPortal)
		{

			/*
			 * a select into table
			 */
			if (parseTree->into != NULL)
			{
639
				/******************
640
				 *	create the "into" relation
641
				 ******************
642 643 644 645 646 647 648 649
				 */
				intoName = parseTree->into;

				/*
				 * have to copy tupType to get rid of constraints
				 */
				tupdesc = CreateTupleDescCopy(tupType);

650
				intoRelationId = heap_create_with_catalog(intoName,
651
											  tupdesc, RELKIND_RELATION);
652

653 654
				FreeTupleDesc(tupdesc);

655
				/******************
656 657 658
				 *	XXX rather than having to call setheapoverride(true)
				 *		and then back to false, we should change the
				 *		arguments to heap_open() instead..
659
				 ******************
660 661 662 663 664 665 666 667 668 669 670 671 672
				 */
				setheapoverride(true);

				intoRelationDesc = heap_open(intoRelationId);

				setheapoverride(false);
			}
		}
	}

	estate->es_into_relation_descriptor = intoRelationDesc;

	return tupType;
673 674 675
}

/* ----------------------------------------------------------------
676 677 678
 *		EndPlan
 *
 *		Cleans up the query plan -- closes files and free up storages
679 680 681
 * ----------------------------------------------------------------
 */
static void
682
EndPlan(Plan *plan, EState *estate)
683
{
684 685
	RelationInfo *resultRelationInfo;
	Relation	intoRelationDesc;
686

687
	/******************
688
	 *	get information from state
689
	 ******************
690
	 */
691 692 693
	resultRelationInfo = estate->es_result_relation_info;
	intoRelationDesc = estate->es_into_relation_descriptor;

694
	/******************
695
	 *	 shut down the query
696
	 ******************
697 698 699
	 */
	ExecEndNode(plan, plan);

700
	/******************
701
	 *	  destroy the executor "tuple" table.
702
	 ******************
703 704
	 */
	{
705
		TupleTable	tupleTable = (TupleTable) estate->es_tupleTable;
706 707 708 709 710

		ExecDestroyTupleTable(tupleTable, true);		/* was missing last arg */
		estate->es_tupleTable = NULL;
	}

711
	/******************
712
	 *	 close the result relations if necessary
713
	 ******************
714 715 716
	 */
	if (resultRelationInfo != NULL)
	{
717
		Relation	resultRelationDesc;
718 719 720 721

		resultRelationDesc = resultRelationInfo->ri_RelationDesc;
		heap_close(resultRelationDesc);

722
		/******************
723
		 *	close indices on the result relation
724
		 ******************
725 726 727 728
		 */
		ExecCloseIndices(resultRelationInfo);
	}

729
	/******************
730
	 *	 close the "into" relation if necessary
731
	 ******************
732 733 734
	 */
	if (intoRelationDesc != NULL)
		heap_close(intoRelationDesc);
735 736 737
}

/* ----------------------------------------------------------------
738 739 740 741 742 743 744 745
 *		ExecutePlan
 *
 *		processes the query plan to retrieve 'tupleCount' tuples in the
 *		direction specified.
 *		Retrieves all tuples if tupleCount is 0
 *
 *		result is either a slot containing a tuple in the case
 *		of a RETRIEVE or NULL otherwise.
746 747 748 749 750 751 752 753
 *
 * ----------------------------------------------------------------
 */

/* the ctid attribute is a 'junk' attribute that is removed before the
   user can see it*/

static TupleTableSlot *
754 755 756
ExecutePlan(EState *estate,
			Plan *plan,
			Query *parseTree,
757 758 759
			CmdType operation,
			int numberTuples,
			ScanDirection direction,
760
			DestReceiver* destfunc)
761
{
762
	JunkFilter *junkfilter;
763 764

	TupleTableSlot *slot;
765
	ItemPointer tupleid = NULL;
766
	ItemPointerData tuple_ctid;
767
	int			current_tuple_count;
768 769
	TupleTableSlot *result;

770
	/******************
771
	 *	initialize local variables
772
	 ******************
773
	 */
774 775 776 777
	slot = NULL;
	current_tuple_count = 0;
	result = NULL;

778
	/******************
779
	 *	Set the direction.
780
	 ******************
781
	 */
782 783
	estate->es_direction = direction;

784
	/******************
785 786
	 *	Loop until we've processed the proper number
	 *	of tuples from the plan..
787
	 ******************
788 789 790 791
	 */

	for (;;)
	{
792 793 794 795 796 797
		/******************
		 *	Execute the plan and obtain a tuple
		 ******************
		 */
		/* at the top level, the parent of a plan (2nd arg) is itself */
		slot = ExecProcNode(plan, plan);
798

799 800 801 802 803 804 805 806 807 808
		/******************
		 *	if the tuple is null, then we assume
		 *	there is nothing more to process so
		 *	we just return null...
		 ******************
		 */
		if (TupIsNull(slot))
		{
			result = NULL;
			break;
809 810
		}

811
		/******************
812 813 814 815 816 817
		 *		if we have a junk filter, then project a new
		 *		tuple with the junk removed.
		 *
		 *		Store this new "clean" tuple in the place of the
		 *		original tuple.
		 *
818 819
		 *		Also, extract all the junk information we need.
		 ******************
820 821 822
		 */
		if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
		{
823
			Datum		datum;
824 825

/*			NameData	attrName; */
826 827
			HeapTuple	newTuple;
			bool		isNull;
828

829
			/******************
830
			 * extract the 'ctid' junk attribute.
831
			 ******************
832 833 834 835 836 837 838 839
			 */
			if (operation == CMD_UPDATE || operation == CMD_DELETE)
			{
				if (!ExecGetJunkAttribute(junkfilter,
										  slot,
										  "ctid",
										  &datum,
										  &isNull))
840
					elog(ERROR, "ExecutePlan: NO (junk) `ctid' was found!");
841 842

				if (isNull)
843
					elog(ERROR, "ExecutePlan: (junk) `ctid' is NULL!");
844 845 846 847 848 849

				tupleid = (ItemPointer) DatumGetPointer(datum);
				tuple_ctid = *tupleid;	/* make sure we don't free the
										 * ctid!! */
				tupleid = &tuple_ctid;
			}
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
			else if (estate->es_rowMark != NULL)
			{
				List		   *l;
				execRowMark	   *erm;
				Buffer			buffer;
				HeapTupleData	tuple;
				int				test;

				foreach (l, estate->es_rowMark)
				{
					erm = lfirst(l);
					if (!ExecGetJunkAttribute(junkfilter,
											  slot,
											  erm->resname,
											  &datum,
											  &isNull))
						elog(ERROR, "ExecutePlan: NO (junk) `%s' was found!", erm->resname);

					if (isNull)
						elog(ERROR, "ExecutePlan: (junk) `%s' is NULL!", erm->resname);

					tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
					test = heap_mark4update(erm->relation, &tuple, &buffer);
					ReleaseBuffer(buffer);
					switch (test)
					{
						case HeapTupleSelfUpdated:
						case HeapTupleMayBeUpdated:
							break;

						case HeapTupleUpdated:
							if (XactIsoLevel == XACT_SERIALIZABLE)
								elog(ERROR, "Can't serialize access due to concurrent update");
							else
								elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
							return(NULL);

						default:
							elog(ERROR, "Unknown status %u from heap_mark4update", test);
							return(NULL);
					}
				}
			}
893

894
			/******************
895 896
			 * Finally create a new "clean" tuple with all junk attributes
			 * removed
897
			 ******************
898 899 900 901 902 903 904 905 906 907
			 */
			newTuple = ExecRemoveJunk(junkfilter, slot);

			slot = ExecStoreTuple(newTuple,		/* tuple to store */
								  slot, /* destination slot */
								  InvalidBuffer,		/* this tuple has no
														 * buffer */
								  true);		/* tuple should be pfreed */
		}						/* if (junkfilter... */

908
		/******************
909 910 911 912
		 *		now that we have a tuple, do the appropriate thing
		 *		with it.. either return it to the user, add
		 *		it to a relation someplace, delete it from a
		 *		relation, or modify some of it's attributes.
913
		 ******************
914 915 916 917
		 */

		switch (operation)
		{
918 919
			case CMD_SELECT:
				ExecRetrieve(slot,		/* slot containing tuple */
920
							 destfunc,	/* destination's tuple-receiver obj */
921 922 923
							 estate);	/* */
				result = slot;
				break;
924

925 926 927 928
			case CMD_INSERT:
				ExecAppend(slot, tupleid, estate);
				result = NULL;
				break;
929

930 931 932 933
			case CMD_DELETE:
				ExecDelete(slot, tupleid, estate);
				result = NULL;
				break;
934

935 936 937 938
			case CMD_UPDATE:
				ExecReplace(slot, tupleid, estate, parseTree);
				result = NULL;
				break;
939

940 941
			default:
				elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
942
				result = NULL;
943
				break;
944
		}
945
		/******************
946 947 948
		 *		check our tuple count.. if we've returned the
		 *		proper number then return, else loop again and
		 *		process more tuples..
949
		 ******************
950 951 952 953
		 */
		current_tuple_count += 1;
		if (numberTuples == current_tuple_count)
			break;
954
	}
955

956
	/******************
957 958
	 *	here, result is either a slot containing a tuple in the case
	 *	of a RETRIEVE or NULL otherwise.
959
	 ******************
960
	 */
961
	return result;
962 963 964
}

/* ----------------------------------------------------------------
965
 *		ExecRetrieve
966
 *
967 968 969 970 971
 *		RETRIEVEs are easy.. we just pass the tuple to the appropriate
 *		print function.  The only complexity is when we do a
 *		"retrieve into", in which case we insert the tuple into
 *		the appropriate relation (note: this is a newly created relation
 *		so we don't need to worry about indices or locks.)
972 973 974
 * ----------------------------------------------------------------
 */
static void
975
ExecRetrieve(TupleTableSlot *slot,
976
			 DestReceiver *destfunc,
977
			 EState *estate)
978
{
979 980
	HeapTuple	tuple;
	TupleDesc	attrtype;
981

982
	/******************
983
	 *	get the heap tuple out of the tuple table slot
984
	 ******************
985 986 987 988
	 */
	tuple = slot->val;
	attrtype = slot->ttc_tupleDescriptor;

989
	/******************
990
	 *	insert the tuple into the "into relation"
991
	 ******************
992 993 994 995 996 997 998
	 */
	if (estate->es_into_relation_descriptor != NULL)
	{
		heap_insert(estate->es_into_relation_descriptor, tuple);
		IncrAppended();
	}

999
	/******************
1000
	 *	send the tuple to the front end (or the screen)
1001
	 ******************
1002
	 */
1003
	(*destfunc->receiveTuple) (tuple, attrtype, destfunc);
1004 1005
	IncrRetrieved();
	(estate->es_processed)++;
1006 1007 1008
}

/* ----------------------------------------------------------------
1009
 *		ExecAppend
1010
 *
1011 1012 1013
 *		APPENDs are trickier.. we have to insert the tuple into
 *		the base relation and insert appropriate tuples into the
 *		index relations.
1014 1015 1016 1017
 * ----------------------------------------------------------------
 */

static void
1018
ExecAppend(TupleTableSlot *slot,
1019
		   ItemPointer tupleid,
1020
		   EState *estate)
1021
{
1022 1023 1024 1025 1026
	HeapTuple	tuple;
	RelationInfo *resultRelationInfo;
	Relation	resultRelationDesc;
	int			numIndices;
	Oid			newId;
1027

1028
	/******************
1029
	 *	get the heap tuple out of the tuple table slot
1030
	 ******************
1031 1032 1033
	 */
	tuple = slot->val;

1034
	/******************
1035
	 *	get information on the result relation
1036
	 ******************
1037 1038 1039 1040
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

1041
	/******************
1042 1043
	 *	have to add code to preform unique checking here.
	 *	cim -12/1/89
1044
	 ******************
1045 1046 1047 1048 1049 1050
	 */

	/* BEFORE ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
	{
1051
		HeapTuple	newtuple;
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065

		newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);

		if (newtuple == NULL)	/* "do nothing" */
			return;

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
			pfree(tuple);
			slot->val = tuple = newtuple;
		}
	}

1066
	/******************
1067
	 * Check the constraints of a tuple
1068
	 ******************
1069 1070 1071 1072
	 */

	if (resultRelationDesc->rd_att->constr)
	{
1073
		ExecConstraints("ExecAppend", resultRelationDesc, tuple);
1074 1075
	}

1076
	/******************
1077
	 *	insert the tuple
1078
	 ******************
1079 1080 1081 1082 1083
	 */
	newId = heap_insert(resultRelationDesc,		/* relation desc */
						tuple); /* heap tuple */
	IncrAppended();

1084
	/******************
1085 1086 1087 1088 1089
	 *	process indices
	 *
	 *	Note: heap_insert adds a new tuple to a relation.  As a side
	 *	effect, the tupleid of the new tuple is placed in the new
	 *	tuple's t_ctid field.
1090
	 ******************
1091 1092 1093
	 */
	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1094
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
1095 1096 1097 1098 1099 1100 1101
	(estate->es_processed)++;
	estate->es_lastoid = newId;

	/* AFTER ROW INSERT Triggers */
	if (resultRelationDesc->trigdesc &&
	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
		ExecARInsertTriggers(resultRelationDesc, tuple);
1102 1103 1104
}

/* ----------------------------------------------------------------
1105
 *		ExecDelete
1106
 *
1107 1108
 *		DELETE is like append, we delete the tuple and its
 *		index tuples.
1109 1110 1111
 * ----------------------------------------------------------------
 */
static void
1112
ExecDelete(TupleTableSlot *slot,
1113
		   ItemPointer tupleid,
1114
		   EState *estate)
1115
{
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1116 1117 1118 1119
	RelationInfo	   *resultRelationInfo;
	Relation			resultRelationDesc;
	ItemPointerData		ctid;
	int					result;
1120

1121
	/******************
1122
	 *	get the result relation information
1123
	 ******************
1124 1125 1126 1127 1128 1129 1130 1131
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

	/* BEFORE ROW DELETE Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
	{
1132
		bool		dodelete;
1133

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1134
		dodelete = ExecBRDeleteTriggers(estate, tupleid);
1135 1136 1137 1138 1139

		if (!dodelete)			/* "do nothing" */
			return;
	}

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1140
	/*
1141 1142
	 *	delete the tuple
	 */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
	result = heap_delete(resultRelationDesc, tupleid, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1153 1154
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1155 1156 1157 1158 1159 1160 1161 1162
			else
				elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_delete", result);
			return;
	}
1163 1164 1165 1166

	IncrDeleted();
	(estate->es_processed)++;

1167
	/******************
1168 1169 1170 1171 1172 1173 1174 1175
	 *	Note: Normally one would think that we have to
	 *		  delete index tuples associated with the
	 *		  heap tuple now..
	 *
	 *		  ... but in POSTGRES, we have no need to do this
	 *		  because the vacuum daemon automatically
	 *		  opens an index scan and deletes index tuples
	 *		  when it finds deleted heap tuples. -cim 9/27/89
1176
	 ******************
1177 1178 1179 1180 1181
	 */

	/* AFTER ROW DELETE Triggers */
	if (resultRelationDesc->trigdesc &&
	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1182
		ExecARDeleteTriggers(estate, tupleid);
1183 1184 1185 1186

}

/* ----------------------------------------------------------------
1187
 *		ExecReplace
1188
 *
1189 1190 1191 1192 1193 1194
 *		note: we can't run replace queries with transactions
 *		off because replaces are actually appends and our
 *		scan will mistakenly loop forever, replacing the tuple
 *		it just appended..	This should be fixed but until it
 *		is, we don't want to get stuck in an infinite loop
 *		which corrupts your database..
1195 1196 1197
 * ----------------------------------------------------------------
 */
static void
1198
ExecReplace(TupleTableSlot *slot,
1199
			ItemPointer tupleid,
1200 1201
			EState *estate,
			Query *parseTree)
1202
{
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1203 1204 1205 1206 1207 1208
	HeapTuple			tuple;
	RelationInfo	   *resultRelationInfo;
	Relation			resultRelationDesc;
	ItemPointerData		ctid;
	int					result;
	int					numIndices;
1209

1210
	/******************
1211
	 *	abort the operation if not running transactions
1212
	 ******************
1213 1214 1215 1216 1217 1218 1219
	 */
	if (IsBootstrapProcessingMode())
	{
		elog(DEBUG, "ExecReplace: replace can't run without transactions");
		return;
	}

1220
	/******************
1221
	 *	get the heap tuple out of the tuple table slot
1222
	 ******************
1223 1224 1225
	 */
	tuple = slot->val;

1226
	/******************
1227
	 *	get the result relation information
1228
	 ******************
1229 1230 1231 1232
	 */
	resultRelationInfo = estate->es_result_relation_info;
	resultRelationDesc = resultRelationInfo->ri_RelationDesc;

1233
	/******************
1234 1235 1236 1237
	 *	have to add code to preform unique checking here.
	 *	in the event of unique tuples, this becomes a deletion
	 *	of the original tuple affected by the replace.
	 *	cim -12/1/89
1238
	 ******************
1239 1240 1241 1242 1243 1244
	 */

	/* BEFORE ROW UPDATE Triggers */
	if (resultRelationDesc->trigdesc &&
	resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
	{
1245
		HeapTuple	newtuple;
1246

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1247
		newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259

		if (newtuple == NULL)	/* "do nothing" */
			return;

		if (newtuple != tuple)	/* modified by Trigger(s) */
		{
			Assert(slot->ttc_shouldFree);
			pfree(tuple);
			slot->val = tuple = newtuple;
		}
	}

1260
	/******************
1261
	 * Check the constraints of a tuple
1262
	 ******************
1263 1264 1265 1266
	 */

	if (resultRelationDesc->rd_att->constr)
	{
1267
		ExecConstraints("ExecReplace", resultRelationDesc, tuple);
1268 1269
	}

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1270
	/*
1271 1272
	 *	replace the heap tuple
	 */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
	result = heap_replace(resultRelationDesc, tupleid, tuple, &ctid);
	switch (result)
	{
		case HeapTupleSelfUpdated:
			return;

		case HeapTupleMayBeUpdated:
			break;

		case HeapTupleUpdated:
1283 1284
			if (XactIsoLevel == XACT_SERIALIZABLE)
				elog(ERROR, "Can't serialize access due to concurrent update");
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1285 1286 1287 1288 1289 1290 1291
			else
				elog(ERROR, "Isolation level %u is not supported", XactIsoLevel);
			return;

		default:
			elog(ERROR, "Unknown status %u from heap_replace", result);
			return;
1292 1293 1294 1295 1296
	}

	IncrReplaced();
	(estate->es_processed)++;

1297
	/******************
1298 1299 1300 1301 1302 1303 1304
	 *	Note: instead of having to update the old index tuples
	 *		  associated with the heap tuple, all we do is form
	 *		  and insert new index tuples..  This is because
	 *		  replaces are actually deletes and inserts and
	 *		  index tuple deletion is done automagically by
	 *		  the vaccuum deamon.. All we do is insert new
	 *		  index tuples.  -cim 9/27/89
1305
	 ******************
1306 1307
	 */

1308
	/******************
1309 1310 1311 1312 1313 1314 1315
	 *	process indices
	 *
	 *	heap_replace updates a tuple in the base relation by invalidating
	 *	it and then appending a new tuple to the relation.	As a side
	 *	effect, the tupleid of the new tuple is placed in the new
	 *	tuple's t_ctid field.  So we now insert index tuples using
	 *	the new tupleid stored there.
1316
	 ******************
1317 1318 1319 1320
	 */

	numIndices = resultRelationInfo->ri_NumIndices;
	if (numIndices > 0)
1321
		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
1322 1323 1324 1325

	/* AFTER ROW UPDATE Triggers */
	if (resultRelationDesc->trigdesc &&
	 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1326
		ExecARUpdateTriggers(estate, tupleid, tuple);
1327
}
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1328

1329
#if 0
1330
static HeapTuple
1331
ExecAttrDefault(Relation rel, HeapTuple tuple)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1332
{
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
	int			ndef = rel->rd_att->constr->num_defval;
	AttrDefault *attrdef = rel->rd_att->constr->defval;
	ExprContext *econtext = makeNode(ExprContext);
	HeapTuple	newtuple;
	Node	   *expr;
	bool		isnull;
	bool		isdone;
	Datum		val;
	Datum	   *replValue = NULL;
	char	   *replNull = NULL;
	char	   *repl = NULL;
	int			i;
1345 1346 1347 1348 1349 1350

	econtext->ecxt_scantuple = NULL;	/* scan tuple slot */
	econtext->ecxt_innertuple = NULL;	/* inner tuple slot */
	econtext->ecxt_outertuple = NULL;	/* outer tuple slot */
	econtext->ecxt_relation = NULL;		/* relation */
	econtext->ecxt_relid = 0;	/* relid */
1351 1352
	econtext->ecxt_param_list_info = NULL;		/* param list info */
	econtext->ecxt_param_exec_vals = NULL;		/* exec param values */
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
	econtext->ecxt_range_table = NULL;	/* range table */
	for (i = 0; i < ndef; i++)
	{
		if (!heap_attisnull(tuple, attrdef[i].adnum))
			continue;
		expr = (Node *) stringToNode(attrdef[i].adbin);

		val = ExecEvalExpr(expr, econtext, &isnull, &isdone);

		pfree(expr);

		if (isnull)
			continue;

		if (repl == NULL)
		{
			repl = (char *) palloc(rel->rd_att->natts * sizeof(char));
			replNull = (char *) palloc(rel->rd_att->natts * sizeof(char));
			replValue = (Datum *) palloc(rel->rd_att->natts * sizeof(Datum));
Bruce Momjian's avatar
Bruce Momjian committed
1372
			MemSet(repl, ' ', rel->rd_att->natts * sizeof(char));
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
		}

		repl[attrdef[i].adnum - 1] = 'r';
		replNull[attrdef[i].adnum - 1] = ' ';
		replValue[attrdef[i].adnum - 1] = val;

	}

	pfree(econtext);

	if (repl == NULL)
1384
		return tuple;
1385

1386
	newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl);
1387 1388

	pfree(repl);
1389
	pfree(tuple);
1390 1391 1392
	pfree(replNull);
	pfree(replValue);

1393
	return newtuple;
1394

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1395
}
1396

1397
#endif
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1398

1399
static char *
1400
ExecRelCheck(Relation rel, HeapTuple tuple)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1401
{
1402 1403 1404
	int			ncheck = rel->rd_att->constr->num_check;
	ConstrCheck *check = rel->rd_att->constr->check;
	ExprContext *econtext = makeNode(ExprContext);
1405
	TupleTableSlot *slot = makeNode(TupleTableSlot);
1406 1407 1408 1409 1410
	RangeTblEntry *rte = makeNode(RangeTblEntry);
	List	   *rtlist;
	List	   *qual;
	bool		res;
	int			i;
1411 1412 1413 1414 1415 1416 1417 1418 1419

	slot->val = tuple;
	slot->ttc_shouldFree = false;
	slot->ttc_descIsNew = true;
	slot->ttc_tupleDescriptor = rel->rd_att;
	slot->ttc_buffer = InvalidBuffer;
	slot->ttc_whichplan = -1;
	rte->relname = nameout(&(rel->rd_rel->relname));
	rte->refname = rte->relname;
1420
	rte->relid = RelationGetRelid(rel);
1421 1422 1423 1424 1425 1426 1427 1428 1429
	rte->inh = false;
	rte->inFromCl = true;
	rtlist = lcons(rte, NIL);
	econtext->ecxt_scantuple = slot;	/* scan tuple slot */
	econtext->ecxt_innertuple = NULL;	/* inner tuple slot */
	econtext->ecxt_outertuple = NULL;	/* outer tuple slot */
	econtext->ecxt_relation = rel;		/* relation */
	econtext->ecxt_relid = 0;	/* relid */
	econtext->ecxt_param_list_info = NULL;		/* param list info */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1430
	econtext->ecxt_param_exec_vals = NULL;		/* exec param values */
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
	econtext->ecxt_range_table = rtlist;		/* range table */

	for (i = 0; i < ncheck; i++)
	{
		qual = (List *) stringToNode(check[i].ccbin);

		res = ExecQual(qual, econtext);

		pfree(qual);

		if (!res)
1442
			return check[i].ccname;
1443 1444 1445 1446 1447 1448 1449 1450
	}

	pfree(slot);
	pfree(rte->relname);
	pfree(rte);
	pfree(rtlist);
	pfree(econtext);

1451
	return (char *) NULL;
1452

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1453 1454
}

1455
void
1456
ExecConstraints(char *caller, Relation rel, HeapTuple tuple)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1457
{
1458 1459 1460 1461

	Assert(rel->rd_att->constr);

	if (rel->rd_att->constr->has_not_null)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1462
	{
1463
		int			attrChk;
1464 1465 1466 1467

		for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
		{
			if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
1468
				elog(ERROR, "%s: Fail to add null value in not null attribute %s",
1469 1470 1471 1472 1473 1474
				  caller, rel->rd_att->attrs[attrChk - 1]->attname.data);
		}
	}

	if (rel->rd_att->constr->num_check > 0)
	{
1475
		char	   *failed;
1476 1477

		if ((failed = ExecRelCheck(rel, tuple)) != NULL)
1478
			elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed);
1479 1480
	}

1481
	return;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
1482
}