home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / executor / ex_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  36.6 KB  |  1,360 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    ex_main.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    top level executor interface routines
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *       ExecMain    - main interface to executor
  10.  *
  11.  *   NOTES
  12.  *    
  13.  *   IDENTIFICATION
  14.  *    $Header: /private/postgres/src/executor/RCS/ex_main.c,v 1.23 1992/08/26 23:18:06 mer Exp $
  15.  * ----------------------------------------------------------------
  16.  */
  17.  
  18. #define EXEC_RULEMANAGER 1
  19.  
  20. #include "tcop/slaves.h"
  21. #include "executor/executor.h"
  22.  
  23.  RcsId("$Header: /private/postgres/src/executor/RCS/ex_main.c,v 1.23 1992/08/26 23:18:06 mer Exp $");
  24.  
  25. /* ----------------------------------------------------------------
  26.  *    random junk
  27.  * ----------------------------------------------------------------
  28.  */
  29. bool  ExecIsInitialized = false;
  30. Const ConstTrue;
  31. Const ConstFalse;
  32.  
  33. extern int Quiet;
  34.  
  35. extern     List rule;
  36.  
  37. /* ----------------------------------------------------------------
  38.  *    InitializeExecutor
  39.  *
  40.  *    This is only called once - by ExecMain, the first time
  41.  *    the user executes a query.
  42.  * ----------------------------------------------------------------
  43.  */
  44. void
  45. InitializeExecutor()
  46. {
  47.     MemoryContext oldContext;
  48.     ObjectId    boolType = 16;    /* see local.bki */
  49.     Size    boolLen = 1;    /* these should come from lookups */
  50.     Datum    datumTrue;
  51.     Datum    datumFalse;
  52.  
  53.     /* ----------------
  54.      *    make certain we are in the top memory context
  55.      *  or else this stuff will go away after the first transaction.
  56.      * ----------------
  57.      */
  58.     oldContext = MemoryContextSwitchTo(TopMemoryContext);
  59.  
  60.     /* ----------------
  61.      *    initialize ConstTrue and ConstFalse
  62.      * ----------------
  63.      */
  64.     datumTrue  = Int32GetDatum((int32) true);
  65.     datumFalse = Int32GetDatum((int32) false);
  66.     
  67.     ConstTrue =  MakeConst(boolType, boolLen, datumTrue,  false, true);
  68.     ConstFalse = MakeConst(boolType, boolLen, datumFalse, false, true);
  69.     
  70. #ifdef EXEC_DEBUGVARIABLEFILE
  71.     /* ----------------
  72.      *    initialize debugging variables
  73.      * ----------------
  74.      */
  75.     if (! Quiet)
  76.     printf("==== using %s\n", EXEC_DEBUGVARIABLEFILE);
  77.     
  78.     DebugVariableFileSet(EXEC_DEBUGVARIABLEFILE);
  79. #endif EXEC_DEBUGVARIABLEFILE
  80.     
  81.     /* ----------------
  82.      *    return to old memory context
  83.      * ----------------
  84.      */
  85.     (void) MemoryContextSwitchTo(oldContext);
  86.  
  87.     ExecIsInitialized = true;
  88. }
  89.  
  90.  
  91. /* ----------------------------------------------------------------
  92.  *       ExecMain
  93.  *   
  94.  *       This is the main routine of the executor module. It accepts
  95.  *       the query descriptor from the traffic cop and executes the
  96.  *       query plan.
  97.  *   
  98.  *       Parameter:
  99.  *          argList --(commandType parseTree queryPlan queryState queryFeature)
  100.  * ----------------------------------------------------------------
  101.  */
  102.  
  103. List
  104. ExecMain(queryDesc, estate, feature)
  105.     List     queryDesc;
  106.     EState     estate;
  107.     List     feature;
  108. {
  109.     int        operation;
  110.     List     parseTree;
  111.     Plan    plan;
  112.     List     result;
  113.     CommandDest dest;
  114.     void    (*destination)();
  115.     
  116.     /* ----------------
  117.      *    sanity checks
  118.      * ----------------
  119.      */
  120.     Assert(!lispNullp(queryDesc));
  121.     
  122.     /* ----------------
  123.      *    initialize if necessary
  124.      * ----------------
  125.      */
  126.     if (!ExecIsInitialized)
  127.     InitializeExecutor();
  128.     
  129.     /* ----------------
  130.      *    extract information from the query descriptor
  131.      *  and the query feature.
  132.      * ----------------
  133.      */
  134.     operation =   CAtom(GetOperation(queryDesc));
  135.     parseTree =   QdGetParseTree(queryDesc);
  136.     plan =      QdGetPlan(queryDesc);
  137.     dest =      QdGetDest(queryDesc);
  138.     destination = (void (*)()) DestToFunction(dest);
  139.     
  140.     /* ----------------
  141.      *    ExecMain is typically called from the tcop three
  142.      *   times:
  143.      *
  144.      *    first time,   command = EXEC_START        initialize
  145.      *   second time, command = EXEC_RUN        run the plan
  146.      *   last time,   command = EXEC_END        cleanup
  147.      * ----------------
  148.      */
  149.     result =    LispNil;
  150.     
  151.     switch(CInteger(FeatureGetCommand(feature))) {
  152.     /* ----------------
  153.      *    EXEC_START, EXEC_RUN, EXEC_END are the
  154.      *    most general cases..
  155.      * ----------------
  156.      */
  157.     case EXEC_START:
  158.     /* result is a tuple descriptor */
  159.     result = InitPlan(operation,
  160.               parseTree,
  161.               plan,
  162.               estate);
  163.     /* reset buffer refcount.  the current refcounts
  164.      * are saved and will be restored at the end of
  165.      * this ExecMain cycle.
  166.      *
  167.      * this makes sure that when ExecMain's are
  168.      * called recursively as for tuple level rules
  169.      * or postquel functions, the buffers pinned
  170.      * by one ExecMain will not be unpinned by another
  171.      * ExecMain.
  172.      */
  173.     BufferRefCountReset(get_es_refcount(estate));
  174.     break;
  175.         
  176.     case EXEC_RUN:
  177.     /* result is a tuple or LispNil */
  178.     result = (List) ExecutePlan(estate,
  179.                     plan,
  180.                     parseTree,
  181.                     operation,
  182.                     ALL_TUPLES,
  183.                     EXEC_FRWD,
  184.                     destination);
  185.     break;
  186.     
  187.     case EXEC_END:
  188.     /* result is a tuple or LispNil */
  189.     result = EndPlan(plan, estate);
  190.     /* restore saved refcounts. */
  191.     BufferRefCountRestore(get_es_refcount(estate));
  192.     break;
  193.  
  194.     /* ----------------
  195.      *    retrieve next n "forward" tuples
  196.      * ----------------
  197.      */
  198.     case EXEC_FOR:
  199.     /* result is a tuple or LispNil */
  200.     result = (List) ExecutePlan(estate,
  201.                     plan,
  202.                     parseTree,
  203.                     operation,
  204.                     CInteger(FeatureGetCount(feature)),
  205.                     EXEC_FRWD,
  206.                     destination);
  207.     break;
  208.  
  209.     /* ----------------
  210.      *    retrieve next n "backward" tuples
  211.      * ----------------
  212.      */
  213.     case EXEC_BACK:
  214.     /* result is a tuple or LispNil */
  215.     result = (List) ExecutePlan(estate,
  216.                     plan,
  217.                     parseTree,
  218.                     operation,
  219.                     CInteger(FeatureGetCount(feature)),
  220.                     EXEC_BKWD,
  221.                     destination);
  222.     break;
  223.     
  224.     /* ----------------
  225.      *    return one tuple but don't "retrieve" it.
  226.      *    (this is used by the rule manager..) -cim 9/14/89
  227.      * ----------------
  228.      */
  229.     case EXEC_RETONE:
  230.     /* result is a tuple or LispNil */
  231.     result = (List) ExecutePlan(estate,
  232.                     plan,
  233.                     parseTree,
  234.                     operation,
  235.                     ONE_TUPLE,
  236.                     EXEC_FRWD,
  237.                     destination);
  238.     break;
  239.     default:
  240.     elog(DEBUG, "ExecMain: Unknown command.");
  241.     break;
  242.     }
  243.     
  244.     return result;
  245. }
  246.  
  247. /* ----------------------------------------------------------------
  248.  *       InitPlan
  249.  *   
  250.  *       Initialises the query plan: open files, allocate storage
  251.  *       and start up the rule manager
  252.  * ----------------------------------------------------------------
  253.  */
  254. extern Relation    CopyRelDescUsing();
  255.  
  256. List
  257. InitPlan(operation, parseTree, plan, estate)
  258.     int            operation;
  259.     EState         estate;
  260.     List         parseTree;
  261.     Plan         plan;
  262. {    
  263.     List        parseRoot;
  264.     List         rangeTable;
  265.     List        resultRelation;
  266.     Relation         relationRelationDesc;
  267.     Relation            intoRelationDesc;
  268.     
  269.     TupleDescriptor     tupType;
  270.     List         targetList;
  271.     int             len;
  272.     List         attinfo;
  273.     extern List        MakeList();
  274.     
  275. #ifdef PALLOC_DEBUG
  276.     {
  277.     extern int query_tuple_count;
  278.     query_tuple_count = 0;
  279.     }
  280. #endif PALLOC_DEBUG    
  281.     
  282.     /* ----------------
  283.      *  get information from query descriptor
  284.      * ----------------
  285.      */
  286.     parseRoot =       parse_root(parseTree);
  287.     rangeTable =    parse_tree_range_table(parseTree);
  288.     resultRelation =     parse_tree_result_relation(parseTree);
  289.     
  290.     /* ----------------
  291.      *  initialize the node's execution state
  292.      * ----------------
  293.      */
  294.     set_es_range_table(estate, rangeTable);
  295.     set_es_error_message(estate, (Name) "Foo bar");
  296.     
  297.     /* ----------------
  298.      *    initialize the BaseId counter so node base_id's
  299.      *  are assigned correctly.  Someday baseid's will have to
  300.      *  be stored someplace other than estate because they
  301.      *  should be unique per query planned.
  302.      * ----------------
  303.      */
  304.     set_es_BaseId(estate, 1);
  305.     
  306.     /* ----------------
  307.      *    initialize result relation stuff
  308.      * ----------------
  309.      */
  310.     set_es_result_rel_scanstate(estate, NULL);
  311.  
  312.     if (resultRelation != NULL && operation != RETRIEVE) {
  313.     /* ----------------
  314.      *    if we have a result relation, open the it and
  315.      *    initialize the result relation info stuff.
  316.      * ----------------
  317.      */
  318.     RelationInfo    resultRelationInfo;
  319.     Index         resultRelationIndex;
  320.     List        rtentry;
  321.     ObjectId    resultRelationOid;
  322.     Relation     resultRelationDesc;
  323.     RelationRuleInfo resRelRuleInfo;
  324.     
  325.     resultRelationIndex = CInteger(resultRelation);
  326.     rtentry =          rt_fetch(resultRelationIndex, rangeTable);
  327.     resultRelationOid =   CInteger(rt_relid(rtentry));
  328.     resultRelationDesc =  heap_open(resultRelationOid);
  329.     resultRelationInfo = MakeRelationInfo(resultRelationIndex,
  330.                           resultRelationDesc,
  331.                           0,      /* num indices */
  332.                           NULL,   /* index descs */
  333.                           NULL);  /* index key info */
  334.     /* ----------------
  335.      *  open indices on result relation and save descriptors
  336.      *  in the result relation information..
  337.      * ----------------
  338.      */
  339.     ExecOpenIndices(resultRelationOid, resultRelationInfo);
  340.     
  341.     set_es_result_relation_info(estate, resultRelationInfo);
  342.  
  343.     /* ----------------
  344.      *  Initialize the result relation rule info.
  345.      * ----------------
  346.      */
  347.     resRelRuleInfo = prs2MakeRelationRuleInfo(resultRelationDesc,
  348.                           operation);
  349.     
  350.     set_es_result_rel_ruleinfo(estate, resRelRuleInfo);
  351.     } else {
  352.     /* ----------------
  353.      *     if no result relation, then set state appropriately
  354.      * ----------------
  355.      */
  356.     set_es_result_relation_info(estate, NULL);
  357.     }
  358.     
  359.     relationRelationDesc = heap_openr(RelationRelationName);
  360.     set_es_relation_relation_descriptor(estate, relationRelationDesc);
  361.     
  362.     /* ----------------
  363.      *    initialize the executor "tuple" table.
  364.      * ----------------
  365.      */
  366.     {
  367.     int        nSlots     = ExecCountSlotsNode(plan);
  368.     TupleTable tupleTable = ExecCreateTupleTable(nSlots+10);
  369.  
  370.     set_es_tupleTable(estate, tupleTable);
  371.     }
  372.  
  373.     /* ----------------
  374.      *     initialize the private state information for
  375.      *       all the nodes in the query tree.  This opens
  376.      *       files, allocates storage and leaves us ready
  377.      *     to start processing tuples..
  378.      * ----------------
  379.      */
  380.     ExecInitNode(plan, estate, NULL);
  381.     
  382.     /* ----------------
  383.      *     get the tuple descriptor describing the type
  384.      *       of tuples to return.. (this is especially important
  385.      *       if we are creating a relation with "retrieve into")
  386.      * ----------------
  387.      */
  388.     tupType =    ExecGetTupType(plan);             /* tuple descriptor */
  389.     targetList = get_qptargetlist(plan);
  390.     len =      ExecTargetListLength(targetList); /* number of attributes */
  391.  
  392.     /* ----------------
  393.      *    now that we have the target list, initialize the junk filter
  394.      *    if this is a REPLACE or a DELETE query.
  395.      *    We also init the junk filter if this is an append query
  396.      *    (there might be some rule lock info there...)
  397.      *    NOTE: in the future we might want to initialize the junk
  398.      *      filter for all queries.
  399.      * ----------------
  400.      */
  401.     if (operation == REPLACE || operation == DELETE || operation == APPEND) {
  402.     JunkFilter j = (JunkFilter) ExecInitJunkFilter(targetList);
  403.     set_es_junkFilter(estate, j);
  404.     } else
  405.     set_es_junkFilter(estate, NULL);
  406.     
  407.     /* ----------------
  408.      *    initialize the "into" relation
  409.      * ----------------
  410.      */
  411.     intoRelationDesc = (Relation) NULL;
  412.     
  413.     if (operation == RETRIEVE) {
  414.     List         resultDesc;
  415.     int          dest;
  416.     String         intoName;
  417.     char        archiveMode;
  418.     ObjectId    intoRelationId;
  419.     
  420.     resultDesc = root_result_relation(parseRoot);
  421.     if (! lispNullp(resultDesc)) {
  422.         dest = CAtom(CAR(resultDesc));
  423.         if (dest == INTO) {
  424.         /* ----------------
  425.          *  create the "into" relation
  426.          *
  427.          *  note: there is currently no way for the user to
  428.          *      specify the desired archive mode of the
  429.          *      "into" relation...
  430.          * ----------------
  431.          */
  432.         intoName = CString(CADR(resultDesc));
  433.         archiveMode = 'n';
  434.         
  435.         intoRelationId = heap_create(intoName,
  436.                          archiveMode,
  437.                          len,
  438.                          DEFAULT_SMGR,
  439.                          (struct attribute **)tupType);
  440.         
  441.         /* ----------------
  442.          *  XXX rather than having to call setheapoverride(true)
  443.          *    and then back to false, we should change the
  444.          *    arguments to heap_open() instead..
  445.          * ----------------
  446.          */
  447.         setheapoverride(true);
  448.         
  449.         intoRelationDesc = heap_open(intoRelationId);
  450.         local_heap_open(intoRelationDesc);
  451.         
  452.         setheapoverride(false);
  453.         
  454.         } else if (dest == INTOTEMP) {
  455.         /* ----------------
  456.          *  this is only for the parallel backends to save results in
  457.          *  temporary relations and collect them later
  458.          * ----------------
  459.          */
  460.  
  461.         intoRelationDesc = ExecCreatR(len, tupType, -1);
  462.         if (! IsMaster) {
  463.             SlaveTmpRelDescInit();
  464.             SlaveInfoP[MyPid].resultTmpRelDesc =
  465.                CopyRelDescUsing(intoRelationDesc, SlaveTmpRelDescAlloc);
  466.         }
  467.         }
  468.     }
  469.     }
  470.  
  471.     set_es_into_relation_descriptor(estate, intoRelationDesc);
  472.     
  473.     /* ----------------
  474.      *    return the type information..
  475.      * ----------------
  476.      */
  477.     attinfo = MakeList(lispInteger(len), tupType, -1);
  478.     
  479.     return
  480.     attinfo;
  481. }
  482.  
  483. /* ----------------------------------------------------------------
  484.  *       EndPlan
  485.  *   
  486.  *       Cleans up the query plan -- closes files and free up storages
  487.  * ----------------------------------------------------------------
  488.  */
  489.  
  490. List
  491. EndPlan(plan, estate)
  492.     Plan        plan;
  493.     EState        estate;
  494. {
  495.     RelationInfo     resultRelationInfo;
  496.     List        resultRelationInfoList;
  497.     Relation        intoRelationDesc;
  498.    
  499.     /* ----------------
  500.      *    get information from state
  501.      * ----------------
  502.      */
  503.     resultRelationInfo =  get_es_result_relation_info(estate);
  504.     resultRelationInfoList = get_es_result_relation_info_list(estate);
  505.     intoRelationDesc =      get_es_into_relation_descriptor(estate);
  506.    
  507.     /* ----------------
  508.      *   shut down the query
  509.      * ----------------
  510.      */
  511.     ExecEndNode(plan);
  512.       
  513.     /* ----------------
  514.      *    destroy the executor "tuple" table.
  515.      * ----------------
  516.      */
  517.     {
  518.     TupleTable tupleTable = (TupleTable) get_es_tupleTable(estate);
  519.     ExecDestroyTupleTable(tupleTable,true);    /* was missing last arg */
  520.     set_es_tupleTable(estate, NULL);
  521.     }
  522.         
  523.     /* ----------------
  524.      *   close the result relations if necessary
  525.      * ----------------
  526.      */
  527.     if (resultRelationInfo != NULL) {
  528.     Relation resultRelationDesc;
  529.     
  530.     resultRelationDesc = get_ri_RelationDesc(resultRelationInfo);
  531.     heap_close(resultRelationDesc);
  532.     
  533.     /* ----------------
  534.      *  close indices on the result relation
  535.      * ----------------
  536.      */
  537.     ExecCloseIndices(resultRelationInfo);
  538.     }
  539.  
  540.     while (resultRelationInfoList != LispNil) {
  541.     Relation resultRelationDesc;
  542.  
  543.     resultRelationInfo = (RelationInfo) CAR(resultRelationInfoList);
  544.     resultRelationDesc = get_ri_RelationDesc(resultRelationInfo);
  545.     heap_close(resultRelationDesc);
  546.     resultRelationInfoList = CDR(resultRelationInfoList);
  547.     }
  548.          
  549.     /* ----------------
  550.      *   close the "into" relation if necessary
  551.      * ----------------
  552.      */
  553.     if (intoRelationDesc != NULL)
  554.     if (ParallelExecutorEnabled())
  555.         /* have to use shared buffer pool for paralle backends */
  556.         heap_close(intoRelationDesc);
  557.     else
  558.         local_heap_close(intoRelationDesc);
  559.     
  560.     /* ----------------
  561.      *    return successfully
  562.      * ----------------
  563.      */
  564.     return
  565.     LispTrue;
  566. }
  567.  
  568. /* ----------------------------------------------------------------
  569.  *       ExecutePlan
  570.  *   
  571.  *       processes the query plan to retrieve 'tupleCount' tuples in the
  572.  *       direction specified.
  573.  *       Retrieves all tuples if tupleCount is 0
  574.  *
  575.  *|    XXX direction seems not to be used (I hope this isn't
  576.  *|         another example of lisp global scoping) -cim 8/7/89
  577.  * ----------------------------------------------------------------
  578.  */
  579.  
  580. TupleTableSlot
  581. ExecutePlan(estate, plan, parseTree, operation, numberTuples,
  582.         direction, printfunc)
  583.     EState     estate;
  584.     Plan    plan;
  585.     LispValue    parseTree;
  586.     int        operation;
  587.     int     numberTuples;
  588.     int     direction;
  589.     void     (*printfunc)();
  590. {
  591.     Relation        intoRelationDesc;
  592.     JunkFilter        junkfilter;
  593.     
  594.     TupleTableSlot    slot;
  595.     ItemPointer        tupleid = NULL;
  596.     ItemPointerData    tuple_ctid;
  597.     int             current_tuple_count;
  598.     TupleTableSlot    result;    /* result to return to ExecMain */
  599.     RuleLock        locks;
  600.     
  601.     /* ----------------
  602.      *  get information
  603.      * ----------------
  604.      */
  605.     intoRelationDesc =    get_es_into_relation_descriptor(estate);
  606.     
  607.     /* ----------------
  608.      *    initialize local variables
  609.      * ----------------
  610.      */
  611.     slot         = NULL;
  612.     current_tuple_count = 0;
  613.     result         = NULL;
  614.  
  615.     /* ----------------
  616.      *    Set the direction.
  617.      * ----------------
  618.      */
  619.     set_es_direction(estate, direction);
  620.  
  621.     /* ----------------
  622.      *    Loop until we've processed the proper number
  623.      *  of tuples from the plan..
  624.      * ----------------
  625.      */
  626.     
  627.     for(;;) {
  628.     /* ----------------
  629.      *    Execute the plan and obtain a tuple
  630.      * ----------------
  631.      */
  632.      if (operation != NOTIFY)
  633.         slot = ExecProcNode(plan);
  634.     
  635.     /* ----------------
  636.      *    if the tuple is null, then we assume
  637.      *    there is nothing more to process so
  638.      *    we just return null...
  639.      * ----------------
  640.      */
  641.     if (TupIsNull((Pointer) slot) && operation != NOTIFY) {
  642.         result = NULL;
  643.         break;
  644.     }
  645.     
  646.     /* ----------------
  647.      *    if we have a junk filter, then project a new
  648.      *    tuple with the junk removed.
  649.      *
  650.      *    Store this new "clean" tuple in the place of the 
  651.      *    original tuple.
  652.      *
  653.      *      Also, extract all the junk ifnormation we need.
  654.      * ----------------
  655.      */
  656.     if ((junkfilter = get_es_junkFilter(estate)) != (JunkFilter)NULL) {
  657.         Datum     datum;
  658.         NameData     attrName;
  659.         HeapTuple     newTuple;
  660.         Boolean     isNull;
  661.  
  662.         /* ---------------
  663.          * extract the 'ctid' junk attribute.
  664.          * ---------------
  665.          */
  666.         if (operation == REPLACE || operation == DELETE) {
  667.         strcpy(&(attrName), "ctid");
  668.         if (! ExecGetJunkAttribute(junkfilter,
  669.                        slot,
  670.                        &attrName,
  671.                        &datum,
  672.                        &isNull))
  673.             elog(WARN,"ExecutePlan: NO (junk) `ctid' was found!");
  674.         
  675.         if (isNull) 
  676.             elog(WARN,"ExecutePlan: (junk) `ctid' is NULL!");
  677.         
  678.         tupleid = (ItemPointer) DatumGetPointer(datum);
  679.         tuple_ctid = *tupleid; /* make sure we don't free the ctid!! */
  680.         tupleid = &tuple_ctid;
  681.         }
  682.  
  683.         /* ---------------
  684.          * Find the "rule lock" info. (if it is there!)
  685.          * ---------------
  686.          */
  687.         strcpy(&(attrName), "lock");
  688.         if (! ExecGetJunkAttribute(junkfilter,
  689.                        slot,
  690.                        &attrName,
  691.                        &datum,
  692.                        &isNull))
  693.         locks = InvalidRuleLock;
  694.         else {
  695.         if (isNull) {
  696.             /*
  697.              * this is an error (I think...)
  698.              * If we have a "lock" junk attribute, then it better
  699.              * have a value!
  700.              * NOTE: an empty lock i.e. "(numOfLocks: 0)"::lock
  701.              * is a good non-null value, i.e. still 'isNull' must
  702.              * be false
  703.              */
  704.             elog(WARN, "ExecutePlan: (junk) rule lock is NULL!");
  705.         }
  706.         
  707.         locks = (RuleLock) DatumGetPointer(datum);
  708.         
  709.         /*
  710.          * Make a copy of the lock, because when we call
  711.          * amreplace, we will (probably?) free it and the
  712.          * "locks" as returned by "ExecGetJunkAttribute" is
  713.          * something that -for some reason- causes problems when
  714.          * you try to pfree it! (believe me, I've tried it!).
  715.          */
  716.         locks = prs2CopyLocks(locks);
  717.         }
  718.  
  719.         /* ---------------
  720.          * Finally create a new "clean" tuple with all junk attributes
  721.          * removed and with the new "rule lock" info.
  722.          * ---------------
  723.          */
  724.         newTuple = ExecRemoveJunk(junkfilter, slot);
  725.         
  726.         slot = (TupleTableSlot)
  727.         ExecStoreTuple((Pointer) newTuple, /* tuple to store */
  728.                    (Pointer) slot,     /* destination slot */
  729.                    InvalidBuffer,     /* this tuple has no buffer */
  730.                    true);         /* tuple should be pfreed */
  731.     } else {
  732.         locks = InvalidRuleLock;
  733.     }
  734.  
  735. #ifdef PALLOC_DEBUG    
  736.     /* ----------------
  737.      *    if debugging memory allocations, print memory dump
  738.      *    every so often
  739.      * ----------------
  740.      */
  741.     {
  742.         extern int query_tuple_count, query_tuple_max;
  743.         if (query_tuple_max && query_tuple_max == ++query_tuple_count) {
  744.         query_tuple_count = 0;
  745.         dump_palloc_list("ExecutePlan", true);
  746.         }
  747.     }
  748. #endif PALLOC_DEBUG
  749.     
  750.     /* ----------------
  751.      *    now that we have a tuple, do the appropriate thing
  752.      *    with it.. either return it to the user, add
  753.      *    it to a relation someplace, delete it from a
  754.      *    relation, or modify some of it's attributes.
  755.      * ----------------
  756.      */
  757.     
  758.     switch(operation) {
  759.     case RETRIEVE:
  760.         result = ExecRetrieve(slot,       /* slot containing tuple */
  761.                   printfunc,      /* print function */
  762.                   intoRelationDesc); /* "into" relation */
  763.         break;
  764.         
  765.     case APPEND:
  766.         result = ExecAppend(slot, tupleid, estate, locks);
  767.         break;
  768.         
  769.     case DELETE:
  770.         result = ExecDelete(slot, tupleid, estate);
  771.         break;
  772.         
  773.     case REPLACE:
  774.         result = ExecReplace(slot, tupleid, estate, parseTree, locks);
  775.         break;
  776.  
  777.         /* Total hack. I'm ignoring any accessor functions for
  778.            Relation, RelationTupleForm, NameData.
  779.            Assuming that NameData.data has offset 0.
  780.            */
  781.     case NOTIFY: {
  782.         RelationInfo rInfo = get_es_result_relation_info(estate);
  783.         Relation rDesc = get_ri_RelationDesc(rInfo);
  784.         Async_Notify(&rDesc->rd_rel->relname);
  785.         result = NULL;
  786.         current_tuple_count = 0;
  787.         numberTuples = 1;
  788.         elog(DEBUG, "ExecNotify %s",&rDesc->rd_rel->relname);
  789.     }
  790.         break;
  791.         
  792.     default:
  793.         elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
  794.         result = NULL;
  795.         break;
  796.     }
  797.     /* ----------------
  798.      *    check our tuple count.. if we've returned the
  799.      *    proper number then return, else loop again and
  800.      *    process more tuples..
  801.      * ----------------
  802.      */
  803.     current_tuple_count += 1;
  804.     if (numberTuples == current_tuple_count)
  805.         break;
  806.     }
  807.  
  808.     /* ----------------
  809.      *    here, result is either a slot containing a tuple in the case
  810.      *  of a RETRIEVE or NULL otherwise.
  811.      * ----------------
  812.      */
  813.     return result;        
  814. }
  815.  
  816. /* ----------------------------------------------------------------
  817.  *    ExecRetrieve
  818.  *
  819.  *    RETRIEVEs are easy.. we just pass the tuple to the appropriate
  820.  *    print function.  The only complexity is when we do a
  821.  *    "retrieve into", in which case we insert the tuple into
  822.  *    the appropriate relation (note: this is a newly created relation
  823.  *    so we don't need to worry about indices or locks.)
  824.  * ----------------------------------------------------------------
  825.  */
  826.  
  827. TupleTableSlot
  828. ExecRetrieve(slot, printfunc, intoRelationDesc)
  829.     TupleTableSlot    slot;
  830.     void         (*printfunc)();
  831.     Relation         intoRelationDesc;
  832. {
  833.     HeapTuple         tuple;
  834.     TupleDescriptor     attrtype;
  835.  
  836.     /* ----------------
  837.      *    get the heap tuple out of the tuple table slot
  838.      * ----------------
  839.      */
  840.     tuple = (HeapTuple) ExecFetchTuple((Pointer) slot);
  841.     attrtype =        ExecSlotDescriptor((Pointer) slot);
  842.     
  843.     /* ----------------
  844.      *    insert the tuple into the "into relation"
  845.      * ----------------
  846.      */
  847.     if (intoRelationDesc != NULL) {
  848.     if (ParallelExecutorEnabled())
  849.         /* for parallel executor, has to insert through shared buffer */
  850.         (void) heap_insert(intoRelationDesc, tuple, NULL);
  851.     else
  852.         (void) local_heap_insert(intoRelationDesc, tuple);
  853.     IncrAppended();
  854.     }
  855.     
  856.     /* ----------------
  857.      *    send the tuple to the front end (or the screen)
  858.      * ----------------
  859.      */
  860.     (*printfunc)(tuple, attrtype);
  861.     IncrRetrieved();
  862.     
  863.     /* ----------------
  864.      *    return the tuple slot back to ExecutePlan
  865.      * ----------------
  866.      */
  867.     return
  868.     slot;
  869. }
  870.  
  871. /* ----------------------------------------------------------------
  872.  *    ExecAppend
  873.  *
  874.  *    APPENDs are trickier.. we have to insert the tuple into
  875.  *    the base relation, insert appropriate tuples into the
  876.  *    index relations and if we step on some locks along the way,
  877.  *    run the rule manager..
  878.  * ----------------------------------------------------------------
  879.  */
  880.  
  881. TupleTableSlot
  882. ExecAppend(slot, tupleid, estate, newlocks)
  883.     TupleTableSlot    slot;
  884.     ItemPointer        tupleid;
  885.     EState        estate;
  886.     RuleLock        newlocks;
  887. {
  888.     HeapTuple     tuple;
  889.     RelationInfo resultRelationInfo;
  890.     Relation     resultRelationDesc;
  891.     int         numIndices;
  892.     RuleLock      locks;
  893.     RuleLock     indexLocks;
  894.     HeapTuple     returnedTuple;
  895.     Buffer     returnedBuffer;
  896.     Prs2Status   status;
  897.     Prs2Stub     ruleStubs;
  898.     RuleLock      stubLocks;
  899.     HeapTuple     tempTuple;
  900.     ObjectId     newId;
  901.  
  902.     /* ----------------
  903.      *    get the heap tuple out of the tuple table slot
  904.      * ----------------
  905.      */
  906.     tuple = (HeapTuple) ExecFetchTuple((Pointer) slot);
  907.     
  908.     /* ----------------
  909.      *    get information on the result relation
  910.      * ----------------
  911.      */
  912.     resultRelationInfo = get_es_result_relation_info(estate);
  913.     resultRelationDesc = get_ri_RelationDesc(resultRelationInfo);
  914.     
  915.     /* ----------------
  916.      *    process rules
  917.      * ----------------
  918.      */
  919. #ifdef EXEC_RULEMANAGER
  920.     /*
  921.      * NOTE: the check for rule stubs etc. is done by the rule manager.
  922.      */
  923.  
  924.     /*
  925.      * Now call the rule manager, but only if necessary.
  926.      */
  927.     if (prs2MustCallRuleManager(get_es_result_rel_ruleinfo(estate),
  928.                 (HeapTuple) NULL,
  929.                 InvalidBuffer,
  930.                 APPEND))
  931.     {
  932.     status = prs2Main(estate,
  933.               (RelationRuleInfo) NULL,/*only aplies to retrieves*/
  934.               APPEND,
  935.               0,
  936.               resultRelationDesc,
  937.               (HeapTuple) NULL,
  938.               InvalidBuffer,
  939.               tuple,
  940.               InvalidBuffer,
  941.               (HeapTuple) NULL,
  942.               InvalidBuffer,
  943.               (AttributeNumberPtr) NULL,
  944.               0,
  945.               &returnedTuple,
  946.               &returnedBuffer);
  947.     if (status == PRS2_STATUS_INSTEAD) {
  948.         /*
  949.          * do not append the tuple
  950.          */
  951.         return NULL;
  952.         
  953.     } else if (status == PRS2_STATUS_TUPLE_CHANGED) {
  954.         /* ----------------
  955.          *  store the returnedTuple in the slot and free the old
  956.          *  copy of the tuple.
  957.          * ----------------
  958.          */
  959.         ExecStoreTuple((Pointer) returnedTuple, /* tuple to store */
  960.                (Pointer) slot,           /* destination slot */
  961.                returnedBuffer,
  962.                true);        /* tuple should be pfreed */
  963.         
  964.         tuple = returnedTuple;
  965.     }
  966.     } /*if prs2MustCallRuleManager*/
  967.  
  968. #endif EXEC_RULEMANAGER
  969.     
  970.     /* ----------------
  971.      *    have to add code to preform unique checking here.
  972.      *  cim -12/1/89
  973.      * ----------------
  974.      */
  975.     
  976.     /* ----------------
  977.      * If the user has explicitly specified some locks in the "replace"
  978.      * statement, ignore all rule stubs & stuff and just put these
  979.      * locks in the tuple. Obviously this is guaranteed to mess things
  980.      * up if the user does not *really* know what he is doing,
  981.      * i.e. if it is not me!  _sp.
  982.      * ----------------
  983.      */
  984.     if (newlocks != InvalidRuleLock)
  985.     HeapTupleSetRuleLock(tuple, InvalidBuffer, newlocks);
  986.     
  987.     /* ----------------
  988.      *    insert the tuple
  989.      * ----------------
  990.      */
  991.     newId = heap_insert(resultRelationDesc, /* relation desc */
  992.             tuple,            /* heap tuple */
  993.             0);            /* return: offset */
  994.     IncrAppended();
  995.     UpdateAppendOid(newId);
  996.     
  997.     /* ----------------
  998.      *    process indices
  999.      * 
  1000.      *    Note: heap_insert adds a new tuple to a relation.  As a side
  1001.      *  effect, the tupleid of the new tuple is placed in the new
  1002.      *  tuple's t_ctid field.
  1003.      * ----------------
  1004.      */
  1005.     numIndices = get_ri_NumIndices(resultRelationInfo);
  1006.     if (numIndices > 0) {
  1007.     indexLocks = ExecInsertIndexTuples(tuple,
  1008.                        &(tuple->t_ctid),
  1009.                        estate);
  1010.     }
  1011.  
  1012.     /* ----------------
  1013.      *    XXX will we ever return anything meaningful?
  1014.      * ----------------
  1015.      */
  1016.     return NULL;
  1017. }
  1018.  
  1019. /* ----------------------------------------------------------------
  1020.  *    ExecDelete
  1021.  *
  1022.  *    DELETE is like append, we delete the tuple and its
  1023.  *    index tuples and then run the rule manager if necessary.
  1024.  * ----------------------------------------------------------------
  1025.  */
  1026.  
  1027. TupleTableSlot
  1028. ExecDelete(slot, tupleid, estate)
  1029.     TupleTableSlot    slot;
  1030.     ItemPointer        tupleid;
  1031.     EState        estate;
  1032. {
  1033.     HeapTuple     tuple;
  1034.     RelationInfo resultRelationInfo;
  1035.     Relation     resultRelationDesc;
  1036.     
  1037.     RuleLock     locks;
  1038.     RuleLock     indexLocks;
  1039.     Prs2Status   status;
  1040.     HeapTuple    oldTuple;
  1041.     Buffer       oldTupleBuffer;
  1042.     HeapTuple    rawTuple;
  1043.     Buffer     rawTupleBuffer;
  1044.     HeapTuple    dummyTuple;
  1045.     Buffer       dummyBuffer;
  1046.  
  1047.     /* ----------------
  1048.      *    get the heap tuple out of the tuple table slot
  1049.      * ----------------
  1050.      */
  1051.     tuple = (HeapTuple) ExecFetchTuple((Pointer) slot);
  1052.  
  1053.     /* ----------------
  1054.      *    get the result relation information
  1055.      * ----------------
  1056.      */
  1057.     resultRelationInfo = get_es_result_relation_info(estate);
  1058.     resultRelationDesc = get_ri_RelationDesc(resultRelationInfo);
  1059.  
  1060. #ifdef EXEC_RULEMANAGER
  1061.     /* ----------------
  1062.      *        process rules
  1063.      * ----------------
  1064.      */
  1065.     
  1066.     /* ----------------
  1067.      * find the old & raw tuples
  1068.      *
  1069.      * NOTE: currently we do not store them anywhere!
  1070.      * therefore we will use the 'tupleid' to find the original
  1071.      * tuple (the "raw" tuple") and we will assume that "old" tuple
  1072.      * is the same as the "raw" tuple.
  1073.      * The only problem is the extra time spent to reactivate
  1074.      * backward chaining rules already activated but... what
  1075.      * else can we do ?
  1076.      */
  1077.     rawTuple = heap_fetch(resultRelationDesc,
  1078.               NowTimeQual,
  1079.               tupleid,
  1080.               &rawTupleBuffer);
  1081.     
  1082.     oldTuple = rawTuple;
  1083.     oldTupleBuffer = rawTupleBuffer;
  1084.  
  1085.     /* ----------------
  1086.      * XXX!!
  1087.      * NOTE: in the current implementation where only RelationLevel
  1088.      * locks are used, the rule manager must look in pg_relation
  1089.      * to find the locks of "oldTuple".
  1090.      */
  1091.     if (prs2MustCallRuleManager(get_es_result_rel_ruleinfo(estate),
  1092.                 oldTuple, oldTupleBuffer, DELETE))
  1093.     {
  1094.     status = prs2Main(estate,
  1095.               (RelationRuleInfo) NULL,/*only aplies to retrieves*/
  1096.               DELETE,
  1097.               0,      /* userid */
  1098.               resultRelationDesc,
  1099.               oldTuple,
  1100.               oldTupleBuffer,
  1101.               (HeapTuple) NULL,
  1102.               InvalidBuffer,
  1103.               rawTuple,
  1104.               rawTupleBuffer,
  1105.               (AttributeNumberPtr) NULL,
  1106.               0,
  1107.               &dummyTuple,
  1108.               &dummyBuffer);
  1109.     
  1110.     if (status == PRS2_STATUS_INSTEAD) {
  1111.       /*
  1112.        * there was an instead rule, do not do the delete...
  1113.        */
  1114.       return NULL;
  1115.     }
  1116.     } /*if prs2MustCallRuleManager*/
  1117.     if (BufferIsValid(rawTupleBuffer)) ReleaseBuffer(rawTupleBuffer);
  1118.  
  1119. #endif EXEC_RULEMANAGER
  1120.     
  1121.     /* ----------------
  1122.      *    delete the tuple
  1123.      * ----------------
  1124.      */
  1125.     locks = heap_delete(resultRelationDesc, /* relation desc */
  1126.             tupleid);        /* item pointer to tuple */
  1127.     
  1128.     IncrDeleted();
  1129.     
  1130.     /* ----------------
  1131.      *    Note: Normally one would think that we have to
  1132.      *          delete index tuples associated with the
  1133.      *          heap tuple now..
  1134.      *
  1135.      *          ... but in POSTGRES, we have no need to do this
  1136.      *        because the vaccuum daemon automatically
  1137.      *          opens an index scan and deletes index tuples
  1138.      *          when it finds deleted heap tuples. -cim 9/27/89
  1139.      * ----------------
  1140.      */
  1141.     
  1142.     /* ----------------
  1143.      *    XXX will we ever return anything meaningful?
  1144.      * ----------------
  1145.      */
  1146.     return NULL;
  1147. }
  1148.  
  1149. /* ----------------------------------------------------------------
  1150.  *    ExecReplace
  1151.  *
  1152.  *    note: we can't run replace queries with transactions
  1153.  *      off because replaces are actually appends and our
  1154.  *      scan will mistakenly loop forever, replacing the tuple
  1155.  *      it just appended..  This should be fixed but until it
  1156.  *      is, we don't want to get stuck in an infinite loop
  1157.  *      which corrupts your database..
  1158.  * ----------------------------------------------------------------
  1159.  */
  1160.  
  1161. TupleTableSlot
  1162. ExecReplace(slot, tupleid, estate, parseTree, newlocks)
  1163.     TupleTableSlot    slot;
  1164.     ItemPointer        tupleid;
  1165.     EState        estate;
  1166.     LispValue        parseTree;
  1167.     RuleLock        newlocks;
  1168. {
  1169.     HeapTuple        tuple;
  1170.     RelationInfo     resultRelationInfo;
  1171.     Relation         resultRelationDesc;
  1172.     RuleLock         locks;
  1173.     RuleLock         indexLocks;
  1174.     int             numIndices;
  1175.     HeapTuple         rawTuple;
  1176.     Buffer        rawTupleBuffer = InvalidBuffer;
  1177.     HeapTuple         oldTuple;
  1178.     Buffer         oldTupleBuffer;
  1179.     HeapTuple         changedTuple;
  1180.     Buffer            changedTupleBuffer;
  1181.     AttributeNumberPtr     attributeArray;
  1182.     AttributeNumber        numberOfReplacedAttributes;
  1183.     LispValue         targetList;
  1184.     LispValue        t;
  1185.     Resdom            resdom;
  1186.     Prs2Status            status;
  1187.     Prs2Stub         ruleStubs;
  1188.     RuleLock         stubLocks;
  1189.     HeapTuple        tempTuple;
  1190.  
  1191.  
  1192.     /* ----------------
  1193.      *    abort the operation if not running transactions
  1194.      * ----------------
  1195.      */
  1196.     if (IsBootstrapProcessingMode()) {
  1197.     elog(DEBUG, "ExecReplace: replace can't run without transactions");
  1198.     return NULL;
  1199.     }
  1200.     
  1201.     /* ----------------
  1202.      *    get the heap tuple out of the tuple table slot
  1203.      * ----------------
  1204.      */
  1205.     tuple = (HeapTuple) ExecFetchTuple((Pointer) slot);
  1206.  
  1207.     /* ----------------
  1208.      *    get the result relation information
  1209.      * ----------------
  1210.      */
  1211.     resultRelationInfo = get_es_result_relation_info(estate);
  1212.     resultRelationDesc = get_ri_RelationDesc(resultRelationInfo);
  1213.  
  1214.     /* ----------------
  1215.      *  process rules
  1216.      * ----------------
  1217.      */
  1218. #ifdef EXEC_RULEMANAGER    
  1219.  
  1220.  
  1221.     /* ----------------
  1222.      * find the old & raw tuples
  1223.      *
  1224.      * NOTE: currently we do not store them anywhere!
  1225.      * therefore we will use the 'tupleid' to find the original
  1226.      * tuple (the "raw" tuple") and we will assume that "old" tuple
  1227.      * is the same as the "raw" tuple.
  1228.      * The only problem is the extra time spent to reactivate
  1229.      * backward chaining rules already activated but... what
  1230.      * else can we do ?
  1231.      */
  1232.     rawTuple = heap_fetch(resultRelationDesc,
  1233.               NowTimeQual,
  1234.               tupleid,
  1235.               &rawTupleBuffer);
  1236.     
  1237.     oldTuple = rawTuple;
  1238.     oldTupleBuffer = rawTupleBuffer;
  1239.  
  1240.  
  1241.     if (prs2MustCallRuleManager(get_es_result_rel_ruleinfo(estate),
  1242.                 oldTuple, oldTupleBuffer, REPLACE))
  1243.     {
  1244.                     
  1245.     /* ----------------
  1246.      * find the attributes replaced...
  1247.      */
  1248.     attributeArray = (AttributeNumberPtr)
  1249.         palloc( sizeof(AttributeNumber)    *
  1250.             RelationGetNumberOfAttributes(resultRelationDesc));
  1251.     
  1252.     numberOfReplacedAttributes = 0;
  1253.     targetList = parse_targetlist(parseTree);
  1254.     foreach (t, targetList) {
  1255.         resdom = (Resdom) CAR(CAR(t));
  1256.         attributeArray[numberOfReplacedAttributes] = get_resno(resdom);
  1257.         numberOfReplacedAttributes += 1;
  1258.     }
  1259.  
  1260.     status = prs2Main(estate,
  1261.               (RelationRuleInfo) NULL,/*only aplies to retrieves*/
  1262.               REPLACE,
  1263.               0,      /* user id */
  1264.               resultRelationDesc,
  1265.               oldTuple,
  1266.               oldTupleBuffer,
  1267.               tuple,
  1268.               InvalidBuffer,
  1269.               rawTuple,
  1270.               oldTupleBuffer,
  1271.               attributeArray,
  1272.               numberOfReplacedAttributes,
  1273.               &changedTuple,
  1274.               &changedTupleBuffer);
  1275.     
  1276.     if (status == PRS2_STATUS_INSTEAD) {
  1277.         /*
  1278.          * An instead rule has been found, do not do the replace...
  1279.          */
  1280.         return NULL;
  1281.     }    
  1282.     
  1283.  
  1284.     if (status == PRS2_STATUS_TUPLE_CHANGED) {
  1285.         ExecStoreTuple((Pointer) changedTuple, /* tuple to store */
  1286.                (Pointer) slot,    /* destination slot */
  1287.                InvalidBuffer,     /* this tuple has no buffer */
  1288.                true);        /* tuple should be pfreed */
  1289.         
  1290.         tuple = changedTuple;
  1291.     }
  1292.     } /*if prs2MustCallRuleManager */
  1293.     if (BufferIsValid(oldTupleBuffer)) ReleaseBuffer(oldTupleBuffer);
  1294.     
  1295. #endif EXEC_RULEMANAGER
  1296.     
  1297.     /* ----------------
  1298.      *    have to add code to preform unique checking here.
  1299.      *  in the event of unique tuples, this becomes a deletion
  1300.      *  of the original tuple affected by the replace.
  1301.      *  cim -12/1/89
  1302.      * ----------------
  1303.      */
  1304.     
  1305.     /* ----------------
  1306.      * If the user has explicitly specified some locks in the "replace"
  1307.      * statement, ignore all rule stubs & stuff and just put these
  1308.      * locks in the tuple. Obviously this is guaranteed to mess things
  1309.      * up if the user does not *really* know what he is doing,
  1310.      * i.e. if it is not me!  _sp.
  1311.      * ----------------
  1312.      */
  1313.     if (newlocks != InvalidRuleLock)
  1314.     HeapTupleSetRuleLock(tuple, InvalidBuffer, newlocks);
  1315.  
  1316.     /* ----------------
  1317.      *    replace the heap tuple
  1318.      * ----------------
  1319.      */
  1320.     locks = heap_replace(resultRelationDesc, /* relation desc */
  1321.              tupleid,         /* item ptr of tuple to replace */
  1322.              tuple);         /* replacement heap tuple */
  1323.     
  1324.     IncrReplaced();
  1325.     
  1326.     /* ----------------
  1327.      *    Note: instead of having to update the old index tuples
  1328.      *        associated with the heap tuple, all we do is form
  1329.      *          and insert new index tuples..  This is because
  1330.      *        replaces are actually deletes and inserts and
  1331.      *          index tuple deletion is done automagically by
  1332.      *          the vaccuum deamon.. All we do is insert new
  1333.      *          index tuples.  -cim 9/27/89
  1334.      * ----------------
  1335.      */
  1336.     
  1337.     /* ----------------
  1338.      *    process indices
  1339.      *
  1340.      *    heap_replace updates a tuple in the base relation by invalidating
  1341.      *  it and then appending a new tuple to the relation.  As a side
  1342.      *  effect, the tupleid of the new tuple is placed in the new
  1343.      *  tuple's t_ctid field.  So we now insert index tuples using
  1344.      *  the new tupleid stored there.
  1345.      * ----------------
  1346.      */
  1347.     numIndices = get_ri_NumIndices(resultRelationInfo);
  1348.     if (numIndices > 0) {
  1349.     indexLocks = ExecInsertIndexTuples(tuple,
  1350.                        &(tuple->t_ctid),
  1351.                        estate);
  1352.     }
  1353.     
  1354.     /* ----------------
  1355.      *    XXX will we ever return anything meaningful?
  1356.      * ----------------
  1357.      */
  1358.     return NULL;
  1359. }
  1360.