head     1.12;
branch   ;
access   ;
symbols  Version_2_1:1.7;
locks    ; strict;
comment  @ * @;


1.12
date     91.11.18.22.21.22;  author mer;  state Exp;
branches ;
next     1.11;

1.11
date     91.05.09.18.11.05;  author sp;  state Exp;
branches ;
next     1.10;

1.10
date     91.05.01.02.51.14;  author cimarron;  state Exp;
branches ;
next     1.9;

1.9
date     91.04.11.21.34.47;  author sp;  state Exp;
branches ;
next     1.8;

1.8
date     91.04.08.18.15.49;  author sp;  state Exp;
branches ;
next     1.7;

1.7
date     91.02.24.12.43.21;  author sp;  state Exp;
branches ;
next     1.6;

1.6
date     91.01.17.19.09.05;  author sp;  state Exp;
branches ;
next     1.5;

1.5
date     91.01.09.19.11.08;  author sp;  state Exp;
branches ;
next     1.4;

1.4
date     90.10.16.17.21.53;  author sp;  state Exp;
branches ;
next     1.3;

1.3
date     90.09.25.16.43.27;  author kemnitz;  state Exp;
branches ;
next     1.2;

1.2
date     90.05.30.13.56.53;  author sp;  state Exp;
branches ;
next     1.1;

1.1
date     90.04.19.19.55.38;  author sp;  state Exp;
branches ;
next     ;


desc
@This is a bunch of routines used to deal with "view" rules,
i.e. rules of the form: ON RETRIEVE TO RELATION DO RETRIEVE ....
@


1.12
log
@prototypes finale
@
text
@/*========================================================================
 *
 * IDENTIFICATION:
 * 	$Header: /users/mer/postgres/src/rules/prs2/RCS/prs2view.c,v 1.11 1991/05/09 18:11:05 sp Exp mer $
 *
 * DESCRIPTION:
 * This file contains (among other things!) the code for 'view-like' rules,
 * i.e. rules that return many tuples at a time like:
 *	ON retrieve to <relation>
 *      DO [ instead ] retrieve ......
 *
 * (if we specify a 'instead' then this is a virtual view,
 * otherwise it might be partially materialized)
 *
 *
 *========================================================================
 */

#include <stdio.h>
#include "utils/log.h"
#include "executor/execdefs.h"
#include "rules/prs2locks.h"
#include "rules/prs2.h"
#include "rules/prs2stub.h"
#include "nodes/execnodes.h"
#include "parser/parse.h"	/* for RETRIEVE, APPEND etc. */
#include "utils/palloc.h"

extern EState CreateExecutorState();
extern LispValue ExecMain();

/*-----------------------------------------------------------------------
 * prs2MakeRelationRuleInfo(relation)
 *
 * This initializes some information about the rules affecting a
 * relation.
 *
 * There are 2 places where this routine can be called:
 *
 * A) by 'ExecInitSeqScan' and 'ExecInitIndexScan'
 * when the 'ScanState' of a 'Scan' node is intialized.
 * In this case `operation' must be RETRIEVE
 *
 * B) by InitPlan when we have an update plan (i.e. a delete, append
 * or a replace command). In this case the 'operation' must be
 * APPEND, DELETE or REPLaCE.
 * 
 * This scan state contains among other things some information
 * needed by the rule manager. See commnets in the definition of the
 * 'RelationRuleInfo' struct for more details....
 *
 */
RelationRuleInfo
prs2MakeRelationRuleInfo(relation, operation)
Relation relation;
int operation;
{
    RuleLock locks;
    Name relationName;
    int i, j, nlocks;
    Prs2OneLock oneLock;
    Prs2LockType lockType;
    ObjectId ruleId;
    Prs2PlanNumber planNo;
    long size;
    int nrules;
    Prs2RuleList  ruleList, ruleListItem;
    Prs2Stub stubs;
    RelationRuleInfo relationRuleInfo;


    /*
     * find the locks of the relation...
     */
    relationName = RelationGetRelationName(relation);
    locks = prs2GetLocksFromRelation(relationName);

    /*
     * create a linked list of all the rule ids that hold a
     * 'LockTypeRetrieveRelation'
     */
    ruleList = NULL;
    if (operation == RETRIEVE) {
	nlocks = prs2GetNumberOfLocks(locks);
	for (i=0; i<nlocks ; i++) {
	    oneLock = prs2GetOneLockFromLocks(locks, i);
	    lockType = prs2OneLockGetLockType(oneLock);
	    ruleId = prs2OneLockGetRuleId(oneLock);
	    planNo = prs2OneLockGetPlanNumber(oneLock);
	    if (lockType==LockTypeRetrieveRelation) {
		ruleListItem = (Prs2RuleList) palloc(sizeof(Prs2RuleListItem));
		if (ruleListItem == NULL) {
		    elog(WARN,"prs2MakeRuleList: Out of memory");
		}
		ruleListItem->type = PRS2_RULELIST_RULEID;
		ruleListItem->data.ruleId.ruleId = ruleId;
		ruleListItem->data.ruleId.planNumber = planNo;
		ruleListItem->next = ruleList;
		ruleList = ruleListItem;
	    }
	}
    }

    /*
     * now find the relation level rule stubs.
     */
    stubs = prs2GetRelationStubs(RelationGetRelationId(relation));

    /*
     * Create and return a 'RelationRuleInfo' structure..
     */
    size = sizeof(RelationRuleInfoData);
    relationRuleInfo = (RelationRuleInfo) palloc(size);
    if (relationRuleInfo == NULL) {
	elog(WARN,
	    "prs2MakeRelationRuleInfo: Out of memory! (%ld bytes requested)",
	    size);
    }

    relationRuleInfo->ruleList = ruleList;
    relationRuleInfo->insteadViewRuleFound = false;
    relationRuleInfo->relationLocks = locks;
    relationRuleInfo->relationStubs = stubs;
    relationRuleInfo->relationStubsHaveChanged = false;

    /*
     * if this is the "pg_class" then ignore all tuple level locks
     * found in tuples, because these locks are not "real" tuple level
     * locks of rules defined in "pg_class", but they are relation level
     * locks defined on various other relations.
     */
    if (!strcmp(relationName, Name_pg_relation))
	relationRuleInfo->ignoreTupleLocks = true;
    else
	relationRuleInfo->ignoreTupleLocks = false;

    return(relationRuleInfo);

}

/*-----------------------------------------------------------------------
 *
 * prs2GetOneTupleFromViewRules
 */
HeapTuple
prs2GetOneTupleFromViewRules(relationRuleInfo, prs2EStateInfo, relation,
			    explainRel)
RelationRuleInfo relationRuleInfo;
Prs2EStateInfo prs2EStateInfo;
Relation relation;
Relation explainRel;
{

    long size;
    Prs2RuleList tempRuleList, tempRuleListItem;
    ParamListInfo paramList;
    LispValue plan, ruleInfo, planQual, planActions, onePlan;
    LispValue queryDesc;
    EState executorState;
    LispValue res;
    HeapTuple tuple;


    /*
     * Process the first record of 'ruleList',
     * until either the lsit becomes empty, or
     * a new tuple is created....
     */
    while(relationRuleInfo->ruleList != NULL) {
	switch (relationRuleInfo->ruleList->type) {
	    case PRS2_RULELIST_RULEID:
		/*
		 * Fetch the plan from Prs2PlansRelation.
		 */
		plan = prs2GetRulePlanFromCatalog(
			    relationRuleInfo->ruleList->data.ruleId.ruleId,
			    relationRuleInfo->ruleList->data.ruleId.planNumber,
			    &paramList);
		/*
		 * It is possible that plan = nil (an obsolete rule?)
		 * In this case ignore the rule.
		 */
		if (null(plan)) {
		    break;
		}
		/*
		 * NOTE: the `paramList' must be empty!
		 * because we do not allow 'NEW' & 'OLD' in 'view-like' rules.
		 * Note though, that the rule qualification might not
		 * be empty. E.g. it might be something like:
		 *       where user() == "Spyros the Great"
		 */
		if (paramList != NULL && paramList[0].kind != PARAM_INVALID) {
		    elog(WARN, "View Rules must not have parameters!\n");
		}
		ruleInfo = prs2GetRuleInfoFromActionPlan(plan);
		planQual = prs2GetQualFromActionPlan(plan);
		planActions = prs2GetActionsFromActionPlan(plan);
		/*
		 * test the rule qualification and if true, then
		 * for every plan specified in the action part of the
		 * rule, create a Prs2RuleListItem and insert it
		 * in a linked list.
		 */
		if (prs2CheckQual(planQual, paramList, prs2EStateInfo)) {
		    tempRuleList = relationRuleInfo->ruleList->next;
		    foreach(onePlan, planActions) {
			size = sizeof(Prs2RuleListItem);
			tempRuleListItem = (Prs2RuleList) palloc(size);
			if (tempRuleListItem == NULL) {
			    elog(WARN,
			    "prs2GetOneTupleFromViewRules: Out of memory");
			}
			tempRuleListItem->type = PRS2_RULELIST_PLAN;
			tempRuleListItem->data.rulePlan.plan = CAR(onePlan);
			tempRuleListItem->next = tempRuleList;
			tempRuleList = tempRuleListItem;
		    }
		    /*
		     * no more action plans for this rule.
		     * replace the Prs2RuleListItem of theis rule with
		     * the chain of Prs2RuleListItem(s) we have just
		     * created.
		     */
		    tempRuleListItem = relationRuleInfo->ruleList;
		    relationRuleInfo->ruleList = tempRuleList;
		    pfree((Pointer)tempRuleListItem);
		    /*
		     * check for 'instead' rules...
		     */
		    if (prs2IsRuleInsteadFromRuleInfo(ruleInfo)) {
			relationRuleInfo->insteadViewRuleFound = true;
		    }
		}
		break;
	    case PRS2_RULELIST_PLAN:
		/*
		 * this is a rule plan. COnstruct the query descriptor,
		 * the EState, and call the executor to perform the
		 * EXEC_START operation...
		 */
		queryDesc = prs2MakeQueryDescriptorFromPlan(
			    relationRuleInfo->ruleList->data.rulePlan.plan);
		executorState = CreateExecutorState();
		set_es_param_list_info(executorState, paramList);
		set_es_prs2_info(executorState, prs2EStateInfo);
		ExecMain(queryDesc, executorState,
			lispCons(lispInteger(EXEC_START), LispNil));
		size = sizeof(Prs2RuleListItem);
		tempRuleList = (Prs2RuleList) palloc(size);
		if (tempRuleList == NULL) {
		    elog(WARN,
		    "prs2GetOneTupleFromViewRules: Out of memory");
		}
		tempRuleList->type = PRS2_RULELIST_QUERYDESC;
		tempRuleList->data.queryDesc.queryDesc = queryDesc;
		/*
		 * NOTE: the following typecast is due to a stupid
		 * circular dependency in the definitions of `EState' and
		 * `Prs2RuleList' which obliged me to declare 
		 * `Prs2RuleList->data.queryDesc.estate' not as an `EState'
		 * (which is the correct) but as a (struct *). Argh!
		 */
		tempRuleList->data.queryDesc.estate = (Pointer) executorState;
		tempRuleList->next = relationRuleInfo->ruleList->next;
		tempRuleListItem = relationRuleInfo->ruleList;
		relationRuleInfo->ruleList = tempRuleList;
		pfree((Pointer)tempRuleListItem);
		break;
	    case PRS2_RULELIST_QUERYDESC:
		/*
		 * At last! a query desciptor (and an EState!)
		 * properly initialized...
		 * Call exec main to retrieve a tuple...
		 */
		res = ExecMain(
			relationRuleInfo->ruleList->data.queryDesc.queryDesc,
			relationRuleInfo->ruleList->data.queryDesc.estate,
			lispCons(lispInteger(EXEC_RETONE), LispNil));
		tuple = (HeapTuple) ExecFetchTuple((TupleTableSlot)res);
		if (tuple != NULL) {
		    /*
		     * Yeahhh! the executor returned a tuple!
		     *
		     * Make a COPY of this tuple
		     * we need to make a copy for 2 reasons:
		     * a) the (low level) executor might release it when
		     *    called with EXEC_END
		     * b) the top level executor might want to pfree it
		     *    and pfree seems to complain (I guess something
		     *    to do with the fact that this palloc happenned
		     *    in the lower executor's context and not in
		     *    the current one...
		     */
		    tuple = palloctup(tuple, InvalidBuffer, relation);
		    return(tuple);
		}
		/*
		 * No more tuples! Remove this record from the
		 * relationRuleInfo->ruleList.
		 * But before doing that, be nice and gracefully
		 * let the executor release whatever it has to...
		 */
		ExecMain(relationRuleInfo->ruleList->data.queryDesc.queryDesc,
			    relationRuleInfo->ruleList->data.queryDesc.estate,
			    lispCons(lispInteger(EXEC_END), LispNil));
		tempRuleList = relationRuleInfo->ruleList;
		relationRuleInfo->ruleList = relationRuleInfo->ruleList->next;
		pfree((Pointer)tempRuleList);
		break;
	} /* switch */
    } /* while */

    /*
     * No (more) rules found, return NULL
     */
    return(NULL);
}
@


1.11
log
@Ignore the tuple locks if 'RelationRuleInfo->ignoreTupleLocks'
is true (which happens if the relation currently being scanned
is "pg_class").
@
text
@d4 1
a4 1
 * 	$Header: RCS/prs2view.c,v 1.10 91/05/01 02:51:14 cimarron Exp Locker: sp $
d227 1
a227 1
		    pfree(tempRuleListItem);
d268 1
a268 1
		pfree(tempRuleListItem);
d309 1
a309 1
		pfree(tempRuleList);
@


1.10
log
@round II of converting simple functions to macros + code cleaning in general
@
text
@d4 1
a4 1
 * 	$Header: RCS/prs2view.c,v 1.9 91/04/11 21:34:47 sp Exp Locker: cimarron $
d125 11
@


1.9
log
@ScanStateRuleInfo has been renamed to RelationRuleInfo,
and is also used for the result relation.
prs2MakeRelationRuleInfo takes an extra argument specifying the kind
of operation to be performed in the relation (RETRIEVE, APPEND etc.)
@
text
@d4 1
a4 1
 * 	$Header: RCS/prs2view.c,v 1.8 91/04/08 18:15:49 sp Exp $
a30 1
extern HeapTuple palloctup();
@


1.8
log
@misc changes to support locking more than one path in the rule
qualification's tree...
@
text
@d4 1
a4 1
 * 	$Header: RCS/prs2view.c,v 1.7 91/02/24 12:43:21 sp Exp Locker: sp $
d26 1
d34 1
a34 1
 * prs2MakeScanStateRuleInfo(relation)
d36 6
a41 1
 * This routine is called by 'ExecInitSeqScan' and 'ExecInitIndexScan'
d43 6
d51 1
a51 1
 * 'ScanStateRuleInfo' struct for more details....
d54 2
a55 2
ScanStateRuleInfo
prs2MakeScanStateRuleInfo(relation)
d57 1
d69 2
a70 1
    ScanStateRuleInfo scanStateRuleInfo;
d84 17
a100 10
    nlocks = prs2GetNumberOfLocks(locks);
    for (i=0; i<nlocks ; i++) {
        oneLock = prs2GetOneLockFromLocks(locks, i);
        lockType = prs2OneLockGetLockType(oneLock);
        ruleId = prs2OneLockGetRuleId(oneLock);
	planNo = prs2OneLockGetPlanNumber(oneLock);
        if (lockType==LockTypeRetrieveRelation) {
	    ruleListItem = (Prs2RuleList) palloc(sizeof(Prs2RuleListItem));
	    if (ruleListItem == NULL) {
		elog(WARN,"prs2MakeRuleList: Out of memory");
a101 5
	    ruleListItem->type = PRS2_RULELIST_RULEID;
	    ruleListItem->data.ruleId.ruleId = ruleId;
	    ruleListItem->data.ruleId.planNumber = planNo;
	    ruleListItem->next = ruleList;
	    ruleList = ruleListItem;
d106 1
a106 1
     * Create and return a 'ScanStateRuleInfo' structure..
d108 8
a115 3
    size = sizeof(ScanStateRuleInfoData);
    scanStateRuleInfo = (ScanStateRuleInfo) palloc(size);
    if (scanStateRuleInfo == NULL) {
d117 1
a117 1
	    "prs2MakeScanStateRuleInfo: Out of memory! (%ld bytes requested)",
d121 5
a125 6
    scanStateRuleInfo->ruleList = ruleList;
    scanStateRuleInfo->insteadRuleFound = false;
    scanStateRuleInfo->relationLocks = locks;
    scanStateRuleInfo->relationStubs =
	prs2GetRelationStubs(RelationGetRelationId(relation));
    scanStateRuleInfo->relationStubsHaveChanged = false;
d127 1
a127 1
    return(scanStateRuleInfo);
d136 1
a136 1
prs2GetOneTupleFromViewRules(scanStateRuleInfo, prs2EStateInfo, relation,
d138 1
a138 1
ScanStateRuleInfo scanStateRuleInfo;
d159 2
a160 2
    while(scanStateRuleInfo->ruleList != NULL) {
	switch (scanStateRuleInfo->ruleList->type) {
d166 2
a167 2
			    scanStateRuleInfo->ruleList->data.ruleId.ruleId,
			    scanStateRuleInfo->ruleList->data.ruleId.planNumber,
d196 1
a196 1
		    tempRuleList = scanStateRuleInfo->ruleList->next;
d215 2
a216 2
		    tempRuleListItem = scanStateRuleInfo->ruleList;
		    scanStateRuleInfo->ruleList = tempRuleList;
d222 1
a222 1
			scanStateRuleInfo->insteadRuleFound = true;
d233 1
a233 1
			    scanStateRuleInfo->ruleList->data.rulePlan.plan);
d254 4
a257 5
		tempRuleList->data.queryDesc.estate =
			(struct EState *)executorState;
		tempRuleList->next = scanStateRuleInfo->ruleList->next;
		tempRuleListItem = scanStateRuleInfo->ruleList;
		scanStateRuleInfo->ruleList = tempRuleList;
d267 2
a268 2
			scanStateRuleInfo->ruleList->data.queryDesc.queryDesc,
			scanStateRuleInfo->ruleList->data.queryDesc.estate,
d290 1
a290 1
		 * scanStateRuleInfo->ruleList.
d294 2
a295 2
		ExecMain(scanStateRuleInfo->ruleList->data.queryDesc.queryDesc,
			    scanStateRuleInfo->ruleList->data.queryDesc.estate,
d297 2
a298 2
		tempRuleList = scanStateRuleInfo->ruleList;
		scanStateRuleInfo->ruleList = scanStateRuleInfo->ruleList->next;
@


1.7
log
@nothing important -- just rearranged some comments...
@
text
@d4 1
a4 1
 * 	$Header: RCS/prs2view.c,v 1.6 91/01/17 19:09:05 sp Exp $
d67 1
a67 1
     * 'LockTypeTupleRetrieveRelation'
d76 1
a76 1
        if (lockType==LockTypeTupleRetrieveRelation) {
d166 3
a168 3
		ruleInfo = prs2GetRuleInfoFromRulePlan(plan);
		planQual = prs2GetQualFromRulePlan(plan);
		planActions = prs2GetActionsFromRulePlan(plan);
@


1.6
log
@do not bomb if you can not find a rule plan (just ignore the rule).
@
text
@d1 1
a1 13
#include <stdio.h>
#include "utils/log.h"
#include "executor/execdefs.h"
#include "rules/prs2locks.h"
#include "rules/prs2.h"
#include "rules/prs2stub.h"
#include "nodes/execnodes.h"

extern EState CreateExecutorState();
extern LispValue ExecMain();
extern HeapTuple palloctup();

/*------------------------------------------------------------------------
d4 1
a4 1
 * 	$Header: RCS/prs2view.c,v 1.5 91/01/09 19:11:08 sp Exp $
d16 1
d18 13
@


1.5
log
@Ooops! 'scanStateRuleInfo->relationStubsHaveChanged' was incorrectly
initialized.
@
text
@d16 1
a16 1
 * 	$Header: RCS/prs2view.c,v 1.4 90/10/16 17:21:53 sp Exp $
d147 7
@


1.4
log
@changes because the executor returns a tuple slot & not a tuple.
@
text
@d16 1
a16 1
 * 	$Header: RCS/prs2view.c,v 1.3 90/09/25 16:43:27 kemnitz Exp $
d103 1
a103 1
    scanStateRuleInfo->relationStubsHaveChanged = true;
@


1.3
log
@Updating from revision 1.2 to revision 1.5
@
text
@d11 1
d16 1
a16 1
 * 	$Header: RCS/prs2view.c,v 1.5 90/08/13 20:30:16 sp Exp $
d114 2
a115 1
prs2GetOneTupleFromViewRules(scanStateRuleInfo, prs2EStateInfo, explainRel)
d118 1
d242 2
a243 1
		if (!null(res)) {
d246 10
d257 1
a257 1
		    tuple = (HeapTuple) CAR(res);
@


1.2
log
@added a typecast so that cc does not complain about an illegal pointer
combination.
@
text
@d2 6
a7 5
#include "log.h"
#include "execdefs.h"
#include "prs2locks.h"
#include "prs2.h"
#include "execnodes.h"
d15 1
a15 1
 * 	$Header: RCS/prs2view.c,v 1.1 90/04/19 19:55:38 sp Exp Locker: sp $
d64 1
a64 1
     * 'LockTypeRetrieveRelation'
d73 1
a73 1
        if (lockType==LockTypeRetrieveRelation) {
d100 3
@


1.1
log
@Initial revision
@
text
@d14 1
a14 1
 * 	$Header: $
d211 9
a219 1
		tempRuleList->data.queryDesc.estate = executorState;
@
