head	1.26;
access;
symbols
	Version_2_1:1.15;
locks; strict;
comment	@ * @;


1.26
date	92.07.08.20.51.28;	author joey;	state Exp;
branches;
next	1.25;

1.25
date	92.07.04.04.37.49;	author mer;	state Exp;
branches;
next	1.24;

1.24
date	92.05.05.01.01.08;	author mer;	state Exp;
branches;
next	1.23;

1.23
date	92.03.25.17.30.55;	author hong;	state Exp;
branches;
next	1.22;

1.22
date	91.11.18.22.21.22;	author mer;	state Exp;
branches;
next	1.21;

1.21
date	91.05.09.18.08.46;	author sp;	state Exp;
branches;
next	1.20;

1.20
date	91.05.03.16.20.05;	author cimarron;	state Exp;
branches;
next	1.19;

1.19
date	91.04.19.05.38.16;	author kemnitz;	state Exp;
branches;
next	1.18;

1.18
date	91.04.10.16.09.23;	author sp;	state Exp;
branches;
next	1.17;

1.17
date	91.04.08.18.14.21;	author sp;	state Exp;
branches;
next	1.16;

1.16
date	91.03.28.14.26.51;	author sp;	state Exp;
branches;
next	1.15;

1.15
date	91.02.25.16.54.02;	author sp;	state Exp;
branches;
next	1.14;

1.14
date	91.02.24.12.39.57;	author sp;	state Exp;
branches;
next	1.13;

1.13
date	91.01.09.19.07.12;	author sp;	state Exp;
branches;
next	1.12;

1.12
date	90.10.25.21.03.59;	author goh;	state Exp;
branches;
next	1.11;

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

1.10
date	90.10.16.17.18.13;	author sp;	state Exp;
branches;
next	1.9;

1.9
date	90.10.10.18.58.00;	author hong;	state Exp;
branches;
next	1.8;

1.8
date	90.09.25.16.42.27;	author kemnitz;	state Exp;
branches;
next	1.7;

1.7
date	90.06.09.18.45.15;	author kemnitz;	state Exp;
branches;
next	1.6;

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

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

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

1.3
date	90.04.03.17.11.43;	author sp;	state Exp;
branches;
next	1.2;

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

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


desc
@rule definition/removal code
@


1.26
log
@set up resdom->rescomplex correctly
@
text
@/*-----------------------------------------------------------------------
 * FILE:
 *   prs2define.c
 *
 * IDENTIFICATION:
 *   $Header: /private/joey/pg/src/rules/prs2/RCS/prs2define.c,v 1.25 1992/07/04 04:37:49 mer Exp joey $
 *
 * DESCRIPTION:
 *   All the routines needed to define a (tuple level) PRS2 rule
 */

#include "tmp/postgres.h"
#include "nodes/primnodes.h"
#include "nodes/primnodes.a.h"
#include "nodes/pg_lisp.h"
#include "utils/log.h"
#include "utils/relcache.h"	/* RelationNameGetRelation() defined here...*/
#include "rules/prs2.h"
#include "access/skey.h"	/* 'ScanKeyEntryData' defined here... */
#include "access/tqual.h"	/* 'NowTimeQual' defined here.. */
#include "access/heapam.h"	/* heap AM calls defined here */
#include "utils/lsyscache.h"	/* get_attnum()  defined here...*/
#include "parser/parse.h"	/* RETRIEVE, APPEND etc defined here.. */
#include "parser/parsetree.h"
#include "catalog/catname.h"	/* names of various system relations */
#include "utils/fmgr.h"	/* for F_CHAR16EQ, F_CHAR16IN etc. */
#include "access/ftup.h"	/* for FormHeapTuple() */
#include "utils/palloc.h"

#include "catalog/pg_proc.h"
#include "catalog/pg_prs2rule.h"
#include "catalog/pg_prs2plans.h"

extern LispValue planner();
extern LispValue lispCopy();


/*-----------------------------------------------------------------------
 *
 * prs2DefineTupleRule
 *
 * Define a tuple-level rule. This is the high-level interface.
 *
 *-----------------------------------------------------------------------
 */

void
prs2DefineTupleRule(parseTree, ruleText)
LispValue parseTree;
char *ruleText;
{

    Prs2RuleData ruleData;
    List hint;

#ifdef PRS2_DEBUG
    printf("PRS2: ---prs2DefineTupleRule called, with argument =");
    lispDisplay(parseTree);
    printf("\n");
    printf("PRS2:   ruletext = %s\n", ruleText);
#endif PRS2_DEBUG
    
    /*
     * find the rule "hint", i.e. see if the user explicitly
     * stated what kind of lock he/she/it/ wnated to use.
     */
    hint = GetRuleHintFromParse(parseTree);
    
    /*
     * extract some rule info form the parsetree...
     */
    ruleData = prs2FindRuleData(parseTree, ruleText);

    /*
     * now put locks/stubs and update system catalogs...
     */
    prs2AddTheNewRule(ruleData, hint);

#ifdef PRS2_DEBUG
    printf("PRS2: --- DEFINE PRS2 RULE: Done.\n");
#endif PRS2_DEBUG
}

/*-----------------------------------------------------------------------
 * prs2RemoveTupleRule
 *
 * Remove a tuple-system rule given its name.
 *
 *-----------------------------------------------------------------------
 */
void
prs2RemoveTupleRule(ruleName)
Name ruleName;
{
    ObjectId ruleId;

    /*
     * first find its oid & then remove it...
     */
    ruleId = get_ruleid(ruleName);
    if (ruleId == InvalidObjectId) {
	elog(WARN, "Rule '%s' does not exist!", ruleName);
    }

    prs2DeleteTheOldRule(ruleId);
}

/*-----------------------------------------------------------------------
 * prs2FindRuleData
 *
 * create a 'Prs2RuleData' struct & fill it with all the information
 * about this rule we will ever need to know...
 *
 *-----------------------------------------------------------------------
 */
Prs2RuleData
prs2FindRuleData(parseTree, ruleText)
List parseTree;
char *ruleText;
{
    Prs2RuleData r;
    List eventTarget;
    Relation rel;
    bool newUsed, currentUsed;

    /*
     * create the structure where we hold all the rule
     * information we need to know...
     */
    r = (Prs2RuleData) palloc(sizeof(Prs2RuleDataData));
    if (r==NULL) {
	elog(WARN, "prs2FindRuleInfo: Out of memory");
    }
    r->ruleName = (Name) palloc(sizeof(NameData));
    if (r->ruleName == NULL) {
	elog(WARN, "prs2FindRuleInfo: Out of memory");
    }
    r->eventRelationName = (Name) palloc(sizeof(NameData));
    if (r->eventRelationName == NULL) {
	elog(WARN, "prs2FindRuleInfo: Out of memory");
    }
    r->eventAttributeName = (Name) palloc(sizeof(NameData));
    if (r->eventAttributeName == NULL) {
	elog(WARN, "prs2FindRuleInfo: Out of memory");
    }
    
    /*
     * start filling it in...
     * NOTE: we do not know yet the rule oid...
     */
    r->ruleId = InvalidObjectId;
    r->parseTree = parseTree;
    r->ruleText = ruleText;
    strcpy(r->ruleName->data, CString(GetRuleNameFromParse(parseTree)));

    if  (CInteger(GetRuleInsteadFromParse(parseTree)) != 0)
	r->isInstead = true;
    else
	r->isInstead = false;
    r->eventType = prs2FindEventTypeFromParse(parseTree);

    /*
     * 
     * Find the OID of the relation to be locked, and the
     * attribute number of the locked attribute. If no such 
     * attribute has been specified, use 'InvalidAttributeNumber'
     * instead.
     *
     * NOTE: 'eventTarget' is a list of one or two items.
     * The first one is the name of the relation and the optional second
     * one is the attribute name
     *
     * XXX: this should change in the future! It would be better
     * that the parser will return a list with the relation OID
     * and the attibute number instead of their names!
     */
    eventTarget = GetRuleEventTargetFromParse(parseTree);
    strcpy(r->eventRelationName->data, CString(CAR(eventTarget)));
    rel = RelationNameGetRelation(r->eventRelationName);
    r->eventRelationOid = rel->rd_id;
    if (null(CDR(eventTarget))) {
	/*
	 * no attribute is specified
	 */
	r->eventAttributeNumber = InvalidAttributeNumber;
	r->eventAttributeName = NULL;
    } else {
	strcpy(r->eventAttributeName->data, CString(CADR(eventTarget)));
	r->eventAttributeNumber = get_attnum(r->eventRelationOid,
					    r->eventAttributeName);
	if (r->eventAttributeNumber == InvalidAttributeNumber) {
	    elog(WARN,"Illegal attribute in event target list");
	}
	/*
	 * XXX currently we only allow tuple-level rules to
	 * be defined in attributes of basic types (i.e. not of type
	 * relation etc....)
	 */
	if (!prs2AttributeIsOfBasicType(r->eventRelationOid,
					r->eventAttributeNumber)) {
		elog(WARN,
		"Can not define tuple rules in non-base type attributes");
	}
	/*
	 * "on delete" and "on append" rules must not have an attribute
	 * specified in the event clause.
	 */
	if (r->eventType == EventTypeDelete)
	    elog(WARN,
	    "On Delete rules must not have an attribute in their event clause");
	if (r->eventType == EventTypeAppend)
	    elog(WARN,
	    "On Append rules must not have an attribute in their event clause");
    }

    /*
     * check if we use CURRENT on a 'on append' rule, or NEW
     * on a 'on retrieve' or 'on delete' rule.
     * If yes, then complain...
     */
    r->ruleQual = GetRuleQualFromParse(parseTree);
    r->ruleAction = GetRuleActionFromParse(parseTree);
    IsPlanUsingNewOrCurrent(r->ruleQual, &currentUsed, &newUsed);
    if (currentUsed && r->eventType == EventTypeAppend) {
	elog(WARN,
	    "An `on append' rule, can not reference the 'current' tuple");
    }
    if (newUsed && r->eventType == EventTypeRetrieve) {
	elog(WARN,
	    "An `on retrieve' rule, can not reference the 'new' tuple");
    }
    if (newUsed && r->eventType == EventTypeDelete) {
	elog(WARN,
	    "An `on delete' rule, can not reference the 'new' tuple");
    }
    IsPlanUsingNewOrCurrent(r->ruleAction, &currentUsed, &newUsed);
    if (currentUsed && r->eventType == EventTypeAppend) {
	elog(WARN,
	    "An `on append' rule, can not reference the 'current' tuple");
    }
    if (newUsed && r->eventType == EventTypeRetrieve) {
	elog(WARN,
	    "An `on retrieve' rule, can not reference the 'new' tuple");
    }
    if (newUsed && r->eventType == EventTypeDelete) {
	elog(WARN,
	    "An `on delete' rule, can not reference the 'new' tuple");
    }

    /*
     * The parsetree generated by the parser has a NEW and/or CURRENT
     * entries in the range table. In order to find the rule qualification
     * and the action plans to be executed at rule activation time,
     * we have to change all the corresponding "Var" nodes to the
     * appropriate "Param" nodes.
     * Note however, that we must also keep the original rule qualification 
     * (i.e. the one with the "Var" nodes) because it is needed to
     * calculate the appropriate stub records etc.
     * nodes to the equivalent
     */
    r->paramParseTree = lispCopy(parseTree);
    SubstituteParamForNewOrCurrent(r->paramParseTree, r->eventRelationOid);
    r->paramRuleQual = GetRuleQualFromParse(r->paramParseTree);
    r->paramRuleAction = GetRuleActionFromParse(r->paramParseTree);

    /*
     * Now, find the type of action. (i.e. ActionTypeRetrieve, 
     * ActionTypeReplaceCurrent or ActionTypeOther).
     * In the first 2 cases,  `updatedAttributeNumber' is the number
     * of attribute beeing updated.
     */
    r->actionType = prs2FindActionTypeFromParse(r->parseTree,
			r->eventAttributeNumber,
			&(r->updatedAttributeNumber),
			r->eventType);
    /*
     * Hm... for the time being we do NOT allow 
     *     ON RETRIEVE ... DO RETRIEVE ....
     * rules without an INSTEAD
     * unless this is a "view" rule (i.e. something
     * like "on retrieve to TOYEMP do retrieve...")
     * In this case the event target object must be a
     * relation and not a "relation.attribute"
     */
    if (!(r->isInstead) && r->actionType == ActionTypeRetrieveValue &&
	r->eventAttributeNumber != InvalidAttributeNumber ) {
	elog(WARN,
	"`on retrieve ... do retrieve' tuple rules must have an `instead'");
    }


#ifdef PRS2_DEBUG
    {
    printf("PRS2: ---DEFINE TUPLE RULE:\n");
    printf("PRS2:    RuleName = %s\n", r->ruleName->data);
    printf("PRS2:    event type = %d ", r->eventType);
    switch (r->eventType) {
	case EventTypeRetrieve:
	    printf("(retrieve)\n");
	    break;
	case EventTypeReplace:
	    printf("(replace)\n");
	    break;
	case EventTypeAppend:
	    printf("(append)\n");
	    break;
	case EventTypeDelete:
	    printf("(delete)\n");
	    break;
	default:
	    printf("(*** UNKNOWN ***)\n");
    }
    printf("PRS2:    event target:");
    lispDisplay(eventTarget);
    printf("\n");
    printf("PRS2:    event target relation OID = %ld\n", r->eventRelationOid);
    printf("PRS2:    event target attr no = %d\n", r->eventAttributeNumber);
    printf("PRS2:    Instead flag = %d\n", r->isInstead);
    printf("PRS2:    ruleAction:");
    lispDisplay(r->paramRuleAction);
    printf("\n");
    }
#endif PRS2_DEBUG
    
    return(r);
}


/*-----------------------------------------------------------------------
 *
 * prs2InsertRuleInfoInCatalog
 *
 * Insert information about a rule in the rules system catalog.
 * As the rule names are unique, we have first to make sure
 * that no other rule with the same names exists.
 *
 *-----------------------------------------------------------------------
 */
ObjectId
prs2InsertRuleInfoInCatalog(r)
Prs2RuleData r;
{
    register		i;
    Relation		prs2RuleRelation;
    HeapTuple		heapTuple;
    char		*values[Prs2RuleRelationNumberOfAttributes];
    char		nulls[Prs2RuleRelationNumberOfAttributes];
    ObjectId		objectId;
    HeapScanDesc	heapScan;
    ScanKeyEntryData	ruleNameKey[1];


    
    /*
     * Open the system catalog relation
     * where we keep the rule info (pg_prs2rule)
     */
    prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);
    if (!RelationIsValid(prs2RuleRelation)) {
	elog(WARN, "prs2InsertRuleInfoCatalog: could not open relation %s",
	     Prs2RuleRelationName);
    }

    /*
     * First make sure that no other rule with the same name exists!
     */
	ScanKeyEntryInitialize(&ruleNameKey[0], 0, Prs2RuleNameAttributeNumber,
						   F_CHAR16EQ, NameGetDatum(r->ruleName));

    heapScan = RelationBeginHeapScan(prs2RuleRelation, false, NowTimeQual,
				     1, (ScanKey) ruleNameKey);
    heapTuple = HeapScanGetNextTuple(heapScan, false, (Buffer *) NULL);
    if (HeapTupleIsValid(heapTuple)) {
	HeapScanEnd(heapScan);
	RelationCloseHeapRelation(prs2RuleRelation);
	elog(WARN, "Sorry, rule %s is already defined",
	     r->ruleName);
    }
    HeapScanEnd(heapScan);

    /*
     * Now create a tuple with the new rule info
     */
    for (i = 0; i < Prs2RuleRelationNumberOfAttributes; ++i) {
	values[i] = NULL;
	nulls[i] = 'n';
    }

    values[Prs2RuleNameAttributeNumber-1] =
			    fmgr(F_CHAR16IN,(char *)(r->ruleName));
    nulls[Prs2RuleNameAttributeNumber-1] = ' ';

    values[Prs2RuleEventTypeAttributeNumber-1] = (char *) r->eventType;
    nulls[Prs2RuleEventTypeAttributeNumber-1] = ' ';

    values[Prs2RuleEventTargetRelationAttributeNumber-1] =
			(char *) r->eventRelationOid;
    nulls[Prs2RuleEventTargetRelationAttributeNumber-1] = ' ';

    values[Prs2RuleEventTargetAttributeAttributeNumber-1] = 
			(char *) r->eventAttributeNumber;
    nulls[Prs2RuleEventTargetAttributeAttributeNumber-1] = ' ';

    values[Prs2RuleTextAttributeNumber-1] = 
			fmgr(F_TEXTIN, r->ruleText);
    nulls[Prs2RuleTextAttributeNumber-1] = ' ';

    heapTuple = FormHeapTuple(Prs2RuleRelationNumberOfAttributes,
			      &prs2RuleRelation->rd_att, values, nulls);

    /*
     * Now insert the tuple in the system catalog
     * and return its OID (which form now on is the rule's id.
     */
    (void) RelationInsertHeapTuple(prs2RuleRelation, heapTuple,
				   (double *) NULL);
    objectId = heapTuple->t_oid;
    RelationCloseHeapRelation(prs2RuleRelation);
    return(objectId);
}

/*-----------------------------------------------------------------------
 * prs2DeleteRuleInfoFromCatalog
 *
 * remove all rule info stored in 'pg_prs2rule' about the given
 * rule.
 *
 *-----------------------------------------------------------------------
 */
void
prs2DeleteRuleInfoFromCatalog(ruleId)
ObjectId ruleId;
{
    Relation prs2RuleRelation;
    HeapScanDesc scanDesc;
    ScanKeyData scanKey;
    HeapTuple tuple;
    Buffer buffer;

    /*
     * Open the pg_rule relation. 
     */
    prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);

     /*
      * Scan the RuleRelation ('pg_prs2rule') until we find a tuple
      */
	ScanKeyEntryInitialize(&scanKey.data[0], 0, ObjectIdAttributeNumber,
						   ObjectIdEqualRegProcedure,
						   ObjectIdGetDatum(ruleId));

    scanDesc = RelationBeginHeapScan(prs2RuleRelation,
				    false, NowTimeQual, 1, &scanKey);

    tuple = HeapScanGetNextTuple(scanDesc, false, &buffer);

    /*
     * complain if no such rule existed
     */
    if (!HeapTupleIsValid(tuple)) {
	RelationCloseHeapRelation(prs2RuleRelation);
	elog(WARN, "No rule with id = '%d' was found.\n", ruleId);
    }

    /*
     * Now delete the tuple...
     */
    RelationDeleteHeapTuple(prs2RuleRelation, &(tuple->t_ctid));
    RelationCloseHeapRelation(prs2RuleRelation);
    HeapScanEnd(scanDesc);
}

/*-----------------------------------------------------------------------
 *
 * prs2InsertRulePlanInCatalog
 *
 *    Insert a rule plan into the appropriate system catalogs.
 *    Arguments:
 *	ruleId		the OID of the rule (as returned by routine
 *			'prs2InsertRuleInfoInCatalog').
 *	planNumber	the corresponding planNumber.
 *	rulePlan	the rule plan itself!
 *
 *-----------------------------------------------------------------------
 */
void
prs2InsertRulePlanInCatalog(ruleId, planNumber, rulePlan)
ObjectId ruleId;
Prs2PlanNumber planNumber;
List rulePlan;
{
    register		i;
    char		*rulePlanString;
    Relation		prs2PlansRelation;
    HeapTuple		heapTuple;
    char		*values[Prs2PlansRelationNumberOfAttributes];
    char		nulls[Prs2PlansRelationNumberOfAttributes];

    
    /*
     * Open the system catalog relation
     */
    prs2PlansRelation=RelationNameOpenHeapRelation(Prs2PlansRelationName);
    if (!RelationIsValid(prs2PlansRelation)) {
	elog(WARN, "prs2InsertRulePlanInCatalog: could not open relation %s",
	     Prs2PlansRelationName);
    }

    /*
     * Create the appropriate tuple.
     * NOTE: 'rulePlan' is of type LispValue, so we have first
     * to transform it to a string using 'PlanToString()'
     */
    rulePlanString = PlanToString(rulePlan);

    for (i = 0; i < Prs2PlansRelationNumberOfAttributes; ++i) {
	nulls[i] = ' ';
    }

    values[Prs2PlansRuleIdAttributeNumber-1] = (char *) ruleId;
    values[Prs2PlansPlanNumberAttributeNumber-1] = (char *) planNumber;
    values[Prs2PlansCodeAttributeNumber-1] = fmgr(F_TEXTIN,rulePlanString);
    
    heapTuple = FormHeapTuple(Prs2PlansRelationNumberOfAttributes,
			      &prs2PlansRelation->rd_att, values, nulls);

    /*
     * Now insert the tuple to the system catalog.
     */
    (void) RelationInsertHeapTuple(prs2PlansRelation,
				heapTuple, (double *) NULL);
    RelationCloseHeapRelation(prs2PlansRelation);
    pfree(rulePlanString);

}

/*--------------------------------------------------------------------------
 * prs2DeleteRulePlanFromCatalog
 *
 * Delete all rule plans for the given rule from the "pg_prs2plans"
 * system catalog.
 *--------------------------------------------------------------------------
 */
void
prs2DeleteRulePlanFromCatalog(ruleId)
ObjectId ruleId;
{
    Relation prs2PlansRelation;
    HeapScanDesc scanDesc;
    ScanKeyData scanKey;
    HeapTuple tuple;
    Buffer buffer;

    /*
     * Delete all tuples of the Prs2Plans relation (pg_prs2plans)
     * corresponding to this rule...
     */
    prs2PlansRelation = RelationNameOpenHeapRelation(Prs2PlansRelationName);

	ScanKeyEntryInitialize(&scanKey.data[0], 0, Prs2PlansRuleIdAttributeNumber,
						   ObjectIdEqualRegProcedure,
						   ObjectIdGetDatum(ruleId));

    scanDesc = RelationBeginHeapScan(prs2PlansRelation,
				    false, NowTimeQual, 1, &scanKey);


    while((tuple=HeapScanGetNextTuple(scanDesc,false,(Buffer *)NULL)) !=NULL) {
	/*
	 * delete the prs2PlansRelation tuple...
	 */
	RelationDeleteHeapTuple(prs2PlansRelation, &(tuple->t_ctid));
    }
	
    RelationCloseHeapRelation(prs2PlansRelation);
    HeapScanEnd(scanDesc);

}

/*----------------------------------------------------------------------
 *
 * prs2GenerateActionPlans
 *
 * generate the plan+parse trees for the action part of the rule
 *
 *----------------------------------------------------------------------
 */
LispValue
prs2GenerateActionPlans(r)
Prs2RuleData r;
{
    LispValue result;
    LispValue action;
    LispValue oneParse;
    LispValue onePlan;
    LispValue oneEntry;
    LispValue qualQuery;
    LispValue ruleInfo;
    LispValue rangeTable;
    AttributeNumber currentAttributeNo;


    rangeTable = GetRuleRangeTableFromParse(r->parseTree);

    /*
     * the first entry in the result is some rule info
     * This consists of the following fields:
     * a) "instead" or "not-instead"
     * b) the attribute number of the attribute specified
     *    in the ON EVENT TO REL.attribute clause
     *    (or InvalidAttributeNumber)
     * c) either InvalidAttributeNumber, or in the case of a rule
     *    of the form:
     *       ON REPLACE TO REL.x WHERE ....
     *       DO REPLACE CURRENT.attribute
     *    the 'attribute' that is replced by the rule.
     */
    if (r->isInstead) {
	ruleInfo = lispCons(lispString("instead"), LispNil);
    } else {
	ruleInfo = lispCons(lispString("not-instead"), LispNil);
    }

    ruleInfo = nappend1(ruleInfo, lispInteger(r->eventAttributeNumber));
    ruleInfo = nappend1(ruleInfo, lispInteger(r->updatedAttributeNumber));

    result = lispCons(ruleInfo, LispNil);


    /*
     * now append the qual entry (parse tree + plan)
     */
    if (null(r->ruleQual)) {
	oneEntry = LispNil;
    } else {
	/*
	 * the 'ruleQual' is just a qualification.
	 * Transform it into a query of the form:
	 * "retrieve (foo=1) where QUAL".
	 * The rule manager will run this query and if there is 
	 * a tuple returned, then we know that the qual is true,
	 * otherwise we know it is false
	 */
	LispValue MakeRoot();
	LispValue root, targetList;
	Resdom resdom;
	Const constant;
	Name name;
	Datum value;

	/*
	 * construct the target list
	 */
	name = (Name) palloc(sizeof(NameData));
	if (name == NULL) {
	    elog(WARN, "prs2GenerateActionPlans: Out of memory");
	}
	strcpy(name->data,"foo");
	resdom = MakeResdom((AttributeNumber)1,
			    (ObjectId) 23,
			    false,
			    (Size) 4,
			    name,
			    (Index) 0,
			    (OperatorTupleForm) 0,
			    0);
	value = Int32GetDatum(1);
	constant = MakeConst((ObjectId) 23,	/* type */
			    (Size) 4,		/* size */
			    value,		/* value */
			    false,		/* isnull */
			    true);		/* byval */
	targetList = lispCons(
			lispCons((LispValue)resdom,
				 lispCons((LispValue)constant, LispNil)),
			LispNil);
	/*
	 * now the root
	 * XXX NumLevels == 1 ??? IS THIS CORRECT ????
	 */
	root = MakeRoot(
			1,			/* num levels */
			lispAtom("retrieve"),	/* command */
			LispNil,		/* result relation */
			rangeTable,		/* range table */
			lispInteger(0),		/* priority */
			LispNil,		/* rule info */
			LispNil,		/* unique flag */
			LispNil,		/* sort_clause */
			targetList);		/* targetList */
	/*
	 * Finally, construct the parse tree...
	 */
	qualQuery = lispCons(root,
			lispCons(targetList,
			    lispCons(r->paramRuleQual, LispNil)));
	onePlan = planner(qualQuery);
	oneEntry = lispCons(onePlan, LispNil);
	oneEntry = lispCons(qualQuery, oneEntry);
    }
    result = nappend1(result, oneEntry);

    /*
     * Now for each action append the corresponding entry
     * (parse tree + plan)
     */
    foreach (action, r->paramRuleAction) {
	oneParse = CAR(action);
	/*
	 * XXX: THIS IS A HACK !!!
	 *      (but it works, so what the hell....) 
	 *
	 * if this is a REPLACE CURRENT (X = ...)
	 * change it to a RETRIEVE (X = ...)
	 */
	changeReplaceToRetrieve(oneParse);
	/*
	 * call the planner to create a plan for this parse tree
	 */
	onePlan = planner(oneParse);
	oneEntry = lispCons(onePlan, LispNil);
	oneEntry = lispCons(oneParse, oneEntry);
	result = nappend1(result, oneEntry);
    }

    /*
     * finally insert itn the beginning of the list the
     * string Prs2RulePlanType_ACTION to show that this is
     * an action plan (as opposed to an import/export plan).
     */
    result = lispCons(lispString(Prs2RulePlanType_ACTION), result);

    return(result);
}

/*------------------------------------------------------------------
 *
 * prs2FindEventTypeFromParse
 *
 * Given a rule's parse tree find its event type.
 *------------------------------------------------------------------
 */
EventType
prs2FindEventTypeFromParse(parseTree)
LispValue parseTree;
{

    int eventTypeInt;
    EventType eventType;

    eventTypeInt = CInteger(GetRuleEventTypeFromParse(parseTree));

    /*
     * Note that the event type as stored in the parse tree is one of
     * RETRIEVE, REPLACE, APPEND or DELETE. All these symbols are
     * defined in "parse.h". So, we have to change them
     * into the appropriate "EventType" type.
     */
    switch (eventTypeInt) {
	case RETRIEVE:
	    eventType = EventTypeRetrieve;
	    break;
	case REPLACE:
	    eventType = EventTypeReplace;
	    break;
	case APPEND:
	    eventType = EventTypeAppend;
	    break;
	case DELETE:
	    eventType = EventTypeDelete;
	    break;
	default:
	    eventType = EventTypeInvalid;
	    elog(WARN, "prs2DefineTupleRule: Illegal event type (int) %d",
		eventTypeInt);
    } /* switch*/

    return(eventType);
}

/*------------------------------------------------------------------
 *
 * prs2FindActionTypeFromParse
 *
 * find the ActionType of a rule.
 *
 * if the action is in the form 'REPLACE CURRENT(x = ....)'
 * then (*updatedAttributeNumber) is the attribute number of the
 * updated field, otherwise it is InvalidAttributeNumber.
 *------------------------------------------------------------------
 */
ActionType
prs2FindActionTypeFromParse(parseTree,
			    eventTargetAttributeNumber,
			    updatedAttributeNumberP,
			    eventType)
LispValue parseTree;
AttributeNumber eventTargetAttributeNumber;
AttributeNumberPtr updatedAttributeNumberP;
EventType eventType;
{
    
    LispValue ruleActions;
    LispValue t, oneRuleAction;
    LispValue root;
    int commandType;
    LispValue resultRelation;
    LispValue rangeTable;
    ActionType actionType;
    Name relationName;
    NameData nameData;
    LispValue targetList;
    int resultRelationNo;
    LispValue resultRelationEntry;

    *updatedAttributeNumberP = InvalidAttributeNumber;

    ruleActions = GetRuleActionFromParse(parseTree);

    if (null(ruleActions)) {
	if (eventType != EventTypeRetrieve) {
	    /*
	     * then this is probably an `instead' rule with no action
	     * specified, e.g. "ON delete to DEPT WHERE ... DO INSTEAD"
	     */
	    return(ActionTypeOther);
	} else {
	    /*
	     * However, if we have something like:
	     * ON RETRIEVE THEN DO INSTEAD NOTHING
	     * we assume that this means do NOT retrieve a value,
	     * i.e. return a null attribute.
	     */
	    *updatedAttributeNumberP = eventTargetAttributeNumber;
	    return(ActionTypeRetrieveValue);
	}
    }

    foreach(t, ruleActions) {
	oneRuleAction = CAR(t);
	/*
	 * find the type of query (retrieve, delete etc...)
	 */
	root = parse_root(oneRuleAction);
	commandType = root_command_type(root);
	resultRelation = root_result_relation(root);
	rangeTable = root_rangetable(root);
	if (!null(resultRelation)) {
	    if (commandType == RETRIEVE) {
		/*
		 * This is a retrieve into, the result reln info
		 * is a list of junk.
		 */
		strncpy(&(nameData.data[0]),
			CString(CADR(resultRelation)), sizeof(NameData));
	    } else {
		resultRelationNo = CInteger(resultRelation);
		resultRelationEntry = nth(resultRelationNo-1, rangeTable);
		strcpy(&(nameData.data[0]),
		CString(rt_relname(resultRelationEntry)));
	    }
	    relationName = &nameData;
	} else {
	    relationName = InvalidName;
	}
	if (commandType == RETRIEVE && null(resultRelation)) {
	    /*
	     * this is a "retrieve" (NOT a "retrieve into...")
	     * action.
	     * It can be either something like:
	     *    ON retrieve to EMP.salary 
	     *    WHERE ....
	     *    DO retrieve (salary = ....) where .....
	     *
	     * In which case only one 'retrieve' command is allowed
	     * in the action part of the rule, 
	     * or it can be a view type rule:
	     *    ON retrieve to TOYEMP
	     *    DO retrieve (EMP.all) where EMP.dept = "toy"
	     */
	    actionType = ActionTypeRetrieveValue;
	    break; 	/* exit 'foreach' loop */

	} else if (commandType == REPLACE &&
		    /*
		     * Dangerous cast - it just happens that NameIsEqual()
		     * currently calls strncmp()
		     */
		    NameIsEqual((Name)"*CURRENT*", relationName)) {
	    /*
	     * this is a replace CURRENT(...)
	     */
	    actionType = ActionTypeReplaceCurrent;
	    /*
	     * find the updated attribute number...
	     */
	    targetList = parse_targetlist(oneRuleAction);
	    if (ExecTargetListLength(targetList) != 1) {
		elog(WARN,
		" a 'replace CURRENT(...)' must replace ONLY 1 attribute");
	    }
	    *updatedAttributeNumberP = 
			get_resno((Resdom)tl_resdom(CAR(targetList)));
	    break; 	/* exit 'foreach' loop */
	} else if (commandType == REPLACE &&
		    NameIsEqual((Name)"*NEW*", relationName)) {
	    /*
	     * this is a replace NEW(...)
	     */
	    actionType = ActionTypeReplaceNew;
	    /*
	     * find the updated attribute number...
	     */
	    targetList = parse_targetlist(oneRuleAction);
	    if (ExecTargetListLength(targetList) != 1) {
		elog(WARN,
		" a 'replace NEW(...)' must replace ONLY 1 attribute");
	    }
	    *updatedAttributeNumberP =
			get_resno((Resdom)tl_resdom(CAR(targetList)));
	    break; 	/* exit 'foreach' loop */
	} else {
	    actionType = ActionTypeOther;
	}
    } /* foreach */

    if (actionType == ActionTypeRetrieveValue) {
	/*
	 * then this must be the ONLY statement in the rule actions!
	 */
	if (length(ruleActions) != 1) {
	    elog(WARN,
	    "a 'retrieve (..)' must be the only action of a PRS2 rule!");
	}
	*updatedAttributeNumberP = eventTargetAttributeNumber;
    }
	
    if (actionType == ActionTypeReplaceCurrent) {
	/*
	 * then this must be the ONLY statement in the rule actions!
	 */
	if (length(ruleActions) != 1) {
	    elog(WARN,
	    "a 'replace CURRENT(..)' must be the only action of a PRS2 rule!");
	}
    }

    if (actionType == ActionTypeReplaceNew) {
	/*
	 * then this must be the ONLY statement in the rule actions!
	 */
	if (length(ruleActions) != 1) {
	    elog(WARN,
	    "a 'replace NEW(..)' must be the only action of a PRS2 rule!");
	}
    }

    return(actionType);
}

/*----------------------------------------------------------------
 *
 * changeReplaceToRetrieve
 *
 * Ghange the parse tree of a 'REPLACE CURRENT(X = ...)'
 * or 'REPLACE NEW(X = ...)' command to a
 * 'RETRIEVE (X = ...)'
 *----------------------------------------------------------------
 */
void
changeReplaceToRetrieve(parseTree)
LispValue parseTree;
{

    LispValue root;
    LispValue targetList;
    int commandType;
    LispValue resultRelation;
    LispValue rangeTable;
    Name relationName;
    NameData nameData;
    int resultRelationNo;
    LispValue resultRelationEntry;


    root = parse_root(parseTree);
    commandType = root_command_type(root);
    resultRelation = root_result_relation(root);
    rangeTable = root_rangetable(root);
    if (!null(resultRelation)) {
	if (commandType == RETRIEVE) {
	    /*
	     * This is a retrieve into, the result reln info
	     * is a list of junk.
	     */
	    strncpy(&(nameData.data[0]),
		    CString(CADR(resultRelation)), sizeof(NameData));
	} else {
	    resultRelationNo = CInteger(resultRelation);
	    resultRelationEntry = nth(resultRelationNo-1, rangeTable);
	    strcpy(&(nameData.data[0]),
	    CString(rt_relname(resultRelationEntry)));
	}
	    relationName = &nameData;
    } else {
	relationName = InvalidName;
    }

    /*
     * Is this a REPLACE CURRENT command?
     */
    if (commandType!=REPLACE ||
       (!NameIsEqual((Name)"*CURRENT*", relationName) &&
       !NameIsEqual((Name)"*NEW*", relationName))) {
	/*
	 * NO, this is not a REPLACE CURRENT or a REPLACE NEW command
	 */
	return;
    }

    /*
     * Yes it is!
     *
     * Now *DESTRUCTIVELY* change the parse tree...
     * 
     * Change the command from 'replace' to 'retrieve'
     * and the result relation to 'nil'
     */
    root = parse_root(parseTree);
    root_command_type_atom(root) = lispAtom("retrieve");
    root_result_relation(root) = LispNil;

    /*
     * Now go to the target list (which must have exactly 1 Resdom
     * node, and change the 'resno' to 1
     */
    targetList = parse_targetlist(parseTree);
    set_resno((Resdom)tl_resdom(CAR(targetList)), (AttributeNumber)1);
}

/*-----------------------------------------------------------------
 *
 * prs2AttributeIsOfBasicType
 *
 * check if the given attribute is of a "basic" type.
 *-----------------------------------------------------------------
 */
bool
prs2AttributeIsOfBasicType(relOid, attrNo)
ObjectId relOid;
AttributeNumber attrNo;
{
    ObjectId typeId;
    char typtype;

    typeId = get_atttype(relOid, attrNo);
    typtype = get_typtype(typeId);
    if (typtype == '\0') {
	elog(WARN, "Cache lookup for type %ld failed...", typeId);
    }

    if (typtype == 'b') {
	return(true);
    } else {
	return(false);
    }
}

/*=============================== DEBUGGINF STUFF ================*/
LispValue
prs2ReadRule(fname)
char *fname;
{
    FILE *fp;
    int c;
    int count, maxcount;
    char *s1, *s2;
    LispValue l;
    LispValue StringToPlan();

    printf("--- prsReadRule.\n");
    AllocateFile();
    if (fname==NULL) {
	fp = stdin;
	printf(" reading rule from stdin.\n");
    } else {
	AllocateFile();
	fp = fopen(fname, "r");
	if (fp==NULL){
	    printf(" Can not open rule file %s\n", fname);
	    elog(WARN,"prs2ReadRule.... exiting...\n");
	} else {
	    printf("Reading rule from file %s\n", fname);
	}
    }

    maxcount = 100;
    s1 = palloc(maxcount);
    if (s1 == NULL) {
	elog(WARN,"prs2ReadRule : out of memory!");
    }

    count = 0;
    while((c=getc(fp)) != EOF) {
	if (count >= maxcount) {
	    maxcount = maxcount + 1000;
	    s2 = palloc(maxcount);
	    if (s2 == NULL) {
		elog(WARN,"prs2ReadRule : out of memory!");
	    }
	    bcopy(s1, s2, count);
	    pfree(s1);
	    s1 = s2;
	}
	s1[count] = c;
	count++;
    }
    s1[count+1] = '\0';

    l = StringToPlan(s1);

    printf("  list = \n");
    lispDisplay(l);

    if (fp!=stdin) {
	fclose(fp);
	FreeFile();
    }

    return(l);
}
@


1.25
log
@compute target list correctly
@
text
@d6 1
a6 1
 *   $Header: /private/mer/pg/src/rules/prs2/RCS/prs2define.c,v 1.24 1992/05/05 01:01:08 mer Exp mer $
d661 1
@


1.24
log
@fix bug related to retrieve into rule actions
@
text
@d6 1
a6 1
 *   $Header: /users/mer/pg/src/rules/prs2/RCS/prs2define.c,v 1.23 1992/03/25 17:30:55 hong Exp mer $
d897 1
a897 1
	    if (length(targetList) != 1) {
d914 1
a914 1
	    if (length(targetList) != 1) {
@


1.23
log
@plugged buffer leaks
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.22 91/11/18 22:21:22 mer Exp $
d848 13
a860 4
	    resultRelationNo = CInteger(resultRelation);
	    resultRelationEntry = nth(resultRelationNo-1, rangeTable);
	    strcpy(&(nameData.data[0]),
		    CString(rt_relname(resultRelationEntry)));
d990 14
a1003 5
	resultRelationNo = CInteger(resultRelation);
	resultRelationEntry = nth(resultRelationNo-1, rangeTable);
	strcpy(&(nameData.data[0]),
		CString(rt_relname(resultRelationEntry)));
	relationName = &nameData;
@


1.22
log
@prototypes finale
@
text
@d6 1
a6 1
 *   $Header: /users/mer/postgres/src/rules/prs2/RCS/prs2define.c,v 1.21 1991/05/09 18:08:46 sp Exp mer $
d470 1
d576 1
@


1.21
log
@"On append" or "On delete" rules must not be defined on a specific
attribute....
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.20 91/05/03 16:20:05 cimarron Exp Locker: sp $
d58 1
a58 1
    lispDisplay(parseTree, 0);
d314 1
a314 1
    lispDisplay(eventTarget, 0);
d671 2
a672 1
			lispCons(resdom, lispCons(constant, LispNil)),
d873 5
a877 1
		    NameIsEqual("*CURRENT*", relationName)) {
d890 2
a891 1
	    *updatedAttributeNumberP = get_resno(tl_resdom(CAR(targetList)));
d894 1
a894 1
		    NameIsEqual("*NEW*", relationName)) {
d907 2
a908 1
	    *updatedAttributeNumberP = get_resno(tl_resdom(CAR(targetList)));
d992 2
a993 2
       (!NameIsEqual("*CURRENT*", relationName) &&
       !NameIsEqual("*NEW*", relationName))) {
d1017 1
a1017 1
    set_resno(tl_resdom(CAR(targetList)), (AttributeNumber)1);
d1102 1
a1102 1
    lispDisplay(l,0);
@


1.20
log
@removed extern decl (now a macro)
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.19 91/04/19 05:38:16 kemnitz Exp Locker: cimarron $
d204 10
a214 1

@


1.19
log
@uses new scankey stuff
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.18 91/04/10 16:09:23 sp Exp Locker: kemnitz $
a33 1
extern HeapTuple palloctup();
@


1.18
log
@the format of the rule plans has slightly changed...
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.17 91/04/08 18:14:21 sp Exp $
d359 2
a360 4
    ruleNameKey[0].flags = 0;
    ruleNameKey[0].attributeNumber= Prs2RuleNameAttributeNumber;
    ruleNameKey[0].procedure = F_CHAR16EQ;
    ruleNameKey[0].argument = NameGetDatum(r->ruleName);
d440 4
a443 4
    scanKey.data[0].flags = 0;
    scanKey.data[0].attributeNumber = ObjectIdAttributeNumber;
    scanKey.data[0].procedure = ObjectIdEqualRegProcedure;
    scanKey.data[0].argument = ObjectIdGetDatum(ruleId);
d551 4
a554 4
    scanKey.data[0].flags = 0;
    scanKey.data[0].attributeNumber = Prs2PlansRuleIdAttributeNumber;
    scanKey.data[0].procedure = ObjectIdEqualRegProcedure;
    scanKey.data[0].argument = ObjectIdGetDatum(ruleId);
@


1.17
log
@misc changes to support locking more than one path in the rule
qualification's tree...
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.16 91/03/28 14:26:51 sp Exp Locker: sp $
d715 7
@


1.16
log
@minor fix in a debuggin routine (never called under normal operations)
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.15 91/02/25 16:54:02 sp Exp $
d526 2
@


1.15
log
@Now the user can explicitly specify what kind of lock (tuple-level-lock
or relation-level-lock) a tuple-system rule will use.
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.14 91/02/24 12:39:57 sp Exp $
d1069 1
a1069 1
	    free(s1);
@


1.14
log
@Quite a few changes. Now tuple-level-locking is implemented 
plus some code cleanup...
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.13 91/01/09 19:07:12 sp Exp Locker: sp $
d55 1
d65 6
d78 1
a78 1
    prs2AddTheNewRule(ruleData);
@


1.13
log
@The routines that put relation level or tuple level locks have been
moved to 'prs2putlocks.c', 'prs2rel.c' and 'prs2tup.c'
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.12 90/10/25 21:03:59 goh Exp $
d28 1
a37 2
void changeReplaceToRetrieve();
bool prs2AttributeIsOfBasicType();
a52 17
    NameData ruleName;
    EventType eventType;
    ActionType actionType;
    LispValue eventTarget;
    NameData eventTargetRelationNameData;
    Relation eventTargetRelation;
    ObjectId eventTargetRelationOid;
    NameData eventTargetAttributeNameData;
    AttributeNumber eventTargetAttributeNumber;
    LispValue ruleQual;
    LispValue paramRuleQual;
    LispValue paramRuleAction;
    LispValue paramParseTree;
    int isRuleInstead;
    LispValue ruleActionPlans;
    ObjectId ruleId;		/*the OID for the new rule*/
    AttributeNumber updatedAttributeNumber;
d54 1
a55 2
    LispValue prs2ReadRule();

d57 1
a57 1
    printf("---prs2DefineTupleRule called, with argument =");
d60 1
a60 1
    printf("   ruletext = %s\n", ruleText);
d62 5
d68 4
a71 4
    strcpy(ruleName.data, CString(GetRuleNameFromParse(parseTree)));
    eventTarget = GetRuleEventTargetFromParse(parseTree);
    isRuleInstead = CInteger(GetRuleInsteadFromParse(parseTree));
    eventType = prs2FindEventTypeFromParse(parseTree);
d73 18
d92 65
d171 4
a174 3
    strcpy(eventTargetRelationNameData.data, CString(CAR(eventTarget)));
    eventTargetRelation = RelationNameGetRelation(&eventTargetRelationNameData);
    eventTargetRelationOid = eventTargetRelation->rd_id;
d179 2
a180 1
	eventTargetAttributeNumber = InvalidAttributeNumber;
d182 4
a185 4
	strcpy(eventTargetAttributeNameData.data, CString(CADR(eventTarget)));
	eventTargetAttributeNumber = get_attnum(eventTargetRelationOid,
					    &eventTargetAttributeNameData);
	if (eventTargetAttributeNumber == InvalidAttributeNumber) {
d193 2
a194 2
	if (!prs2AttributeIsOfBasicType(eventTargetRelationOid,
					eventTargetAttributeNumber)) {
d200 1
d202 34
d246 4
a249 5
    ruleQual = GetRuleQualFromParse(parseTree);
    paramParseTree = lispCopy(parseTree);
    SubstituteParamForNewOrCurrent(paramParseTree, eventTargetRelationOid);
    paramRuleQual = GetRuleQualFromParse(paramParseTree);
    paramRuleAction = GetRuleActionFromParse(paramParseTree);
d257 4
a260 4
    actionType = prs2FindActionTypeFromParse(parseTree,
			eventTargetAttributeNumber,
			&updatedAttributeNumber,
			eventType);
d270 2
a271 2
    if (!isRuleInstead && actionType == ActionTypeRetrieveValue &&
	eventTargetAttributeNumber != InvalidAttributeNumber ) {
a275 1
    
d278 5
a282 4
    printf("---DEFINE TUPLE RULE:\n");
    printf("   RuleName = %s\n", ruleName.data);
    printf("   event type = %d ", eventType);
    switch (eventType) {
d298 1
a298 1
    printf("   event target:");
d301 5
a305 5
    printf("   event target relation OID = %ld\n", eventTargetRelationOid);
    printf("   event target attr no = %d\n", eventTargetAttributeNumber);
    printf("   Instead flag = %d\n", isRuleInstead);
    printf("   ruleAction:");
    lispDisplay(paramRuleAction, 0);
d307 1
a308 28

    /*
     * Insert information about the rule in the catalogs.
     * The routine returns the rule's OID.
     *
     */
    ruleId = prs2InsertRuleInfoInCatalog(&ruleName,
					eventType,
					eventTargetRelationOid,
					eventTargetAttributeNumber,
					ruleText);
					
    /*
     * Now generate the plans for the action part of the rule
     */
    ruleActionPlans = prs2GenerateActionPlans(isRuleInstead,
					paramRuleQual,paramRuleAction,
					GetRuleRangeTableFromParse(parseTree),
					eventTargetAttributeNumber,
					updatedAttributeNumber);

    /*
     * Store the plans generated above in the system 
     * catalogs.
     */
    prs2InsertRulePlanInCatalog(ruleId, 
			    ActionPlanNumber,
			    ruleActionPlans);
d310 1
a310 13
    /*
     * Now set the appropriate locks.
     */
    prs2TupleSystemPutLocks(ruleId, eventTargetRelationOid,
		eventTargetAttributeNumber,
		updatedAttributeNumber,
		eventType, actionType,
		ruleQual);

#ifdef PRS2_DEBUG
    printf("--- DEFINE PRS2 RULE: Done.\n");
#endif PRS2_DEBUG

d322 1
a323 1

d325 2
a326 7
prs2InsertRuleInfoInCatalog(ruleName, eventType, eventRelationOid,
			    eventAttributeNumber, ruleText)
Name ruleName;
EventType eventType;
ObjectId eventRelationOid;
AttributeNumber eventAttributeNumber;
char * ruleText;
d341 1
d355 1
a355 1
    ruleNameKey[0].argument = NameGetDatum(ruleName);
d357 1
a357 1
    heapScan = RelationBeginHeapScan(prs2RuleRelation, 0, NowTimeQual,
d359 1
a359 1
    heapTuple = HeapScanGetNextTuple(heapScan, 0, (Buffer *) NULL);
d363 2
a364 2
	elog(WARN, "prs2InsertRuleInfoInCatalog: rule %s already defined",
	     ruleName);
d376 2
a377 1
    values[Prs2RuleNameAttributeNumber-1] = fmgr(F_CHAR16IN,(char *)ruleName);
d380 1
a380 1
    values[Prs2RuleEventTypeAttributeNumber-1] = (char *) eventType;
d384 1
a384 1
			(char *) eventRelationOid;
d388 1
a388 1
			(char *) eventAttributeNumber;
d392 1
a392 1
			fmgr(F_TEXTIN, ruleText);
d410 1
d412 49
d469 2
d474 3
a476 3
ObjectId	ruleId;
Prs2PlanNumber	planNumber;
LispValue	rulePlan;
d521 42
d568 2
d572 2
a573 10
prs2GenerateActionPlans(isRuleInstead, ruleQual,ruleAction,
			rangeTable,
			eventTargetAttributeNumber,
			updatedAttributeNumber)
int isRuleInstead;
LispValue ruleQual;
LispValue ruleAction;
LispValue rangeTable;
AttributeNumber eventTargetAttributeNumber;
AttributeNumber updatedAttributeNumber;
d582 1
d586 2
d601 1
a601 1
    if (isRuleInstead) {
d607 2
a608 2
    ruleInfo = nappend1(ruleInfo, lispInteger(eventTargetAttributeNumber));
    ruleInfo = nappend1(ruleInfo, lispInteger(updatedAttributeNumber));
d616 1
a616 1
    if (null(ruleQual)) {
d677 1
a677 1
			    lispCons(ruleQual, LispNil)));
d688 1
a688 1
    foreach (action, ruleAction) {
a707 1

a709 113
/* ----------------------------------------------------------------
 *
 * prs2RemoveTupleRule
 *
 * Delete a rule given its rulename.
 *
 * There are three steps.
 *   1) Find the corresponding tuple in 'pg_prs2rule' relation.
 *      Find the rule Id (i.e. the Oid of the tuple) and finally delete
 *      the tuple.
 *   2) Given the rule Id find and delete all corresonding tuples from
 *      'pg_prs2plans' relation
 *   3) (Optional) Delete the locks from the 'pg_relation' relation.
 *
 *
 * ----------------------------------------------------------------
 */

void
prs2RemoveTupleRule(ruleName)
Name ruleName;
{
    Relation prs2RuleRelation;
    Relation prs2PlansRelation;
    HeapScanDesc scanDesc;
    ScanKeyData scanKey;
    HeapTuple tuple;
    ObjectId ruleId;
    ObjectId eventRelationOid;
    Datum eventRelationOidDatum;
    Buffer buffer;
    Boolean isNull;

    /*
     * Open the pg_rule relation. 
     */
    prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);

     /*
      * Scan the RuleRelation ('pg_prs2rule') until we find a tuple
      */
    scanKey.data[0].flags = 0;
    scanKey.data[0].attributeNumber = Prs2RuleNameAttributeNumber;
    scanKey.data[0].procedure = Character16EqualRegProcedure;
    scanKey.data[0].argument = NameGetDatum(ruleName);
    scanDesc = RelationBeginHeapScan(prs2RuleRelation,
				    0, NowTimeQual, 1, &scanKey);

    tuple = HeapScanGetNextTuple(scanDesc, 0, &buffer);

    /*
     * complain if no rule with such name existed
     */
    if (!HeapTupleIsValid(tuple)) {
	RelationCloseHeapRelation(prs2RuleRelation);
	elog(WARN, "No rule with name = '%s' was found.\n", ruleName);
    }

    /*
     * Store the OID of the rule (i.e. the tuple's OID)
     * and the event relation's OID
     */
    ruleId = tuple->t_oid;
    eventRelationOidDatum = HeapTupleGetAttributeValue(
				tuple,
				buffer,
				Prs2RuleEventTargetRelationAttributeNumber,
				&(prs2RuleRelation->rd_att),
				&isNull);
    if (isNull) {
	/* XXX strange!!! */
	elog(WARN, "prs2RemoveTupleRule: null event target relation!");
    }
    eventRelationOid = DatumGetObjectId(eventRelationOidDatum);

    /*
     * Now delete the tuple...
     */
    RelationDeleteHeapTuple(prs2RuleRelation, &(tuple->t_ctid));
    RelationCloseHeapRelation(prs2RuleRelation);

    /*
     * Now delete all tuples of the Prs2Plans relation (pg_prs2plans)
     * corresponding to this rule...
     */
    prs2PlansRelation = RelationNameOpenHeapRelation(Prs2PlansRelationName);

    scanKey.data[0].flags = 0;
    scanKey.data[0].attributeNumber = Prs2PlansRuleIdAttributeNumber;
    scanKey.data[0].procedure = ObjectIdEqualRegProcedure;
    scanKey.data[0].argument = ObjectIdGetDatum(ruleId);
    scanDesc = RelationBeginHeapScan(prs2PlansRelation,
				    0, NowTimeQual, 1, &scanKey);


    while((tuple=HeapScanGetNextTuple(scanDesc, 0, (Buffer *)NULL)) != NULL) {
	/*
	 * delete the prs2PlansRelation tuple...
	 */
	RelationDeleteHeapTuple(prs2PlansRelation, &(tuple->t_ctid));
    }
	
    RelationCloseHeapRelation(prs2PlansRelation);

    /*
     * Now delete the relation level locks from the updated relation
     */
    prs2RemoveRelationLevelLocks(ruleId, eventRelationOid);

    elog(DEBUG, "---Rule '%s' deleted.\n", ruleName);

}

d715 1
d764 1
a919 64
/*=============================== DEBUGGINF STUFF ================*/
LispValue
prs2ReadRule(fname)
char *fname;
{
    FILE *fp;
    int c;
    int count, maxcount;
    char *s1, *s2;
    LispValue l;
    LispValue StringToPlan();

    printf("--- prsReadRule.\n");
    AllocateFile();
    if (fname==NULL) {
	fp = stdin;
	printf(" reading rule from stdin.\n");
    } else {
	AllocateFile();
	fp = fopen(fname, "r");
	if (fp==NULL){
	    printf(" Can not open rule file %s\n", fname);
	    elog(WARN,"prs2ReadRule.... exiting...\n");
	} else {
	    printf("Reading rule from file %s\n", fname);
	}
    }

    maxcount = 100;
    s1 = palloc(maxcount);
    if (s1 == NULL) {
	elog(WARN,"prs2ReadRule : out of memory!");
    }

    count = 0;
    while((c=getc(fp)) != EOF) {
	if (count >= maxcount) {
	    maxcount = maxcount + 1000;
	    s2 = palloc(maxcount);
	    if (s2 == NULL) {
		elog(WARN,"prs2ReadRule : out of memory!");
	    }
	    bcopy(s1, s2, count);
	    free(s1);
	    s1 = s2;
	}
	s1[count] = c;
	count++;
    }
    s1[count+1] = '\0';

    l = StringToPlan(s1);

    printf("  list = \n");
    lispDisplay(l,0);

    if (fp!=stdin) {
	fclose(fp);
	FreeFile();
    }

    return(l);
}

d927 1
d996 1
d1017 64
@


1.12
log
@spyro's earlier change to locks breaks procedures,
not caught till mike's new demo used it because
I didn't have latest files.

- jeff
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.11 90/10/20 14:29:51 sp Exp Locker: goh $
d35 2
d44 3
d64 3
a66 1
    LispValue ruleAction;
a69 1
    Prs2LockType lockType;
a83 1
    ruleQual = GetRuleQualFromParse(parseTree);
d85 1
a85 1
    ruleAction = GetRuleActionFromParse(parseTree);
a86 1
    eventType = prs2FindEventTypeFromParse(parseTree);
d130 17
d200 1
a200 1
    lispDisplay(ruleAction, 0);
d219 1
a219 1
					ruleQual,ruleAction,
d235 1
a235 1
    prs2PutTupleOrRewriteLocks(ruleId, eventTargetRelationOid,
d238 2
a239 1
		eventType, actionType, true);
a246 7
/*-----------------------------------------------------------------------
 * prs2PutLocksInRelation
 *
 * Put the appropriate locks for the rule. For the time
 * being we just put a relation level lock in pg_relation.
 * All the tuples of the target relation are assumed to be locked
 */
a247 80
void
prs2PutLocksInRelation(ruleId, lockType, eventRelationOid, eventAttributeNumber)
ObjectId ruleId;
Prs2LockType lockType;
ObjectId eventRelationOid;
AttributeNumber eventAttributeNumber;
{

    Relation relationRelation;
    HeapScanDesc scanDesc;
    ScanKeyData scanKey;
    HeapTuple tuple;
    Buffer buffer;
    HeapTuple newTuple;
    RuleLock currentLock;

    /*
     * Lock a relation given its ObjectId.
     * Go to the RelationRelation (i.e. pg_relation), find the
     * appropriate tuple, and add the specified lock to it.
     */
    relationRelation = RelationNameOpenHeapRelation(RelationRelationName);

    scanKey.data[0].flags = 0;
    scanKey.data[0].attributeNumber = ObjectIdAttributeNumber;
    scanKey.data[0].procedure = ObjectIdEqualRegProcedure;
    scanKey.data[0].argument = ObjectIdGetDatum(eventRelationOid);
    scanDesc = RelationBeginHeapScan(relationRelation,
					0, NowTimeQual,
					1, &scanKey);
    
    tuple = HeapScanGetNextTuple(scanDesc, 0, &buffer);
    if (!HeapTupleIsValid(tuple)) {
	elog(WARN, "Invalid rel OID %ld", eventRelationOid);
    }

    /*
     * We have found the appropriate tuple of the RelationRelation.
     * Now find its old locks, and add the new one
     */
    currentLock = prs2GetLocksFromTuple(tuple, buffer,
					relationRelation->rd_att);

#ifdef PRS2_DEBUG
    /*-- DEBUG --*/
    printf("previous Lock:");
    prs2PrintLocks(currentLock);
    printf("\n");
#endif /* PRS2_DEBUG */

    currentLock = prs2AddLock(currentLock,
			ruleId,
			lockType,
			eventAttributeNumber,
			ActionPlanNumber);

#ifdef PRS2_DEBUG
    /*-- DEBUG --*/
    printf("new Lock:");
    prs2PrintLocks(currentLock);
    printf("\n");
#endif /* PRS2_DEBUG */

    /*
     * Create a new tuple (i.e. a copy of the old tuple
     * with its rule lock field changed and replace the old
     * tuple in the Relationrelation
     */
    newTuple = prs2PutLocksInTuple(tuple, buffer,
		    relationRelation,
		    currentLock);

    RelationReplaceHeapTuple(relationRelation, &(tuple->t_ctid),
			    newTuple, (double *)NULL);
    
    RelationCloseHeapRelation(relationRelation);

}


d664 1
a664 1
    prs2RemoveLocks(ruleId, eventRelationOid);
a669 86
/*--------------------------------------------------------------
 *
 * RuleUnlockRelation
 *
 * Unlock a relation given its ObjectId ant the Objectid of the rule
 * Go to the RelationRelation (i.e. pg_relation), find the
 * appropriate tuple, and remove all locks of this rule from it.
 */

void
prs2RemoveLocks(ruleId, eventRelationOid)
ObjectId ruleId;
ObjectId eventRelationOid;
{

    Relation relationRelation;
    HeapScanDesc scanDesc;
    ScanKeyData scanKey;
    HeapTuple tuple;
    Buffer buffer;
    HeapTuple newTuple;
    HeapTuple newTuple2;
    RuleLock currentLocks;
    Boolean isNull;
    int i;
    int numberOfLocks;
    Prs2OneLock oneLock;

    relationRelation = RelationNameOpenHeapRelation(RelationRelationName);

    scanKey.data[0].flags = 0;
    scanKey.data[0].attributeNumber = ObjectIdAttributeNumber;
    scanKey.data[0].procedure = ObjectIdEqualRegProcedure;
    scanKey.data[0].argument = ObjectIdGetDatum(eventRelationOid);
    scanDesc = RelationBeginHeapScan(relationRelation,
					0, NowTimeQual,
					1, &scanKey);
    
    tuple = HeapScanGetNextTuple(scanDesc, 0, &buffer);
    if (!HeapTupleIsValid(tuple)) {
	elog(NOTICE, "Could not find relation with id %ld\n", eventRelationOid);
    } else {
	/*
	 * "calculate" the new locks...
	 */
	currentLocks = prs2GetLocksFromTuple(
				tuple,
				buffer,
				&(relationRelation->rd_att));
#ifdef PRS2_DEBUG
	printf("previous Lock:");
	prs2PrintLocks(currentLocks);
	printf("\n");
#endif PRS2_DEBUG

	/*
	 * find all the locks with the given rule id and remove them
	 */
	currentLocks = prs2RemoveAllLocksOfRule(currentLocks, ruleId);

#ifdef PRS2_DEBUG
	printf("new Lock:");
	prs2PrintLocks(currentLocks);
	printf("\n");
#endif PRS2_DEBUG

	/*
	 * Create a new tuple (i.e. a copy of the old tuple
	 * with its rule lock field changed and replace the old
	 * tuple in the RelationRelation
	 */
	newTuple = prs2PutLocksInTuple(tuple, buffer,
				    relationRelation,
				    currentLocks);
	RelationReplaceHeapTuple(relationRelation, &(tuple->t_ctid),
				newTuple, (double *)NULL);
	
    }

    /*
     * we are done, close the RelationRelation...
     */
    RelationCloseHeapRelation(relationRelation);

}

a875 159
}

/*------------------------------------------------------------------
 *
 * prs2PutLocks
 *
 * (used by the query rewrite system)
 */
prs2PutLocks(ruleId, relationOid, eventAttributeNo,
	    updatedAttributeNo, eventType, actionType)
ObjectId ruleId;
ObjectId relationOid;
AttributeNumber eventAttributeNo;
AttributeNumber updatedAttributeNo;
EventType eventType;
ActionType actionType;
{
    prs2PutTupleOrRewriteLocks(ruleId, relationOid, eventAttributeNo,
		updatedAttributeNo, eventType, actionType, false);
}

/*------------------------------------------------------------------
 *
 * prs2PutTupleOrRewriteLocks
 *
 * Put the appropriate rule locks.
 * NOTE: currently only relation level locking is implemented
 * NOTE: isTupleLevel is true if this routine is used by the tuple
 * level system, otherwise (if it is used by the query rewrite
 * system) it is false.
 */
prs2PutTupleOrRewriteLocks(ruleId, relationOid, eventAttributeNo,
			    updatedAttributeNo,
			    eventType, actionType, isTupleLevel)
ObjectId ruleId;
ObjectId relationOid;
AttributeNumber eventAttributeNo;
AttributeNumber updatedAttributeNo;
EventType eventType;
ActionType actionType;
bool isTupleLevel;
{
    Prs2LockType lockType;
    AttributeNumber attributeNo;

    /*
     * find the lock type
     */
    lockType = LockTypeInvalid;

    if (actionType == ActionTypeRetrieveValue &&
	eventAttributeNo == InvalidAttributeNumber) {
	/*
	 * this is a "view" rule....
	 */
	if (isTupleLevel) {
	    lockType = LockTypeTupleRetrieveRelation;
	} else {
	    lockType = LockTypeRetrieveRelation;
	}
	attributeNo = InvalidAttributeNumber;
    } else if (actionType == ActionTypeRetrieveValue ||
	actionType == ActionTypeReplaceCurrent ||
	actionType == ActionTypeReplaceNew) {
	/*
	 * In this case the attribute to be locked is the updated
	 * attribute...
	 */
	attributeNo = updatedAttributeNo;
	switch (eventType) {
	    case EventTypeRetrieve:
		if (isTupleLevel) {
		    lockType = LockTypeTupleRetrieveWrite;
		} else {
		    if ( actionType == ActionTypeRetrieveValue ) {
			lockType = LockTypeRetrieveRelation;
		    } else 
		      lockType = LockTypeRetrieveWrite;
		}
		break;
	    case EventTypeReplace:
		if (isTupleLevel) {
		    lockType = LockTypeTupleReplaceWrite;
		} else {
		    lockType = LockTypeReplaceWrite;
		}
		if (actionType == ActionTypeReplaceCurrent) {
		    elog(WARN, "ON REPLACE rules can not update CURRENT tuple");
		}
		break;
	    case EventTypeAppend:
		if (isTupleLevel) {
		    lockType = LockTypeTupleAppendWrite;
		} else {
		    lockType = LockTypeAppendWrite;
		}
		if (actionType == ActionTypeReplaceCurrent) {
		    elog(WARN, "ON APPEND rules can not update CURRENT tuple");
		}
		break;
	    case EventTypeDelete:
		if (isTupleLevel) {
		    lockType = LockTypeTupleDeleteWrite;
		} else {
		    lockType = LockTypeDeleteWrite;
		}
		elog(WARN, "ON DELETE rules can not update CURRENT tuple");
		break;
	    default:
		elog(WARN, "prs2PutLocks: Illegal Event type: %c", eventType);
	}
    } else if (actionType == ActionTypeOther) {
	/*
	 * In this case the attribute to be locked is the 'event'
	 * attribute...
	 */
	attributeNo = eventAttributeNo;
	switch (eventType) {
	    case EventTypeRetrieve:
		if (isTupleLevel) {
		    lockType = LockTypeTupleRetrieveAction;
		} else {
		    lockType = LockTypeRetrieveAction;
		}
		break;
	    case EventTypeReplace:
		if (isTupleLevel) {
		    lockType = LockTypeTupleReplaceAction;
		} else {
		    lockType = LockTypeReplaceAction;
		}
		break;
	    case EventTypeAppend:
		if (isTupleLevel) {
		    lockType = LockTypeTupleAppendAction;
		} else {
		    lockType = LockTypeAppendAction;
		}
		break;
	    case EventTypeDelete:
		if (isTupleLevel) {
		    lockType = LockTypeTupleDeleteAction;
		} else {
		    lockType = LockTypeDeleteAction;
		}
		break;
	    default:
		elog(WARN, "prs2PutLocks: Illegal Event type: %c", eventType);
	}
    } else {
	elog(WARN, "prs2PutLocks: Illegal Action type: %c", actionType);
    }

#ifdef PRS2DEBUG
    printf("prs2PutLocks: (ACTION='%c', EVENT='%c', LOCK='%c'\n",
	    actionType, eventType, lockType);
#endif PRS2DEBUG

    prs2PutLocksInRelation(ruleId, lockType, relationOid, attributeNo);
@


1.11
log
@Now "view" rules don't have to have an "instead"
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.10 90/10/16 17:18:13 sp Exp $
d1101 4
a1104 1
		    lockType = LockTypeRetrieveWrite;
@


1.10
log
@bug fix: space allocated for a Name was local to a routine
and it was blown away upon return...
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.9 90/10/10 18:58:00 hong Exp $
d139 4
d144 2
a145 1
    if (!isRuleInstead && actionType == ActionTypeRetrieveValue) {
@


1.9
log
@added a new field in Resdom node
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.8 90/09/25 16:42:27 kemnitz Exp Locker: hong $
d537 1
a537 1
	NameData nameData;
d543 5
a547 1
	strcpy(nameData.data,"foo");
d551 1
a551 1
			    &(nameData.data[0]),
@


1.8
log
@Updating from revision 1.7 to revision 1.18
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.18 90/08/18 00:41:40 cimarron Exp $
d549 2
a550 1
			    (OperatorTupleForm) 0);
@


1.7
log
@Got rid of datum indirection.
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.6 90/05/31 14:54:26 sp Exp $
d12 16
a27 19
#include "c.h"
#include "primnodes.h"
#include "primnodes.a.h"
#include "datum.h"
#include "pg_lisp.h"
#include "log.h"
#include "relcache.h"	/* RelationNameGetRelation() defined here...*/
#include "prs2.h"
#include "anum.h"	/* RuleRelationNumberOfAttributes etc. defined here */
#include "skey.h"	/* 'ScanKeyEntryData' defined here... */
#include "tqual.h"	/* 'NowTimeQual' defined here.. */
#include "heapam.h"	/* heap AM calls defined here */
#include "lsyscache.h"	/* get_attnum()  defined here...*/
#include "parse.h"	/* RETRIEVE, APPEND etc defined here.. */
#include "parsetree.h"
#include "catname.h"	/* names of various system relations defined here */
#include "rproc.h"	/* for ObjectIdEqualRegProcedure etc. */
#include "fmgr.h"	/* for F_CHAR16EQ, F_CHAR16IN etc. */
#include "ftup.h"	/* for FormHeapTuple() */
d29 4
d36 1
a68 5
/* #define NO_PARSER_SUPPORT */
#ifdef NO_PARSER_SUPPORT
    parseTree = prs2ReadRule("/users/spyros/postgres/O/support/RULE");
#endif

d113 10
d133 11
a143 1
			&updatedAttributeNumber);
d193 4
a196 3
					    ruleQual,ruleAction,
					    eventTargetAttributeNumber,
					    updatedAttributeNumber);
d209 1
a209 1
    prs2PutLocks(ruleId, eventTargetRelationOid,
d212 1
a212 1
		eventType, actionType);
d330 2
a331 2
    char		*values[RuleRelationNumberOfAttributes];
    char		nulls[RuleRelationNumberOfAttributes];
d474 1
d480 1
a524 1
#ifdef NOT_YET
d533 1
d540 3
a542 5
	root = lispCons(lispInteger(1),
		lispCons(lispAtom("retrieve"),
		    lispCons(LispNil,
			lispCons(LispNil,
			    lispCons(lispCons(0,LispNil),LispNil)))));
d547 1
a547 1
			    &nameData,
d559 17
a578 3
#else /* NOT_YET*/
	qualQuery = ruleQual;
#endif /* NOT_YET */
d765 9
a773 8
	elog(WARN, "Invalid rel Oid %ld\n", eventRelationOid);
    }

    currentLocks = prs2GetLocksFromTuple(
			    tuple,
			    buffer,
			    &(relationRelation->rd_att));

d775 3
a777 3
    printf("previous Lock:");
    prs2PrintLocks(currentLocks);
    printf("\n");
a778 5
    
    /*
     * find all the locks with the given rule id and remove them
     */
    currentLocks = prs2RemoveAllLocksOfRule(currentLocks, ruleId);
d780 5
d786 3
a788 3
    printf("new Lock:");
    prs2PrintLocks(currentLocks);
    printf("\n");
d791 13
d805 1
a805 3
     * Create a new tuple (i.e. a copy of the old tuple
     * with its rule lock field changed and replace the old
     * tuple in the RelationRelation
a806 7
    newTuple = prs2PutLocksInTuple(tuple, buffer,
				relationRelation,
				currentLocks);

    RelationReplaceHeapTuple(relationRelation, &(tuple->t_ctid),
			    newTuple, (double *)NULL);
    
d868 2
a869 1
			    updatedAttributeNumberP)
d873 1
d886 2
d894 16
a909 5
	/*
	 * then this is probably an `instead' rule with no action
	 * specified, e.g. "ON delete to DEPT WHERE ... DO INSTEAD"
	 */
	return(ActionTypeOther);
d921 5
a925 2
	if (!null(rangeTable)) {
	    strcpy(&(nameData.data[0]), CString(rt_relname(CAR(rangeTable))));
d947 1
d949 1
a949 1
		    NameIsEqual("CURRENT", relationName)) {
d964 16
d1006 10
d1023 19
d1044 3
d1048 3
a1050 2
prs2PutLocks(ruleId, relationOid, eventAttributeNo, updatedAttributeNo,
			eventType, actionType)
d1057 1
d1072 5
a1076 1
	lockType = LockTypeRetrieveRelation;
d1079 2
a1080 1
	actionType == ActionTypeReplaceCurrent) {
d1088 5
a1092 1
		lockType = LockTypeRetrieveWrite;
d1095 8
a1102 1
		lockType = LockTypeReplaceWrite;
d1105 8
a1112 1
		lockType = LockTypeAppendWrite;
d1115 5
a1119 1
		lockType = LockTypeDeleteWrite;
d1133 5
a1137 1
		lockType = LockTypeRetrieveAction;
d1140 5
a1144 1
		lockType = LockTypeReplaceAction;
d1147 5
a1151 1
		lockType = LockTypeAppendAction;
d1154 5
a1158 1
		lockType = LockTypeDeleteAction;
d1243 2
a1244 1
 * Ghange the parse tree of a 'REPLACE CURRENT(X = ...)' command to a
d1259 2
d1267 5
a1271 2
    if (!null(rangeTable)) {
	strcpy(&(nameData.data[0]), CString(rt_relname(CAR(rangeTable))));
d1280 3
a1282 1
    if (commandType!=REPLACE || !NameIsEqual("CURRENT", relationName)) {
d1284 1
a1284 1
	 * NO, this is not a REPLACE CURRENT command
d1307 27
@


1.6
log
@MakeConst now takes a new argument ("byval")
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.5 90/05/14 20:29:12 sp Exp Locker: sp $
d236 1
a236 1
    scanKey.data[0].argument.objectId.value = eventRelationOid;
d335 1
a335 1
    ruleNameKey[0].argument.name.value = ruleName;
d624 1
a624 1
    scanKey.data[0].argument.name.value = ruleName;
d670 1
a670 1
    scanKey.data[0].argument.objectId.value = ruleId;
d726 1
a726 1
    scanKey.data[0].argument.objectId.value = eventRelationOid;
@


1.5
log
@now it uses the parse tree returned by the parser (instead of
trying to read it from a file)
,
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.4 90/04/19 19:51:26 sp Exp $
d533 5
a537 4
	constant = MakeConst((ObjectId) 23,
			    (Size) 4,
			    value,
			    false);
@


1.4
log
@Now can handle 'view' rules...
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.3 90/04/03 17:11:43 sp Exp $
d67 1
a67 1
#define NO_PARSER_SUPPORT
@


1.3
log
@rules with 'on ... do replace CURRENT' are defined correctly
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.2 90/01/31 03:50:04 sp Exp $
d9 1
a9 1
 *   All teh routines needed to define a (tuple) PRS2 rule
d876 12
a887 1
	     * this is a retrieve (NOT a retrieve into...)
d960 8
a967 1
    if (actionType == ActionTypeRetrieveValue ||
@


1.2
log
@a little bit more clever when deciding what kind of locks to put!
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.1 90/01/11 14:42:49 sp Exp Locker: sp $
d13 3
d34 1
d62 1
d65 7
a85 2
    actionType = prs2FindActionTypeFromParse(parseTree);

d117 11
d176 3
a178 1
					    ruleQual,ruleAction);
d192 3
a194 1
		eventTargetAttributeNumber, eventType, actionType);
d455 3
a457 1
prs2GenerateActionPlans(isRuleInstead, ruleQual,ruleAction)
d461 2
d469 3
a472 1
    result = LispNil;
d476 10
d488 1
a488 1
	oneEntry = lispCons(lispString("instead"), LispNil);
d490 1
a490 1
	oneEntry = lispCons(lispString("not-instead"), LispNil);
d493 2
a494 1
    result = nappend1(result, oneEntry);
d496 1
d498 1
d505 42
a546 1
	onePlan = planner(ruleQual);
d548 1
a548 1
	oneEntry = lispCons(ruleQual, oneEntry);
d559 8
d822 4
d828 3
a830 1
prs2FindActionTypeFromParse(parseTree)
d832 2
d844 2
d847 2
d851 8
d869 2
a870 1
	    strcpy(relationName,CString(rt_relname(CAR(rangeTable))));
d874 1
a874 1
	if (commandType == RETRIEVE && !null(resultRelation)) {
d886 9
d909 1
d932 2
a933 1
prs2PutLocks(ruleId, relationOid, attributeNo, eventType, actionType)
d936 2
a937 1
AttributeNumber attributeNo;
d942 1
d951 5
d974 5
d1005 126
@


1.1
log
@Initial revision
@
text
@d6 1
a6 1
 *   $Header: RCS/prs2define.c,v 1.2 90/01/11 00:22:47 sp Exp Locker: sp $
a17 1
#include "ruledef.h"	/* PlanToString() defined here... */
d23 1
a43 1
    int	eventTypeInt;
d45 1
a67 1
    eventTypeInt = CInteger(GetRuleEventTypeFromParse(parseTree));
d73 2
a74 25
    /*
     * Note that the event type as stored in the parse tree is one of
     * RETRIEVE, REPLACE, APPEND or DELETE. All these symbols are
     * defined in "parse.h". So, we have to change them
     * into the appropriate "EventType" type.
     */
    switch (eventTypeInt) {
	case RETRIEVE:
	    eventType = EventTypeRetrieve;
	    break;
	case REPLACE:
	    eventType = EventTypeReplace;
	    break;
	case APPEND:
	    eventType = EventTypeAppend;
	    break;
	case DELETE:
	    eventType = EventTypeDelete;
	    break;
	default:
	    eventType = EventTypeInvalid;
	    elog(WARN, "prs2DefineTupleRule: Illegal event type (int) %d",
		eventTypeInt);
    } /* switch*/
    
a166 4
     *
     * Try first to findthe appropriate type of lock.
     * Normally if the rule updates the current tuple
     * we must put a LockTypeWrite lock.
d168 2
a170 6
    /* XXX Thsi wil not work! */
    lockType = LockTypeWrite;
    prs2PutLocks(ruleId, lockType,
		    eventTargetRelationOid,
		    eventTargetAttributeNumber);

d178 1
a178 1
 * prs2PutLocks
d186 1
a186 1
prs2PutLocks(ruleId, lockType, eventRelationOid, eventAttributeNumber)
d199 1
a199 1
    Prs2Locks currentLock;
d621 1
a621 1
    Prs2Locks currentLocks;
d678 190
@
