Re: anonymous composite types for Table Functions (aka - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: anonymous composite types for Table Functions (aka |
Date | |
Msg-id | 200208041948.g74JmT416236@candle.pha.pa.us Whole thread Raw |
In response to | Re: anonymous composite types for Table Functions (aka (Joe Conway <mail@joeconway.com>) |
List | pgsql-patches |
Got it and applied. Thanks. This is a major feature now. --------------------------------------------------------------------------- Joe Conway wrote: > 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); > > ---------------------------(end of broadcast)--------------------------- > TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
pgsql-patches by date: