Re: [HACKERS] psql's help (the LIMIT stuff)

Поиск
Список
Период
Сортировка
От jwieck@debis.com (Jan Wieck)
Тема Re: [HACKERS] psql's help (the LIMIT stuff)
Дата
Msg-id m0zWM4W-000EBPC@orion.SAPserv.Hamburg.dsh.de
обсуждение исходный текст
Ответ на Re: [HACKERS] psql's help (the LIMIT stuff)  (Bruce Momjian <maillist@candle.pha.pa.us>)
Ответы Re: [HACKERS] psql's help (the LIMIT stuff)
Re: [HACKERS] psql's help (the LIMIT stuff)
Список pgsql-hackers
>
> > > >
> > > >     I hope the QUERY_LIMIT too.
> > >
> > > I still have that cnfify() possible fix to review for KQSO.  Are you
> > > still thinking limit for 6.4 final, or a minor release after that?
> >
> >     I  posted the part that is the minimum applied to 6.4 to make
> >     adding LIMIT later  non-initdb  earlier.  Anyway,  here  it's
> >     again.
>
> Already applied.  I assume it is the same as the one I applied.

    Seen,  thanks.  Your 'Applied' just arrived after I packed it
    again. It's the same.

> We are close to final, and can easily put it in 6.4.1, which I am sure
> we will need, and if we split CVS trees, you'll have lots of minor
> versions to pick from.  :-)
>
> Seems like it would be a nice minor release item, but the problem is
> that minor releases aren't tested as much as major ones.  How confident
> are you in the code?  What do others thing?

    I regression tested it,  and  did  additional  tests  in  the
    SPI/PL  area.  It  works.  It only touches the parser and the
    executor. Rules, planner/optimizer just bypass the values  in
    the  parsetree.  The  parser  and  the  executor are parts of
    Postgres I feel very familiar with (not so in the optimizer).
    I  trust  in  the  code  and  would  use  it  in a production
    environment.

    It's below.


Jan

--

#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#======================================== jwieck@debis.com (Jan Wieck) #


diff -cr src.orig/backend/commands/command.c src/backend/commands/command.c
*** src.orig/backend/commands/command.c    Fri Oct 16 11:53:38 1998
--- src/backend/commands/command.c    Fri Oct 16 12:56:44 1998
***************
*** 39,44 ****
--- 39,45 ----
  #include "utils/mcxt.h"
  #include "utils/portal.h"
  #include "utils/syscache.h"
+ #include "string.h"

  /* ----------------
   *        PortalExecutorHeapMemory stuff
***************
*** 101,106 ****
--- 102,108 ----
      int            feature;
      QueryDesc  *queryDesc;
      MemoryContext context;
+     Const        limcount;

      /* ----------------
       *    sanity checks
***************
*** 113,118 ****
--- 115,134 ----
      }

      /* ----------------
+      *    Create a const node from the given count value
+      * ----------------
+      */
+     memset(&limcount, 0, sizeof(limcount));
+     limcount.type        = T_Const;
+     limcount.consttype    = INT4OID;
+     limcount.constlen    = sizeof(int4);
+     limcount.constvalue    = (Datum)count;
+     limcount.constisnull    = FALSE;
+     limcount.constbyval    = TRUE;
+     limcount.constisset    = FALSE;
+     limcount.constiscast    = FALSE;
+
+     /* ----------------
       *    get the portal from the portal name
       * ----------------
       */
***************
*** 176,182 ****
      PortalExecutorHeapMemory = (MemoryContext)
          PortalGetHeapMemory(portal);

!     ExecutorRun(queryDesc, PortalGetState(portal), feature, count);

      if (dest == None)            /* MOVE */
          pfree(queryDesc);
--- 192,198 ----
      PortalExecutorHeapMemory = (MemoryContext)
          PortalGetHeapMemory(portal);

!     ExecutorRun(queryDesc, PortalGetState(portal), feature, (Node *)NULL, (Node *)&limcount);

      if (dest == None)            /* MOVE */
          pfree(queryDesc);
diff -cr src.orig/backend/executor/execMain.c src/backend/executor/execMain.c
*** src.orig/backend/executor/execMain.c    Fri Oct 16 11:53:38 1998
--- src/backend/executor/execMain.c    Fri Oct 16 20:05:19 1998
***************
*** 64,69 ****
--- 64,70 ----
  static void EndPlan(Plan *plan, EState *estate);
  static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
              Query *parseTree, CmdType operation,
+             int offsetTuples,
              int numberTuples, ScanDirection direction,
              void (*printfunc) ());
  static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (),
***************
*** 163,169 ****
   * ----------------------------------------------------------------
   */
  TupleTableSlot *
! ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
  {
      CmdType        operation;
      Query       *parseTree;
--- 164,170 ----
   * ----------------------------------------------------------------
   */
  TupleTableSlot *
! ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node *limcount)
  {
      CmdType        operation;
      Query       *parseTree;
***************
*** 171,176 ****
--- 172,179 ----
      TupleTableSlot *result;
      CommandDest dest;
      void        (*destination) ();
+     int        offset = 0;
+     int        count = 0;

      /******************
       *    sanity checks
***************
*** 191,196 ****
--- 194,289 ----
      estate->es_processed = 0;
      estate->es_lastoid = InvalidOid;

+     /******************
+      *    if given get the offset of the LIMIT clause
+      ******************
+      */
+     if (limoffset != NULL)
+     {
+         Const        *coffset;
+         Param        *poffset;
+         ParamListInfo    paramLI;
+         int        i;
+
+         switch (nodeTag(limoffset))
+         {
+             case T_Const:
+                 coffset = (Const *)limoffset;
+                 offset = (int)(coffset->constvalue);
+                 break;
+
+             case T_Param:
+                 poffset = (Param *)limoffset;
+                 paramLI = estate->es_param_list_info;
+
+                 if (paramLI == NULL)
+                     elog(ERROR, "parameter for limit offset not in executor state");
+                 for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
+                 {
+                     if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
+                         break;
+                 }
+                 if (paramLI[i].kind == PARAM_INVALID)
+                     elog(ERROR, "parameter for limit offset not in executor state");
+                 if (paramLI[i].isnull)
+                     elog(ERROR, "limit offset cannot be NULL value");
+                 offset = (int)(paramLI[i].value);
+
+                 break;
+
+             default:
+                 elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
+         }
+
+         if (offset < 0)
+             elog(ERROR, "limit offset cannot be negative");
+     }
+
+     /******************
+      *    if given get the count of the LIMIT clause
+      ******************
+      */
+     if (limcount != NULL)
+     {
+         Const        *ccount;
+         Param        *pcount;
+         ParamListInfo    paramLI;
+         int        i;
+
+         switch (nodeTag(limcount))
+         {
+             case T_Const:
+                 ccount = (Const *)limcount;
+                 count = (int)(ccount->constvalue);
+                 break;
+
+             case T_Param:
+                 pcount = (Param *)limcount;
+                 paramLI = estate->es_param_list_info;
+
+                 if (paramLI == NULL)
+                     elog(ERROR, "parameter for limit count not in executor state");
+                 for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
+                 {
+                     if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid)
+                         break;
+                 }
+                 if (paramLI[i].kind == PARAM_INVALID)
+                     elog(ERROR, "parameter for limit count not in executor state");
+                 if (paramLI[i].isnull)
+                     elog(ERROR, "limit count cannot be NULL value");
+                 count = (int)(paramLI[i].value);
+
+                 break;
+
+             default:
+                 elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount));
+         }
+
+         if (count < 0)
+             elog(ERROR, "limit count cannot be negative");
+     }
+
      switch (feature)
      {

***************
*** 199,205 ****
                                   plan,
                                   parseTree,
                                   operation,
!                                  ALL_TUPLES,
                                   ForwardScanDirection,
                                   destination);
              break;
--- 292,299 ----
                                   plan,
                                   parseTree,
                                   operation,
!                                  offset,
!                                  count,
                                   ForwardScanDirection,
                                   destination);
              break;
***************
*** 208,213 ****
--- 302,308 ----
                                   plan,
                                   parseTree,
                                   operation,
+                                  offset,
                                   count,
                                   ForwardScanDirection,
                                   destination);
***************
*** 222,227 ****
--- 317,323 ----
                                   plan,
                                   parseTree,
                                   operation,
+                                  offset,
                                   count,
                                   BackwardScanDirection,
                                   destination);
***************
*** 237,242 ****
--- 333,339 ----
                                   plan,
                                   parseTree,
                                   operation,
+                                  0,
                                   ONE_TUPLE,
                                   ForwardScanDirection,
                                   destination);
***************
*** 691,696 ****
--- 788,794 ----
              Plan *plan,
              Query *parseTree,
              CmdType operation,
+             int offsetTuples,
              int numberTuples,
              ScanDirection direction,
              void (*printfunc) ())
***************
*** 742,747 ****
--- 840,859 ----
          {
              result = NULL;
              break;
+         }
+
+         /******************
+          *    For now we completely execute the plan and skip
+          *    result tuples if requested by LIMIT offset.
+          *    Finally we should try to do it in deeper levels
+          *    if possible (during index scan)
+          *    - Jan
+          ******************
+          */
+         if (offsetTuples > 0)
+         {
+             --offsetTuples;
+             continue;
          }

          /******************
diff -cr src.orig/backend/executor/functions.c src/backend/executor/functions.c
*** src.orig/backend/executor/functions.c    Fri Oct 16 11:53:38 1998
--- src/backend/executor/functions.c    Fri Oct 16 19:01:02 1998
***************
*** 130,135 ****
--- 130,138 ----
                                       None);
          estate = CreateExecutorState();

+         if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)
+             elog(ERROR, "LIMIT clause from SQL functions not yet implemented");
+
          if (nargs > 0)
          {
              int            i;
***************
*** 200,206 ****

      feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;

!     return ExecutorRun(es->qd, es->estate, feature, 0);
  }

  static void
--- 203,209 ----

      feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;

!     return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL);
  }

  static void
diff -cr src.orig/backend/executor/spi.c src/backend/executor/spi.c
*** src.orig/backend/executor/spi.c    Fri Oct 16 11:53:39 1998
--- src/backend/executor/spi.c    Fri Oct 16 19:25:33 1998
***************
*** 791,796 ****
--- 791,798 ----
      bool        isRetrieveIntoRelation = false;
      char       *intoName = NULL;
      int            res;
+     Const        tcount_const;
+     Node        *count = NULL;

      switch (operation)
      {
***************
*** 825,830 ****
--- 827,865 ----
              return SPI_ERROR_OPUNKNOWN;
      }

+     /* ----------------
+      *    Get the query LIMIT tuple count
+      * ----------------
+      */
+     if (parseTree->limitCount != NULL)
+     {
+         /* ----------------
+          *      A limit clause in the parsetree overrides the
+          *    tcount parameter
+          * ----------------
+          */
+         count = parseTree->limitCount;
+     }
+     else
+     {
+         /* ----------------
+          *      No LIMIT clause in parsetree. Use a local Const node
+          *    to put tcount into it
+          * ----------------
+          */
+         memset(&tcount_const, 0, sizeof(tcount_const));
+         tcount_const.type           = T_Const;
+         tcount_const.consttype      = INT4OID;
+         tcount_const.constlen       = sizeof(int4);
+         tcount_const.constvalue     = (Datum)tcount;
+         tcount_const.constisnull    = FALSE;
+         tcount_const.constbyval     = TRUE;
+         tcount_const.constisset     = FALSE;
+         tcount_const.constiscast    = FALSE;
+
+         count = (Node *)&tcount_const;
+     }
+
      if (state == NULL)            /* plan preparation */
          return res;
  #ifdef SPI_EXECUTOR_STATS
***************
*** 845,851 ****
          return SPI_OK_CURSOR;
      }

!     ExecutorRun(queryDesc, state, EXEC_FOR, tcount);

      _SPI_current->processed = state->es_processed;
      if (operation == CMD_SELECT && queryDesc->dest == SPI)
--- 880,886 ----
          return SPI_OK_CURSOR;
      }

!     ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);

      _SPI_current->processed = state->es_processed;
      if (operation == CMD_SELECT && queryDesc->dest == SPI)
diff -cr src.orig/backend/parser/analyze.c src/backend/parser/analyze.c
*** src.orig/backend/parser/analyze.c    Fri Oct 16 11:53:41 1998
--- src/backend/parser/analyze.c    Fri Oct 16 13:29:27 1998
***************
*** 180,186 ****
--- 180,190 ----

          case T_SelectStmt:
              if (!((SelectStmt *) parseTree)->portalname)
+             {
                  result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
+                 result->limitOffset = ((SelectStmt *)parseTree)->limitOffset;
+                 result->limitCount = ((SelectStmt *)parseTree)->limitCount;
+             }
              else
                  result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
              break;
diff -cr src.orig/backend/parser/gram.y src/backend/parser/gram.y
*** src.orig/backend/parser/gram.y    Fri Oct 16 11:53:42 1998
--- src/backend/parser/gram.y    Sun Oct 18 22:20:36 1998
***************
*** 45,50 ****
--- 45,51 ----
  #include "catalog/catname.h"
  #include "utils/elog.h"
  #include "access/xact.h"
+ #include "catalog/pg_type.h"

  #ifdef MULTIBYTE
  #include "mb/pg_wchar.h"
***************
*** 163,169 ****
          sort_clause, sortby_list, index_params, index_list, name_list,
          from_clause, from_list, opt_array_bounds, nest_array_bounds,
          expr_list, attrs, res_target_list, res_target_list2,
!         def_list, opt_indirection, group_clause, TriggerFuncArgs

  %type <node>    func_return
  %type <boolean>    set_opt
--- 164,171 ----
          sort_clause, sortby_list, index_params, index_list, name_list,
          from_clause, from_list, opt_array_bounds, nest_array_bounds,
          expr_list, attrs, res_target_list, res_target_list2,
!         def_list, opt_indirection, group_clause, TriggerFuncArgs,
!         opt_select_limit

  %type <node>    func_return
  %type <boolean>    set_opt
***************
*** 192,197 ****
--- 194,201 ----

  %type <ival>    fetch_how_many

+ %type <node>    select_limit_value select_offset_value
+
  %type <list>    OptSeqList
  %type <defelt>    OptSeqElem

***************
*** 267,273 ****
          FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
          GRANT, GROUP, HAVING, HOUR_P,
          IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
!         JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
          MATCH, MINUTE_P, MONTH_P, NAMES,
          NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
          OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
--- 271,277 ----
          FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
          GRANT, GROUP, HAVING, HOUR_P,
          IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
!         JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LIMIT, LOCAL,
          MATCH, MINUTE_P, MONTH_P, NAMES,
          NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
          OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
***************
*** 299,305 ****
          INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
          LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
          NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
!         OIDS, OPERATOR, PASSWORD, PROCEDURAL,
          RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
          SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
          UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
--- 303,309 ----
          INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
          LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
          NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
!         OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
          RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
          SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
          UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
***************
*** 2591,2596 ****
--- 2595,2601 ----
               result from_clause where_clause
               group_clause having_clause
               union_clause sort_clause
+              opt_select_limit
                  {
                      SelectStmt *n = makeNode(SelectStmt);
                      n->unique = $2;
***************
*** 2602,2607 ****
--- 2607,2622 ----
                      n->havingClause = $8;
                      n->unionClause = $9;
                      n->sortClause = $10;
+                     if ($11 != NIL)
+                     {
+                         n->limitOffset = nth(0, $11);
+                         n->limitCount = nth(1, $11);
+                     }
+                     else
+                     {
+                         n->limitOffset = NULL;
+                         n->limitCount = NULL;
+                     }
                      $$ = (Node *)n;
                  }
          ;
***************
*** 2699,2704 ****
--- 2714,2794 ----
          | ASC                                    { $$ = "<"; }
          | DESC                                    { $$ = ">"; }
          | /*EMPTY*/                                { $$ = "<"; /*default*/ }
+         ;
+
+ opt_select_limit:    LIMIT select_offset_value ',' select_limit_value
+     { $$ = lappend(lappend(NIL, $2), $4); }
+         | LIMIT select_limit_value OFFSET select_offset_value
+     { $$ = lappend(lappend(NIL, $4), $2); }
+         | LIMIT select_limit_value
+     { $$ = lappend(lappend(NIL, NULL), $2); }
+         | OFFSET select_offset_value LIMIT select_limit_value
+     { $$ = lappend(lappend(NIL, $2), $4); }
+         | OFFSET select_offset_value
+     { $$ = lappend(lappend(NIL, $2), NULL); }
+         | /* EMPTY */
+     { $$ = NIL; }
+         ;
+
+ select_limit_value:    Iconst
+             {
+                 Const    *n = makeNode(Const);
+
+                 if ($1 < 1)
+                     elog(ERROR, "selection limit must be ALL or a positive integer value > 0");
+
+                 n->consttype    = INT4OID;
+                 n->constlen    = sizeof(int4);
+                 n->constvalue    = (Datum)$1;
+                 n->constisnull    = FALSE;
+                 n->constbyval    = TRUE;
+                 n->constisset    = FALSE;
+                 n->constiscast    = FALSE;
+                 $$ = (Node *)n;
+             }
+         | ALL
+             {
+                 Const    *n = makeNode(Const);
+                 n->consttype    = INT4OID;
+                 n->constlen    = sizeof(int4);
+                 n->constvalue    = (Datum)0;
+                 n->constisnull    = FALSE;
+                 n->constbyval    = TRUE;
+                 n->constisset    = FALSE;
+                 n->constiscast    = FALSE;
+                 $$ = (Node *)n;
+             }
+         | PARAM
+             {
+                 Param    *n = makeNode(Param);
+                 n->paramkind = PARAM_NUM;
+                 n->paramid = $1;
+                 n->paramtype = INT4OID;
+                 $$ = (Node *)n;
+             }
+         ;
+
+ select_offset_value:    Iconst
+             {
+                 Const    *n = makeNode(Const);
+
+                 n->consttype    = INT4OID;
+                 n->constlen    = sizeof(int4);
+                 n->constvalue    = (Datum)$1;
+                 n->constisnull    = FALSE;
+                 n->constbyval    = TRUE;
+                 n->constisset    = FALSE;
+                 n->constiscast    = FALSE;
+                 $$ = (Node *)n;
+             }
+         | PARAM
+             {
+                 Param    *n = makeNode(Param);
+                 n->paramkind = PARAM_NUM;
+                 n->paramid = $1;
+                 n->paramtype = INT4OID;
+                 $$ = (Node *)n;
+             }
          ;

  /*
diff -cr src.orig/backend/parser/keywords.c src/backend/parser/keywords.c
*** src.orig/backend/parser/keywords.c    Fri Oct 16 11:53:42 1998
--- src/backend/parser/keywords.c    Sun Oct 18 22:13:29 1998
***************
*** 128,133 ****
--- 128,134 ----
      {"leading", LEADING},
      {"left", LEFT},
      {"like", LIKE},
+     {"limit", LIMIT},
      {"listen", LISTEN},
      {"load", LOAD},
      {"local", LOCAL},
***************
*** 156,161 ****
--- 157,163 ----
      {"null", NULL_P},
      {"numeric", NUMERIC},
      {"of", OF},
+     {"offset", OFFSET},
      {"oids", OIDS},
      {"old", CURRENT},
      {"on", ON},
diff -cr src.orig/backend/rewrite/rewriteDefine.c src/backend/rewrite/rewriteDefine.c
*** src.orig/backend/rewrite/rewriteDefine.c    Fri Oct 16 11:53:46 1998
--- src/backend/rewrite/rewriteDefine.c    Fri Oct 16 13:48:55 1998
***************
*** 312,317 ****
--- 312,323 ----
          heap_close(event_relation);

          /*
+          * LIMIT in view is not supported
+          */
+         if (query->limitOffset != NULL || query->limitCount != NULL)
+             elog(ERROR, "LIMIT clause not supported in views");
+
+         /*
           * ... and finally the rule must be named _RETviewname.
           */
          sprintf(expected_name, "_RET%s", event_obj->relname);
diff -cr src.orig/backend/tcop/pquery.c src/backend/tcop/pquery.c
*** src.orig/backend/tcop/pquery.c    Fri Oct 16 11:53:47 1998
--- src/backend/tcop/pquery.c    Fri Oct 16 14:02:36 1998
***************
*** 40,46 ****
  #include "commands/command.h"

  static char *CreateOperationTag(int operationType);
! static void ProcessQueryDesc(QueryDesc *queryDesc);


  /* ----------------------------------------------------------------
--- 40,46 ----
  #include "commands/command.h"

  static char *CreateOperationTag(int operationType);
! static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount);


  /* ----------------------------------------------------------------
***************
*** 205,211 ****
   * ----------------------------------------------------------------
   */
  static void
! ProcessQueryDesc(QueryDesc *queryDesc)
  {
      Query       *parseTree;
      Plan       *plan;
--- 205,211 ----
   * ----------------------------------------------------------------
   */
  static void
! ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
  {
      Query       *parseTree;
      Plan       *plan;
***************
*** 330,336 ****
       *     actually run the plan..
       * ----------------
       */
!     ExecutorRun(queryDesc, state, EXEC_RUN, 0);

      /* save infos for EndCommand */
      UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
--- 330,336 ----
       *     actually run the plan..
       * ----------------
       */
!     ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);

      /* save infos for EndCommand */
      UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
***************
*** 373,377 ****
          print_plan(plan, parsetree);
      }
      else
!         ProcessQueryDesc(queryDesc);
  }
--- 373,377 ----
          print_plan(plan, parsetree);
      }
      else
!         ProcessQueryDesc(queryDesc, parsetree->limitOffset, parsetree->limitCount);
  }
diff -cr src.orig/include/executor/executor.h src/include/executor/executor.h
*** src.orig/include/executor/executor.h    Fri Oct 16 11:53:56 1998
--- src/include/executor/executor.h    Fri Oct 16 12:04:17 1998
***************
*** 83,89 ****
   * prototypes from functions in execMain.c
   */
  extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
! extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count);
  extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
  extern HeapTuple ExecConstraints(char *caller, Relation rel, HeapTuple tuple);
  #ifdef QUERY_LIMIT
--- 83,89 ----
   * prototypes from functions in execMain.c
   */
  extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
! extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node
*limcount);
  extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
  extern HeapTuple ExecConstraints(char *caller, Relation rel, HeapTuple tuple);
  #ifdef QUERY_LIMIT

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Sferacarta Software
Дата:
Сообщение: Re[2]: [HACKERS] psql \d command
Следующее
От: Gerald Gryschuk
Дата:
Сообщение: Re: [INTERFACES] New docs and ODBC for Unix