Re: anonymous composite types for Table Functions (aka - Mailing list pgsql-patches
| From | Joe Conway |
|---|---|
| Subject | Re: anonymous composite types for Table Functions (aka |
| Date | |
| Msg-id | 3D4CCF7A.3020506@joeconway.com Whole thread Raw |
| In response to | Re: anonymous composite types for Table Functions (aka SRFs) (Bruce Momjian <pgman@candle.pha.pa.us>) |
| Responses |
Re: anonymous composite types for Table Functions (aka
|
| List | 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 by date: