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

  1. /* ------------------------------------------------
  2.  *   FILE
  3.  *     functions.c
  4.  *
  5.  *   DESCRIPTION
  6.  *    Routines to handle functions called from the executor
  7.  *      Putting this stuff in fmgr makes the postmaster a mess....
  8.  *
  9.  *
  10.  *   IDENTIFICATION
  11.  *       $Header: /private/postgres/src/executor/RCS/functions.c,v 1.15 1992/08/25 17:47:58 mer Exp $
  12.  * ------------------------------------------------
  13.  */
  14. #include "tmp/postgres.h"
  15.  
  16. #include "parser/parsetree.h"
  17. #include "parser/parse.h" /* for NOT used in macros in ExecEvalExpr */
  18. #include "nodes/primnodes.h"
  19. #include "nodes/relation.h"
  20. #include "nodes/execnodes.h"
  21. #include "nodes/plannodes.h"
  22. #include "planner/keys.h"
  23. #include "catalog/pg_proc.h"
  24. #include "tcop/pquery.h"
  25. #include "utils/params.h"
  26. #include "utils/fmgr.h"
  27. #include "utils/fcache.h"
  28. #include "utils/log.h"
  29. #include "catalog/syscache.h"
  30. #include "catalog/pg_language.h"
  31. #include "access/heapam.h"
  32. #include "executor/executor.h"
  33.  
  34. #include "rules/prs2locks.h"    /*
  35.                  * this because we have to worry about
  36.                  * copying rule locks when we copy tuples
  37.                  * d*mn you sp!! -mer 7 July 1992
  38.                  */
  39. #undef new
  40.  
  41. typedef enum {F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE} ExecStatus;
  42.  
  43. typedef struct local_es {
  44.     List qd;
  45.     EState estate;
  46.     struct local_es *next;
  47.     ExecStatus status;
  48. } execution_state;
  49.  
  50. #define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)
  51.  
  52. Datum
  53. ProjectAttribute(TD, tlist, tup,isnullP)
  54.      TupleDescriptor TD;
  55.      List tlist;
  56.      HeapTuple tup;
  57.      Boolean *isnullP;
  58. {
  59.     Datum val,valueP;
  60.     Var  attrVar = (Var)CADR(tlist);
  61.     AttributeNumber attrno = get_varattno(attrVar);
  62.  
  63.     
  64.     val = HeapTupleGetAttributeValue(tup,
  65.                      InvalidBuffer,
  66.                      attrno,
  67.                      TD,
  68.                      isnullP);
  69.     if (*isnullP)
  70.     return NULL;
  71.  
  72.     valueP = datumCopy(val,
  73.                TD->data[attrno-1]->atttypid,
  74.                TD->data[attrno-1]->attbyval,
  75.                (Size) TD->data[attrno-1]->attlen);
  76.     return valueP;
  77. }
  78.  
  79. execution_state *
  80. init_execution_state(fcache, args)
  81.      FunctionCachePtr fcache;
  82.      char *args[];
  83. {
  84.     execution_state       *newes;
  85.     execution_state       *nextes;
  86.     execution_state       *preves;
  87.     LispValue             parseTree_list;
  88.     LispValue             planTree_list;
  89.     char                  *src;
  90.     int nargs;
  91.  
  92.     nargs = fcache->nargs;
  93.  
  94.     newes = (execution_state *) palloc(sizeof(execution_state));
  95.     nextes = newes;
  96.     preves = (execution_state *)NULL;
  97.  
  98.  
  99.     planTree_list = (LispValue)
  100.     pg_plan(fcache->src, fcache->argOidVect, nargs, &parseTree_list, None);
  101.  
  102.     for ( ;
  103.      planTree_list;
  104.      planTree_list = CDR(planTree_list),parseTree_list = CDR(parseTree_list)
  105.     )
  106.     {
  107.     EState    estate;
  108.     LispValue parseTree = CAR(parseTree_list);
  109.     Plan planTree = (Plan)CAR(planTree_list);
  110.  
  111.     if (!nextes)
  112.         nextes = (execution_state *) palloc(sizeof(execution_state));
  113.     if (preves)
  114.         preves->next = nextes;
  115.  
  116.     nextes->next = NULL;
  117.     nextes->status = F_EXEC_START;
  118.     nextes->qd = CreateQueryDesc(parseTree,
  119.                      planTree,
  120.                      args,
  121.                      fcache->argOidVect,
  122.                      nargs,
  123.                      None);
  124.     estate = CreateExecutorState();
  125.  
  126.     if (nargs > 0)
  127.     {
  128.         int           i;
  129.         ParamListInfo paramLI;
  130.  
  131.         paramLI =
  132.         (ParamListInfo)palloc((nargs+1)*sizeof(ParamListInfoData));
  133.  
  134.         bzero(paramLI, nargs*sizeof(ParamListInfoData));
  135.         set_es_param_list_info(estate, paramLI);
  136.  
  137.         for (i=0; i<nargs; paramLI++, i++)
  138.         {
  139.             paramLI->kind = PARAM_NUM;
  140.             paramLI->id = i+1;
  141.             paramLI->isnull = false;
  142.             paramLI->value = NULL;
  143.         }
  144.         paramLI->kind = PARAM_INVALID;
  145.     }
  146.     else
  147.         set_es_param_list_info(estate, (ParamListInfo)NULL);
  148.         nextes->estate = estate;
  149.     preves = nextes;
  150.     nextes = (execution_state *)NULL;
  151.     }
  152.  
  153.     return newes;
  154. }
  155.  
  156. List
  157. postquel_start(es)
  158.     execution_state *es;
  159. {
  160.     return ExecMain(es->qd, es->estate,
  161.             lispCons(lispInteger(EXEC_START), LispNil));
  162. }
  163.  
  164. TupleTableSlot
  165. postquel_getnext(es)
  166.     execution_state *es;
  167. {
  168.     LispValue feature;
  169.  
  170.     feature = (LAST_POSTQUEL_COMMAND(es)) ?
  171.     lispCons(lispInteger(EXEC_RETONE), LispNil) :
  172.     lispCons(lispInteger(EXEC_RUN), LispNil);
  173.  
  174.     return (TupleTableSlot) ExecMain(es->qd, es->estate, feature);
  175. }
  176.  
  177. List
  178. postquel_end(es)
  179.     execution_state *es;
  180. {
  181.     List qd;
  182.     EState estate;
  183.     List res3;
  184.     res3 = ExecMain(es->qd, es->estate,
  185.             lispCons(lispInteger(EXEC_END), LispNil));
  186.     return res3;
  187. }
  188.  
  189. void
  190. postquel_sub_params(es, nargs, args, nullV)
  191.     execution_state  *es;
  192.     int              nargs;
  193.     char             *args[];
  194.     bool             *nullV;
  195. {
  196.     ParamListInfo paramLI;
  197.     EState estate;
  198.  
  199.     estate = es->estate;
  200.     paramLI = get_es_param_list_info(estate);
  201.  
  202.     while (paramLI->kind != PARAM_INVALID)
  203.     {
  204.     if (paramLI->kind == PARAM_NUM)
  205.     {
  206.         Assert(paramLI->id <= nargs);
  207.         paramLI->value = (Datum)args[(paramLI->id - 1)];
  208.         paramLI->isnull = nullV[(paramLI->id - 1)];
  209.     }
  210.     paramLI++;
  211.     }
  212. }
  213.  
  214. TupleTableSlot
  215. copy_function_result(fcache, resultSlot)
  216.     FunctionCachePtr fcache;
  217.     TupleTableSlot   resultSlot;
  218. {
  219.     TupleTableSlot  funcSlot;
  220.     TupleDescriptor resultTd;
  221.     HeapTuple newTuple;
  222.     HeapTuple oldTuple;
  223.  
  224.     Assert(! TupIsNull((Pointer)resultSlot));
  225.     oldTuple = (HeapTuple)ExecFetchTuple(resultSlot);
  226.  
  227.     funcSlot = (TupleTableSlot)fcache->funcSlot;
  228.     
  229.     if (funcSlot == (TupleTableSlot)NULL)
  230.     return resultSlot;
  231.  
  232.     resultTd = ExecSlotDescriptor(resultSlot);
  233.     /*
  234.      * When the funcSlot is NULL we have to initialize the funcSlot's
  235.      * tuple descriptor.
  236.      */
  237.     if (TupIsNull((Pointer)funcSlot))
  238.     {
  239.     int             i      = 0;
  240.     TupleDescriptor funcTd = ExecSlotDescriptor(funcSlot);
  241.  
  242.     while (i < oldTuple->t_natts)
  243.     {
  244.         funcTd->data[i] =
  245.             (AttributeTupleForm)palloc(sizeof(FormData_pg_attribute));
  246.         bcopy(resultTd->data[i],
  247.           funcTd->data[i],
  248.           sizeof(FormData_pg_attribute));
  249.         i++;
  250.     }
  251.     }
  252.  
  253.     newTuple = (HeapTuple)heap_copysimple(oldTuple);
  254.  
  255.     return (TupleTableSlot)
  256.     ExecStoreTuple((Pointer)newTuple,
  257.            (Pointer)funcSlot,
  258.            InvalidBuffer,
  259.            true);
  260. }
  261.  
  262. Datum
  263. postquel_execute(es, fcache, fTlist, args, isNull)
  264.     execution_state  *es;
  265.     FunctionCachePtr fcache;
  266.     LispValue        fTlist;
  267.     char             **args;
  268.     bool             *isNull;
  269. {
  270.     TupleTableSlot slot;
  271.     Datum          value;
  272.  
  273.     if (es->status == F_EXEC_START)
  274.     {
  275.     (void) postquel_start(es);
  276.     es->status = F_EXEC_RUN;
  277.     }
  278.  
  279.     if (fcache->nargs > 0)
  280.         postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
  281.  
  282.     slot = postquel_getnext(es);
  283.  
  284.     if (TupIsNull((Pointer)slot))
  285.     {
  286.     postquel_end(es);
  287.     es->status = F_EXEC_DONE;
  288.     *isNull = true;
  289.     /*
  290.      * If this isn't the last command for the function
  291.      * we have to increment the command
  292.      * counter so that subsequent commands can see changes made
  293.      * by previous ones.
  294.      */
  295.     if (!LAST_POSTQUEL_COMMAND(es)) CommandCounterIncrement();
  296.     return (Datum)NULL;
  297.     }
  298.  
  299.     if (LAST_POSTQUEL_COMMAND(es))
  300.     {
  301.     TupleTableSlot resSlot;
  302.  
  303.     /*
  304.      * Copy the result.  copy_function_result is smart enough
  305.      * to do nothing when no action is called for.  This helps
  306.      * reduce the logic and code redundancy here.
  307.      */
  308.     resSlot = copy_function_result(fcache, slot);
  309.     if (fTlist != (LispValue)NULL)
  310.     {
  311.         HeapTuple tup;
  312.         List      tle = CAR(fTlist);
  313.  
  314.         tup = (HeapTuple)ExecFetchTuple((Pointer)resSlot);
  315.         value = ProjectAttribute(ExecSlotDescriptor(resSlot),
  316.                      tle,
  317.                      tup,
  318.                      isNull);
  319.     }
  320.     else
  321.     {
  322.         value = (Datum)resSlot;
  323.         *isNull = false;
  324.     }
  325.  
  326.     /*
  327.      * If this is a single valued function we have to end the
  328.      * function execution now.
  329.      */
  330.     if (fcache->oneResult)
  331.     {
  332.         (void)postquel_end(es);
  333.         es->status = F_EXEC_DONE;
  334.     }
  335.  
  336.     return value;
  337.     }
  338.     /*
  339.      * If this isn't the last command for the function, we don't
  340.      * return any results, but we have to increment the command
  341.      * counter so that subsequent commands can see changes made
  342.      * by previous ones.
  343.      */
  344.     CommandCounterIncrement();
  345.     return (Datum)NULL;
  346. }
  347.  
  348. Datum
  349. postquel_function(funcNode, args, isNull, isDone)
  350.      Func funcNode;
  351.      char *args[];
  352.      bool *isNull;
  353.      bool *isDone;
  354. {
  355.     HeapTuple        tup;
  356.     execution_state  *es;
  357.     LispValue         tlist;
  358.     Datum            result;
  359.     FunctionCachePtr fcache = get_func_fcache(funcNode);
  360.  
  361.     es = (execution_state *) fcache->func_state;
  362.     if (es == NULL)
  363.     {
  364.     es = init_execution_state(fcache, args);
  365.     fcache->func_state = (char *) es;
  366.     }
  367.  
  368.     while (es && es->status == F_EXEC_DONE)
  369.         es = es->next;
  370.  
  371.     Assert(es);
  372.     /*
  373.      * Execute each command in the function one after another until we're
  374.      * executing the final command and get a result or we run out of
  375.      * commands.
  376.      */
  377.     while (es != (execution_state *)NULL)
  378.     {
  379.     result = postquel_execute(es,
  380.                   fcache,
  381.                   get_func_tlist(funcNode),
  382.                   args,
  383.                   isNull);
  384.     if (es->status != F_EXEC_DONE)
  385.         break;
  386.     es = es->next;
  387.     }
  388.  
  389.     /*
  390.      * If we've gone through every command in this function, we are done.
  391.      */
  392.     if (es == (execution_state *)NULL)
  393.     {
  394.     /*
  395.      * Reset the execution states to start over again
  396.      */
  397.     es = (execution_state *)fcache->func_state;
  398.     while (es)
  399.     {
  400.         es->status = F_EXEC_START;
  401.         es = es->next;
  402.     }
  403.     /*
  404.      * Let caller know we're finished.
  405.      */
  406.     *isDone = true;
  407.     return (fcache->oneResult) ? result : (Datum)NULL;
  408.     }
  409.     /*
  410.      * If we got a result from a command within the function it has
  411.      * to be the final command.  All others shouldn't be returing
  412.      * anything.
  413.      */
  414.     Assert ( LAST_POSTQUEL_COMMAND(es) );
  415.     *isDone = false;
  416.  
  417.     return result;
  418. }
  419.