Function returns composite type
Hi!
For some reason I wish to write C-function for SQL which returns set of
composite type, but this type is defined function itself and composite type can
be changed from call to call. So I can't define create type by 'CREATE TYPE'
command.
It's documented (34.7.8. Returning Rows (Composite Types) from C-Language
Functions) there are only two ways to get TupleDesc: for a named relation and
based on type OID. That ways are useless in my case.
Is it possibly?
--
Teodor Sigaev E-mail: teodor@sigaev.ru
Teodor Sigaev <teodor@sigaev.ru> writes:
For some reason I wish to write C-function for SQL which returns set of
composite type, but this type is defined function itself and composite type can
be changed from call to call. So I can't define create type by 'CREATE TYPE'
command.
Perhaps the RECORD stuff would help you? It's poorly documented, but
you could look at the code for SRFs to see how to use it.
regards, tom lane
Perhaps the RECORD stuff would help you? It's poorly documented, but
you could look at the code for SRFs to see how to use it.regards, tom lane
Ok, RECORD was a keyword, thank you. But I have questions:
1 What do you mean SRF? Set Return Function?
2 Some example I found in contrib/tablefunc, and so I create test function:
Datum
qqn(PG_FUNCTION_ARGS) {
int attnum = PG_NARGS();
TupleDesc tupdesc;
char attname[NAMEDATALEN];
int i;
TupleTableSlot *slot;
AttInMetadata *attinmeta;
Datum *dvalues, result;
char *nulls;
HeapTuple tuple;
/* set tupledesc */
tupdesc = CreateTemplateTupleDesc(attnum, false);
for (i = 0; i < attnum; i++) {
sprintf(attname, "z%d", i+1);
TupleDescInitEntry(tupdesc, i+1, attname, INT4OID, -1, 0, false);
}
slot = TupleDescGetSlot(tupdesc);
attinmeta = TupleDescGetAttInMetadata(tupdesc);
dvalues = (Datum *) palloc(attnum * sizeof(Datum));
nulls = (char *) palloc(attnum * sizeof(char));
for (i = 0; i < attnum; i++) {
nulls[i] = ' ';
dvalues[i] = PG_GETARG_DATUM(i);
}
/* tupdesc = attinmeta->tupdesc */
tuple = heap_formtuple(tupdesc, dvalues, nulls);
pfree(dvalues);
pfree(nulls);
result = TupleGetDatum(slot, tuple);
PG_RETURN_DATUM(result);
}
create function qqN(int4)
returns record
AS 'MODULE_PATHNAME'
LANGUAGE 'C';
create function qqN(int4,int4)
returns record
AS 'MODULE_PATHNAME'
LANGUAGE 'C';
# select * from qqn(1) as c(qq int4);
qq
----
1
(1 row)
# select * from qqn(1,2) as c(qq int4, qq1 int4);
qq | qq1
----+-----
1 | 2
(1 row)
It works fine. But is there way not to point 'as c(qq int4, qq1 int4)'? Notice:
qqn isn't real, it's test only.
Thank you.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
Teodor Sigaev wrote:
Ok, RECORD was a keyword, thank you. But I have questions:
1 What do you mean SRF? Set Return Function?
It refers to functions returning one or more tuples. From a practical
standpoint, it is a function that is (and must be) used in the FROM
clause like a table (hence also known as a "table function").
# select * from qqn(1,2) as c(qq int4, qq1 int4);
qq | qq1
----+-----
1 | 2
(1 row)It works fine. But is there way not to point 'as c(qq int4, qq1 int4)'?
If you mean, is there a way to leave out the 'as c(qq int4, qq1 int4)',
the answer is no. You need to either declare the function to return a
determinate data type, or you have to specify the data type at runtime
in the query string.
Joe
It works fine. But is there way not to point 'as c(qq int4, qq1 int4)'?
If you mean, is there a way to leave out the 'as c(qq int4, qq1 int4)',
the answer is no. You need to either declare the function to return a
determinate data type, or you have to specify the data type at runtime
in the query string.
it's a great pity :(.
But in function I already make TupleDesc:
tupdesc = CreateTemplateTupleDesc(attnum, false);
for (i = 0; i < attnum; i++) {
sprintf(attname, "z%d", i+1);
TupleDescInitEntry(tupdesc, i+1, attname, INT4OID, -1, 0, false);
}
As I understand, this code makes full description of returning value, including
types and column's names.
Is this info used anywhere?
--
Teodor Sigaev E-mail: teodor@sigaev.ru
Teodor Sigaev wrote:
it's a great pity :(.
But in function I already make TupleDesc:
tupdesc = CreateTemplateTupleDesc(attnum, false);
for (i = 0; i < attnum; i++) {
sprintf(attname, "z%d", i+1);
TupleDescInitEntry(tupdesc, i+1, attname, INT4OID, -1,
0, false);
}
As I understand, this code makes full description of returning value,
including types and column's names.
Is this info used anywhere?
You could actually get the tupdesc from the caller if you wanted. See,
for example crosstab_hash() in contrib/tablefunc:
<snip>
/* check to see if caller supports us returning a tuplestore */
if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
elog(ERROR, "crosstab: materialize mode required, but it is not "
"allowed in this context");
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* get the requested return tuple description */
tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
</snip>
The problem is that the parser needs the column data types long before
your function gets called by the executor. Therefore you either need the
predetermined return type, or the query string definition.
We've discussed a couple of times allowing the parser to "interrogate"
the function at parse time to let it determine what the runtime tupdesc
will be, but I haven't been able to come up with a good way to do that.
Joe
You could actually get the tupdesc from the caller if you wanted. See,
for example crosstab_hash() in contrib/tablefunc:<snip>
/* check to see if caller supports us returning a tuplestore */
if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
elog(ERROR, "crosstab: materialize mode required, but it is not "
"allowed in this context");per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);/* get the requested return tuple description */
tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
</snip>
Thank you for point.
The problem is that the parser needs the column data types long before
your function gets called by the executor. Therefore you either need the
predetermined return type, or the query string definition.
Ok, I see
We've discussed a couple of times allowing the parser to "interrogate"
the function at parse time to let it determine what the runtime tupdesc
will be, but I haven't been able to come up with a good way to do that.
Can we make follow:
Functions, returning record and called in sql without description,
??lled with specific arguments (as is done for SRF by SRF_IS_FIRSTCALL()). With
this arguments it should return TupleDesc.
As I see, the place to such call is addRangeTableEntryForFunction at
src/parser/parse_relation.c near lines N921-964. In this place we have all that
we need.
Am I wrong?
--
Teodor Sigaev E-mail: teodor@sigaev.ru
We've discussed a couple of times allowing the parser to "interrogate"
the function at parse time to let it determine what the runtime tupdesc
will be, but I haven't been able to come up with a good way to do that.
This seems fairly unworkable to me, as in interesting cases the parser
could not find out what parameter values to pass to the function, so the
function wouldn't have enough information to know what it will return
either.
regards, tom lane