Re: anonymous composite types for Table Functions (aka

Поиск
Список
Период
Сортировка
От Joe Conway
Тема Re: anonymous composite types for Table Functions (aka
Дата
Msg-id 3D4CCF7A.3020506@joeconway.com
обсуждение исходный текст
Ответ на Re: anonymous composite types for Table Functions (aka SRFs)  (Bruce Momjian <pgman@candle.pha.pa.us>)
Ответы Re: anonymous composite types for Table Functions (aka  (Bruce Momjian <pgman@candle.pha.pa.us>)
Список pgsql-patches
Bruce Momjian wrote:
> I am sorry but I am unable to apply this patch because of the DROP
> COLUMN patch that was applied since you submitted this.
>
> It had rejections in gram.y and parse_relation.c, but those were easy to
> fix.  The big problem is pg_proc.c, where the code changes can not be
> merged.
>
> I am attaching the rejected part of the patch.  If you can send me a
> fixed version of just that change, I can commit the rest.
>

OK. Here is a patch against current cvs for just pg_proc.c. This
includes all the changes for that file (i.e. not just the one rejected
hunk).

Thanks,

Joe


Index: src/backend/catalog/pg_proc.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/catalog/pg_proc.c,v
retrieving revision 1.82
diff -c -r1.82 pg_proc.c
*** src/backend/catalog/pg_proc.c    2 Aug 2002 18:15:05 -0000    1.82
--- src/backend/catalog/pg_proc.c    4 Aug 2002 06:21:51 -0000
***************
*** 25,30 ****
--- 25,31 ----
  #include "miscadmin.h"
  #include "parser/parse_coerce.h"
  #include "parser/parse_expr.h"
+ #include "parser/parse_relation.h"
  #include "parser/parse_type.h"
  #include "tcop/tcopprot.h"
  #include "utils/builtins.h"
***************
*** 33,39 ****
  #include "utils/syscache.h"


! static void checkretval(Oid rettype, List *queryTreeList);
  Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
  Datum fmgr_c_validator(PG_FUNCTION_ARGS);
  Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
--- 34,40 ----
  #include "utils/syscache.h"


! static void checkretval(Oid rettype, char fn_typtype, List *queryTreeList);
  Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
  Datum fmgr_c_validator(PG_FUNCTION_ARGS);
  Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
***************
*** 367,460 ****
       */
      tlistlen = ExecCleanTargetListLength(tlist);

-     /*
-      * For base-type returns, the target list should have exactly one
-      * entry, and its type should agree with what the user declared. (As
-      * of Postgres 7.2, we accept binary-compatible types too.)
-      */
      typerelid = typeidTypeRelid(rettype);
-     if (typerelid == InvalidOid)
-     {
-         if (tlistlen != 1)
-             elog(ERROR, "function declared to return %s returns multiple columns in final SELECT",
-                  format_type_be(rettype));

!         restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
!         if (!IsBinaryCompatible(restype, rettype))
!             elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
!                  format_type_be(rettype), format_type_be(restype));

!         return;
!     }

-     /*
-      * If the target list is of length 1, and the type of the varnode in
-      * the target list matches the declared return type, this is okay.
-      * This can happen, for example, where the body of the function is
-      * 'SELECT func2()', where func2 has the same return type as the
-      * function that's calling it.
-      */
-     if (tlistlen == 1)
-     {
-         restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
-         if (IsBinaryCompatible(restype, rettype))
              return;
      }

!     /*
!      * By here, the procedure returns a tuple or set of tuples.  This part
!      * of the typechecking is a hack. We look up the relation that is the
!      * declared return type, and scan the non-deleted attributes to ensure
!      * that they match the datatypes of the non-resjunk columns.
!      */
!     reln = heap_open(typerelid, AccessShareLock);
!     relnatts = reln->rd_rel->relnatts;
!     rellogcols = 0;                /* we'll count nondeleted cols as we go */
!     colindex = 0;
!
!     foreach(tlistitem, tlist)
!     {
!         TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
!         Form_pg_attribute attr;
!         Oid            tletype;
!         Oid            atttype;

!         if (tle->resdom->resjunk)
!             continue;

!         do {
              colindex++;
              if (colindex > relnatts)
!                 elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
!                      format_type_be(rettype), rellogcols);
!             attr = reln->rd_att->attrs[colindex - 1];
!         } while (attr->attisdropped);
!         rellogcols++;
!
!         tletype = exprType(tle->expr);
!         atttype = attr->atttypid;
!         if (!IsBinaryCompatible(tletype, atttype))
!             elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
!                  format_type_be(rettype),
!                  format_type_be(tletype),
!                  format_type_be(atttype),
!                  rellogcols);
!     }
!
!     for (;;)
!     {
!         colindex++;
!         if (colindex > relnatts)
!             break;
!         if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
!             rellogcols++;
!     }

!     if (tlistlen != rellogcols)
!         elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
!              format_type_be(rettype), rellogcols);

!     heap_close(reln, AccessShareLock);
  }


--- 368,480 ----
       */
      tlistlen = ExecCleanTargetListLength(tlist);

      typerelid = typeidTypeRelid(rettype);

!     if (fn_typtype == 'b')
!     {
!         /*
!          * For base-type returns, the target list should have exactly one
!          * entry, and its type should agree with what the user declared. (As
!          * of Postgres 7.2, we accept binary-compatible types too.)
!          */

!         if (typerelid == InvalidOid)
!         {
!             if (tlistlen != 1)
!                 elog(ERROR, "function declared to return %s returns multiple columns in final SELECT",
!                      format_type_be(rettype));
!
!             restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
!             if (!IsBinaryCompatible(restype, rettype))
!                 elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
!                      format_type_be(rettype), format_type_be(restype));

              return;
+         }
+
+         /*
+          * If the target list is of length 1, and the type of the varnode in
+          * the target list matches the declared return type, this is okay.
+          * This can happen, for example, where the body of the function is
+          * 'SELECT func2()', where func2 has the same return type as the
+          * function that's calling it.
+          */
+         if (tlistlen == 1)
+         {
+             restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
+             if (IsBinaryCompatible(restype, rettype))
+                 return;
+         }
      }
+     else if (fn_typtype == 'c')
+     {
+         /*
+          * By here, the procedure returns a tuple or set of tuples.  This part
+          * of the typechecking is a hack. We look up the relation that is the
+          * declared return type, and scan the non-deleted attributes to ensure
+          * that they match the datatypes of the non-resjunk columns.
+          */
+         reln = heap_open(typerelid, AccessShareLock);
+         relnatts = reln->rd_rel->relnatts;
+         rellogcols = 0;                /* we'll count nondeleted cols as we go */
+         colindex = 0;

!         foreach(tlistitem, tlist)
!         {
!             TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
!             Form_pg_attribute attr;
!             Oid            tletype;
!             Oid            atttype;
!
!             if (tle->resdom->resjunk)
!                 continue;
!
!             do {
!                 colindex++;
!                 if (colindex > relnatts)
!                     elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
!                          format_type_be(rettype), rellogcols);
!                 attr = reln->rd_att->attrs[colindex - 1];
!             } while (attr->attisdropped);
!             rellogcols++;

!             tletype = exprType(tle->expr);
!             atttype = attr->atttypid;
!             if (!IsBinaryCompatible(tletype, atttype))
!                 elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
!                      format_type_be(rettype),
!                      format_type_be(tletype),
!                      format_type_be(atttype),
!                      rellogcols);
!         }

!         for (;;)
!         {
              colindex++;
              if (colindex > relnatts)
!                 break;
!             if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
!                 rellogcols++;
!         }

!         if (tlistlen != rellogcols)
!             elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
!                  format_type_be(rettype), rellogcols);

!         heap_close(reln, AccessShareLock);
!
!         return;
!     }
!     else if (fn_typtype == 'p' && rettype == RECORDOID)
!     {
!         /*
!          * For RECORD return type, defer this check until we get the
!          * first tuple.
!          */
!         return;
!     }
!     else
!         elog(ERROR, "Unknown kind of return type specified for function");
  }


***************
*** 553,558 ****
--- 573,579 ----
      bool        isnull;
      Datum        tmp;
      char       *prosrc;
+     char        functyptype;

      tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
      if (!HeapTupleIsValid(tuple))
***************
*** 569,576 ****

      prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));

      querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
!     checkretval(proc->prorettype, querytree_list);

      ReleaseSysCache(tuple);
      PG_RETURN_BOOL(true);
--- 590,600 ----

      prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));

+     /* check typtype to see if we have a predetermined return type */
+     functyptype = typeid_get_typtype(proc->prorettype);
+
      querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
!     checkretval(proc->prorettype, functyptype, querytree_list);

      ReleaseSysCache(tuple);
      PG_RETURN_BOOL(true);

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

Предыдущее
От: Bruce Momjian
Дата:
Сообщение: Re: Updated CHECK failed message patch
Следующее
От: Bruce Momjian
Дата:
Сообщение: Re: anonymous composite types for Table Functions (aka SRFs)