Re: When do we lose column names?

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: When do we lose column names?
Дата
Msg-id 28413.1321500388@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: When do we lose column names?  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: When do we lose column names?  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
I wrote:
> and the issue seems to be that in execution of a RowExpr, the
> executor doesn't pay any attention to preserving the column names
> in the generated tupledesc --- see the ExecTypeFromExprList call
> in execQual.c. ...
> We could certainly make it do that --- it wouldn't even be terribly
> hard, since RowExpr already does store the column names. ...
> (wanders off to look at whether the only other caller of
> ExecTypeFromExprList could be taught to provide useful field names...)

PFC, a patch that does this.  This seems to fix Andrew's issue with
respect to the RowExpr case.  It's not really ideal with respect to
the ValuesScan case, because what you get seems to always be the
hard-wired "columnN" names for VALUES columns, even if you try to
override that with an alias:

regression=# select each(hstore(q)) as x
      from (values (1,2,3),(4,5,6) limit 2) as q(x,y,z);
      x
-------------
 (column1,1)
 (column2,2)
 (column3,3)
 (column1,4)
 (column2,5)
 (column3,6)
(6 rows)

I think this happens because VALUES in a FROM item is treated like a
sub-select, and the aliases are getting applied at the "wrong" level.
Don't know if that's worth trying to fix, or how hard it would be.
Curiously, it works just fine if the VALUES can be folded:

regression=# select each(hstore(q)) as x
      from (values (1,2,3),(4,5,6)) as q(x,y,z);
   x
-------
 (x,1)
 (y,2)
 (z,3)
 (x,4)
 (y,5)
 (z,6)
(6 rows)


            regards, tom lane

diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 887e5ce82a0b9011627450fdd1046d5529beb110..8f0b5979ba589a1e3aa10405671d4c0793361c5e 100644
*** a/src/backend/executor/execQual.c
--- b/src/backend/executor/execQual.c
*************** ExecInitExpr(Expr *node, PlanState *pare
*** 4627,4633 ****
                  if (rowexpr->row_typeid == RECORDOID)
                  {
                      /* generic record, use runtime type assignment */
!                     rstate->tupdesc = ExecTypeFromExprList(rowexpr->args);
                      BlessTupleDesc(rstate->tupdesc);
                      /* we won't need to redo this at runtime */
                  }
--- 4627,4634 ----
                  if (rowexpr->row_typeid == RECORDOID)
                  {
                      /* generic record, use runtime type assignment */
!                     rstate->tupdesc = ExecTypeFromExprList(rowexpr->args,
!                                                            rowexpr->colnames);
                      BlessTupleDesc(rstate->tupdesc);
                      /* we won't need to redo this at runtime */
                  }
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 3f44ef0186ace8434ceaaf2ef37c14ca0fec632d..3ed90da7a52e2d0e982cfe0ef29022ac1ce1a4a5 100644
*** a/src/backend/executor/execTuples.c
--- b/src/backend/executor/execTuples.c
*************** ExecTypeFromTLInternal(List *targetList,
*** 954,980 ****
  /*
   * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
   *
!  * Here we must make up an arbitrary set of field names.
   */
  TupleDesc
! ExecTypeFromExprList(List *exprList)
  {
      TupleDesc    typeInfo;
!     ListCell   *l;
      int            cur_resno = 1;
!     char        fldname[NAMEDATALEN];

      typeInfo = CreateTemplateTupleDesc(list_length(exprList), false);

!     foreach(l, exprList)
      {
!         Node       *e = lfirst(l);
!
!         sprintf(fldname, "f%d", cur_resno);

          TupleDescInitEntry(typeInfo,
                             cur_resno,
!                            fldname,
                             exprType(e),
                             exprTypmod(e),
                             0);
--- 954,981 ----
  /*
   * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
   *
!  * Caller must also supply a list of field names (String nodes).
   */
  TupleDesc
! ExecTypeFromExprList(List *exprList, List *namesList)
  {
      TupleDesc    typeInfo;
!     ListCell   *le;
!     ListCell   *ln;
      int            cur_resno = 1;
!
!     Assert(list_length(exprList) == list_length(namesList));

      typeInfo = CreateTemplateTupleDesc(list_length(exprList), false);

!     forboth(le, exprList, ln, namesList)
      {
!         Node       *e = lfirst(le);
!         char       *n = strVal(lfirst(ln));

          TupleDescInitEntry(typeInfo,
                             cur_resno,
!                            n,
                             exprType(e),
                             exprTypmod(e),
                             0);
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index d5260e40b32abe5dc5ff437cda8e037f6cdbe12a..0089e501fa2e43c10a1d530110d1fa5f38144cd9 100644
*** a/src/backend/executor/nodeValuesscan.c
--- b/src/backend/executor/nodeValuesscan.c
***************
*** 25,30 ****
--- 25,31 ----

  #include "executor/executor.h"
  #include "executor/nodeValuesscan.h"
+ #include "parser/parsetree.h"


  static TupleTableSlot *ValuesNext(ValuesScanState *node);
*************** ValuesScanState *
*** 188,193 ****
--- 189,196 ----
  ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
  {
      ValuesScanState *scanstate;
+     RangeTblEntry *rte = rt_fetch(node->scan.scanrelid,
+                                   estate->es_range_table);
      TupleDesc    tupdesc;
      ListCell   *vtl;
      int            i;
*************** ExecInitValuesScan(ValuesScan *node, ESt
*** 239,245 ****
      /*
       * get info about values list
       */
!     tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));

      ExecAssignScanType(&scanstate->ss, tupdesc);

--- 242,249 ----
      /*
       * get info about values list
       */
!     tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists),
!                                    rte->eref->colnames);

      ExecAssignScanType(&scanstate->ss, tupdesc);

diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index bdd499bea662d405fc6522c036c53955c0a2e3f9..0d69a34e12bd224396019c37b20cdcac85d73339 100644
*** a/src/include/executor/executor.h
--- b/src/include/executor/executor.h
*************** extern TupleTableSlot *ExecInitNullTuple
*** 256,262 ****
                        TupleDesc tupType);
  extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
  extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
! extern TupleDesc ExecTypeFromExprList(List *exprList);
  extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);

  typedef struct TupOutputState
--- 256,262 ----
                        TupleDesc tupType);
  extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
  extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
! extern TupleDesc ExecTypeFromExprList(List *exprList, List *namesList);
  extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);

  typedef struct TupOutputState

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

Предыдущее
От: Peter Geoghegan
Дата:
Сообщение: Re: ISN was: Core Extensions relocation
Следующее
От: Tom Lane
Дата:
Сообщение: Re: When do we lose column names?