diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index ac941598be7546dc395005606f502e2b548b534f..4a521a0fac79193db79252da9a6f71ee83d5311e 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -447,7 +447,6 @@ dblink_fetch(PG_FUNCTION_ARGS) TupleDesc tupdesc = NULL; int call_cntr; int max_calls; - TupleTableSlot *slot; AttInMetadata *attinmeta; char *msg; PGresult *res = NULL; @@ -566,9 +565,10 @@ dblink_fetch(PG_FUNCTION_ARGS) if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); - else if (functyptype == 'p' && functypeid == RECORDOID) + else if (functypeid == RECORDOID) { - if (!rsinfo || !IsA(rsinfo, ReturnSetInfo)) + if (!rsinfo || !IsA(rsinfo, ReturnSetInfo) || + rsinfo->expectedDesc == NULL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " @@ -582,8 +582,6 @@ dblink_fetch(PG_FUNCTION_ARGS) elog(ERROR, "return type must be a row type"); /* store needed metadata for subsequent calls */ - slot = TupleDescGetSlot(tupdesc); - funcctx->slot = slot; attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; @@ -599,8 +597,6 @@ dblink_fetch(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - slot = funcctx->slot; - res = (PGresult *) funcctx->user_fctx; attinmeta = funcctx->attinmeta; tupdesc = attinmeta->tupdesc; @@ -626,7 +622,7 @@ dblink_fetch(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } @@ -649,7 +645,6 @@ dblink_record(PG_FUNCTION_ARGS) TupleDesc tupdesc = NULL; int call_cntr; int max_calls; - TupleTableSlot *slot; AttInMetadata *attinmeta; char *msg; PGresult *res = NULL; @@ -741,7 +736,7 @@ dblink_record(PG_FUNCTION_ARGS) /* need a tuple descriptor representing one TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); /* * and save a copy of the command status string to return as @@ -776,9 +771,10 @@ dblink_record(PG_FUNCTION_ARGS) { if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); - else if (functyptype == 'p' && functypeid == RECORDOID) + else if (functypeid == RECORDOID) { - if (!rsinfo || !IsA(rsinfo, ReturnSetInfo)) + if (!rsinfo || !IsA(rsinfo, ReturnSetInfo) || + rsinfo->expectedDesc == NULL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " @@ -793,8 +789,6 @@ dblink_record(PG_FUNCTION_ARGS) } /* store needed metadata for subsequent calls */ - slot = TupleDescGetSlot(tupdesc); - funcctx->slot = slot; attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; @@ -810,8 +804,6 @@ dblink_record(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - slot = funcctx->slot; - res = (PGresult *) funcctx->user_fctx; attinmeta = funcctx->attinmeta; tupdesc = attinmeta->tupdesc; @@ -846,7 +838,7 @@ dblink_record(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } @@ -925,7 +917,7 @@ dblink_exec(PG_FUNCTION_ARGS) /* need a tuple descriptor representing one TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); /* * and save a copy of the command status string to return as our @@ -939,7 +931,7 @@ dblink_exec(PG_FUNCTION_ARGS) /* need a tuple descriptor representing one TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); /* * and save a copy of the command status string to return as our @@ -978,7 +970,6 @@ dblink_get_pkey(PG_FUNCTION_ARGS) FuncCallContext *funcctx; int32 call_cntr; int32 max_calls; - TupleTableSlot *slot; AttInMetadata *attinmeta; MemoryContext oldcontext; @@ -1010,15 +1001,9 @@ dblink_get_pkey(PG_FUNCTION_ARGS) */ tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "position", - INT4OID, -1, 0, false); + INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "colname", - TEXTOID, -1, 0, false); - - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - - /* assign slot to function context */ - funcctx->slot = slot; + TEXTOID, -1, 0); /* * Generate attribute metadata needed later to produce tuples from @@ -1053,8 +1038,6 @@ dblink_get_pkey(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - slot = funcctx->slot; - results = (char **) funcctx->user_fctx; attinmeta = funcctx->attinmeta; @@ -1075,7 +1058,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/contrib/intagg/int_aggregate.c b/contrib/intagg/int_aggregate.c index 2bb06ff73a4a81c51cf6bd6d3ebccbf9789b5808..bd03f5c0c317e37cdfe29bcab219f85cfa4f63b3 100644 --- a/contrib/intagg/int_aggregate.c +++ b/contrib/intagg/int_aggregate.c @@ -25,7 +25,6 @@ #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "executor/executor.h" -#include "utils/sets.h" #include "utils/syscache.h" #include "access/tupmacs.h" #include "access/xact.h" diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index abc2249aedfcd3c805c2524d157afb8c0ea9a393..ca082618568d182b6f178a4cf53daf4e81415868 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.13 2003/11/29 19:51:35 pgsql Exp $ + * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.14 2004/04/01 21:28:43 tgl Exp $ * * Copyright (c) 2001,2002 Tatsuo Ishii * @@ -111,7 +111,6 @@ pgstattuple_real(Relation rel) uint64 free_space = 0; /* free/reusable space in bytes */ double free_percent; /* free/reusable space in % */ TupleDesc tupdesc; - TupleTableSlot *slot; AttInMetadata *attinmeta; char **values; int i; @@ -122,9 +121,6 @@ pgstattuple_real(Relation rel) */ tupdesc = RelationNameGetTupleDesc(DUMMY_TUPLE); - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - /* * Generate attribute metadata needed later to produce tuples from raw * C strings @@ -192,7 +188,7 @@ pgstattuple_real(Relation rel) } /* - * Prepare a values array for storage in our slot. This should be an + * Prepare a values array for constructing the tuple. This should be an * array of C strings which will be processed later by the appropriate * "in" functions. */ @@ -214,7 +210,7 @@ pgstattuple_real(Relation rel) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); /* Clean up */ for (i = 0; i < NCOLUMNS; i++) diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index 622164b91b551320aeaee1570bd395ad43ee88ff..3eccebf476f767fde76a6cb40a7c235849bf75a0 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -351,7 +351,6 @@ crosstab(PG_FUNCTION_ARGS) TupleDesc ret_tupdesc; int call_cntr; int max_calls; - TupleTableSlot *slot; AttInMetadata *attinmeta; SPITupleTable *spi_tuptable = NULL; TupleDesc spi_tupdesc; @@ -429,10 +428,10 @@ crosstab(PG_FUNCTION_ARGS) if (functyptype == 'c') { - /* Build a tuple description for a functypeid tuple */ + /* Build a tuple description for a named composite type */ tupdesc = TypeGetTupleDesc(functypeid, NIL); } - else if (functyptype == 'p' && functypeid == RECORDOID) + else if (functypeid == RECORDOID) { if (fcinfo->nargs != 2) ereport(ERROR, @@ -461,12 +460,6 @@ crosstab(PG_FUNCTION_ARGS) errmsg("return and sql tuple descriptions are " \ "incompatible"))); - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - - /* assign slot to function context */ - funcctx->slot = slot; - /* * Generate attribute metadata needed later to produce tuples from * raw C strings @@ -499,9 +492,6 @@ crosstab(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - /* return slot for our tuple */ - slot = funcctx->slot; - /* user context info */ fctx = (crosstab_fctx *) funcctx->user_fctx; lastrowid = fctx->lastrowid; @@ -621,7 +611,7 @@ crosstab(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); /* Clean up */ for (i = 0; i < num_categories + 1; i++) @@ -1675,7 +1665,7 @@ make_crosstab_tupledesc(TupleDesc spi_tupdesc, int num_categories) strcpy(attname, "rowname"); TupleDescInitEntry(tupdesc, attnum, attname, sql_atttypid, - -1, 0, false); + -1, 0); /* now the category values columns */ sql_attr = spi_tupdesc->attrs[2]; @@ -1687,7 +1677,7 @@ make_crosstab_tupledesc(TupleDesc spi_tupdesc, int num_categories) sprintf(attname, "category_%d", i + 1); TupleDescInitEntry(tupdesc, attnum, attname, sql_atttypid, - -1, 0, false); + -1, 0); } return tupdesc; diff --git a/contrib/tsearch2/ts_stat.c b/contrib/tsearch2/ts_stat.c index 732f25b6bd1638f301a3558b7d0d195774ae5279..a6518e34396d9845118ad20ba62255009109ad0f 100644 --- a/contrib/tsearch2/ts_stat.c +++ b/contrib/tsearch2/ts_stat.c @@ -303,7 +303,6 @@ ts_setup_firstcall(FuncCallContext *funcctx, tsstat * stat) memcpy(st->stat, stat, stat->len); funcctx->user_fctx = (void *) st; tupdesc = RelationNameGetTupleDesc("statinfo"); - funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); MemoryContextSwitchTo(oldcontext); } @@ -334,7 +333,7 @@ ts_process_call(FuncCallContext *funcctx) (values[0])[entry->len] = '\0'; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - result = TupleGetDatum(funcctx->slot, tuple); + result = HeapTupleGetDatum(tuple); pfree(values[0]); st->cur++; diff --git a/contrib/tsearch2/wparser.c b/contrib/tsearch2/wparser.c index b7e45e51885f449d9160e46721cb43bf62068bf4..9c3c4430480d2329596c10c5d6d45de3a9de43c9 100644 --- a/contrib/tsearch2/wparser.c +++ b/contrib/tsearch2/wparser.c @@ -187,7 +187,6 @@ setup_firstcall(FuncCallContext *funcctx, Oid prsid) ); funcctx->user_fctx = (void *) st; tupdesc = RelationNameGetTupleDesc("tokentype"); - funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); MemoryContextSwitchTo(oldcontext); } @@ -211,7 +210,7 @@ process_call(FuncCallContext *funcctx) values[2] = st->list[st->cur].descr; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - result = TupleGetDatum(funcctx->slot, tuple); + result = HeapTupleGetDatum(tuple); pfree(values[1]); pfree(values[2]); @@ -391,7 +390,6 @@ prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) funcctx->user_fctx = (void *) st; tupdesc = RelationNameGetTupleDesc("tokenout"); - funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); MemoryContextSwitchTo(oldcontext); } @@ -413,7 +411,7 @@ prs_process_call(FuncCallContext *funcctx) sprintf(tid, "%d", st->list[st->cur].type); values[1] = st->list[st->cur].lexem; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - result = TupleGetDatum(funcctx->slot, tuple); + result = HeapTupleGetDatum(tuple); pfree(values[1]); st->cur++; diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 196fdc6efdd761b341283b81f57876bd383249c8..0cdbdcfb7b52e042bed9fe525fc5a7b6dfcda6a2 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ <!-- Documentation of the system catalogs, directed toward PostgreSQL developers - $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.84 2004/02/15 21:01:38 tgl Exp $ + $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.85 2004/04/01 21:28:43 tgl Exp $ --> <chapter id="catalogs"> @@ -809,24 +809,6 @@ </entry> </row> - <row> - <entry><structfield>attisset</structfield></entry> - <entry><type>bool</type></entry> - <entry></entry> - <entry> - If true, this attribute is a set. In that case, what is really - stored in the attribute is the OID of a row in the - <structname>pg_proc</structname> catalog. The - <structname>pg_proc</structname> row contains the query - string that defines this set, i.e., the query to run to get - the set. So the <structfield>atttypid</structfield> (see - above) refers to the type returned by this query, but the - actual length of this attribute is the length (size) of an - <type>oid</type>. --- At least this is the theory. All this - is probably quite broken these days. - </entry> - </row> - <row> <entry><structfield>attalign</structfield></entry> <entry><type>char</type></entry> diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index c87a136bdd471fe89a8a1e4ef6595fdf45ecdd84..4018c2e3e1ba68efbfdf60d24936ceb74d7777ca 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.33 2004/03/17 01:05:10 momjian Exp $ +$PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.34 2004/04/01 21:28:43 tgl Exp $ --> <chapter id="spi"> @@ -1953,8 +1953,7 @@ char * SPI_getrelname(Relation <parameter>rel</parameter>) allocations made by <function>palloc</function>, <function>repalloc</function>, or SPI utility functions (except for <function>SPI_copytuple</function>, - <function>SPI_copytupledesc</function>, - <function>SPI_copytupleintoslot</function>, + <function>SPI_returntuple</function>, <function>SPI_modifytuple</function>, and <function>SPI_palloc</function>) are made in this context. When a procedure disconnects from the SPI manager (via @@ -2169,7 +2168,9 @@ HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>) <para> <function>SPI_copytuple</function> makes a copy of a row in the - upper executor context. + upper executor context. This is normally used to return a modified + row from a trigger. In a function declared to return a composite + type, use <function>SPI_returntuple</function> instead. </para> </refsect1> @@ -2200,21 +2201,21 @@ HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>) <!-- *********************************************** --> -<refentry id="spi-spi-copytupledesc"> +<refentry id="spi-spi-returntuple"> <refmeta> - <refentrytitle>SPI_copytupledesc</refentrytitle> + <refentrytitle>SPI_returntuple</refentrytitle> </refmeta> <refnamediv> - <refname>SPI_copytupledesc</refname> - <refpurpose>make a copy of a row descriptor in the upper executor context</refpurpose> + <refname>SPI_returntuple</refname> + <refpurpose>prepare to return a tuple as a Datum</refpurpose> </refnamediv> - <indexterm><primary>SPI_copytupledesc</primary></indexterm> + <indexterm><primary>SPI_returntuple</primary></indexterm> <refsynopsisdiv> <synopsis> -TupleDesc SPI_copytupledesc(TupleDesc <parameter>tupdesc</parameter>) +HeapTupleHeader SPI_returntuple(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>) </synopsis> </refsynopsisdiv> @@ -2222,63 +2223,16 @@ TupleDesc SPI_copytupledesc(TupleDesc <parameter>tupdesc</parameter>) <title>Description</title> <para> - <function>SPI_copytupledesc</function> makes a copy of a row - descriptor in the upper executor context. + <function>SPI_returntuple</function> makes a copy of a row in + the upper executor context, returning it in the form of a rowtype Datum. + The returned pointer need only be converted to Datum via PointerGetDatum + before returning. </para> - </refsect1> - - <refsect1> - <title>Arguments</title> - - <variablelist> - <varlistentry> - <term><literal>TupleDesc <parameter>tupdesc</parameter></literal></term> - <listitem> - <para> - row descriptor to be copied - </para> - </listitem> - </varlistentry> - </variablelist> - </refsect1> - - <refsect1> - <title>Return Value</title> - - <para> - the copied row descriptor; <symbol>NULL</symbol> only if - <parameter>tupdesc</parameter> is <symbol>NULL</symbol> - </para> - </refsect1> -</refentry> - -<!-- *********************************************** --> - -<refentry id="spi-spi-copytupleintoslot"> - <refmeta> - <refentrytitle>SPI_copytupleintoslot</refentrytitle> - </refmeta> - - <refnamediv> - <refname>SPI_copytupleintoslot</refname> - <refpurpose>make a copy of a row and descriptor in the upper executor context</refpurpose> - </refnamediv> - - <indexterm><primary>SPI_copytupleintoslot</primary></indexterm> - - <refsynopsisdiv> -<synopsis> -TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>) -</synopsis> - </refsynopsisdiv> - - <refsect1> - <title>Description</title> <para> - <function>SPI_copytupleintoslot</function> makes a copy of a row in - the upper executor context, returning it in the form of a filled-in - <type>TupleTableSlot</type> structure. + Note that this should be used for functions that are declared to return + composite types. It is not used for triggers; use + <function>SPI_copytuple</> for returning a modified row in a trigger. </para> </refsect1> @@ -2299,7 +2253,8 @@ TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, Tup <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> <listitem> <para> - row descriptor to be copied + descriptor for row (pass the same descriptor each time for most + effective caching) </para> </listitem> </varlistentry> @@ -2310,9 +2265,9 @@ TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, Tup <title>Return Value</title> <para> - <type>TupleTableSlot</type> containing the copied row and - descriptor; <symbol>NULL</symbol> only if - <parameter>row</parameter> or <parameter>rowdesc</parameter> are + <type>HeapTupleHeader</type> pointing to copied row; + <symbol>NULL</symbol> only if + <parameter>row</parameter> or <parameter>rowdesc</parameter> is <symbol>NULL</symbol> </para> </refsect1> diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index c8f71296857b6dc481674362355c603ec6329c3d..4b06aefd362eb9413260df3f628c4fc80e66c0dd 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.80 2004/03/09 16:57:47 neilc Exp $ +$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.81 2004/04/01 21:28:43 tgl Exp $ --> <sect1 id="xfunc"> @@ -1623,7 +1623,7 @@ SELECT name, c_overpaid(emp, 1500) AS overpaid #include "executor/executor.h" /* for GetAttributeByName() */ bool -c_overpaid(TupleTableSlot *t, /* the current row of emp */ +c_overpaid(HeapTupleHeader t, /* the current row of emp */ int32 limit) { bool isnull; @@ -1647,7 +1647,7 @@ PG_FUNCTION_INFO_V1(c_overpaid); Datum c_overpaid(PG_FUNCTION_ARGS) { - TupleTableSlot *t = (TupleTableSlot *) PG_GETARG_POINTER(0); + HeapTupleHeader t = PG_GETARG_HEAPTUPLEHEADER(0); int32 limit = PG_GETARG_INT32(1); bool isnull; int32 salary; @@ -1666,7 +1666,8 @@ c_overpaid(PG_FUNCTION_ARGS) <function>GetAttributeByName</function> is the <productname>PostgreSQL</productname> system function that returns attributes out of the specified row. It has - three arguments: the argument of type <type>TupleTableSlot*</type> passed into + three arguments: the argument of type <type>HeapTupleHeader</type> passed + into the function, the name of the desired attribute, and a return parameter that tells whether the attribute is null. <function>GetAttributeByName</function> returns a <type>Datum</type> @@ -1674,6 +1675,11 @@ c_overpaid(PG_FUNCTION_ARGS) appropriate <function>DatumGet<replaceable>XXX</replaceable>()</function> macro. </para> + <para> + There is also <function>GetAttributeByNum</function>, which selects + the target attribute by column number instead of name. + </para> + <para> The following command declares the function <function>c_overpaid</function> in SQL: @@ -1681,8 +1687,11 @@ c_overpaid(PG_FUNCTION_ARGS) <programlisting> CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean AS '<replaceable>DIRECTORY</replaceable>/funcs', 'c_overpaid' - LANGUAGE C; + LANGUAGE C STRICT; </programlisting> + + Notice we have used <literal>STRICT</> so that we did not have to + check whether the input arguments were NULL. </para> </sect2> @@ -1700,38 +1709,25 @@ CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean </para> <para> - The support for returning composite data types (or rows) starts - with the <structname>AttInMetadata</> structure. This structure - holds arrays of individual attribute information needed to create - a row from raw C strings. The information contained in the - structure is derived from a <structname>TupleDesc</> structure, - but it is stored to avoid redundant computations on each call to - a set-returning function (see next section). In the case of a - function returning a set, the <structname>AttInMetadata</> - structure should be computed once during the first call and saved - for reuse in later calls. <structname>AttInMetadata</> also - saves a pointer to the original <structname>TupleDesc</>. -<programlisting> -typedef struct AttInMetadata -{ - /* full TupleDesc */ - TupleDesc tupdesc; - - /* array of attribute type input function finfo */ - FmgrInfo *attinfuncs; - - /* array of attribute type typelem */ - Oid *attelems; - - /* array of attribute typmod */ - int32 *atttypmods; -} AttInMetadata; -</programlisting> + There are two ways you can build a composite data value (henceforth + a <quote>tuple</>): you can build it from an array of Datum values, + or from an array of C strings that can be passed to the input + conversion functions of the tuple's column datatypes. In either + case, you first need to obtain or construct a <structname>TupleDesc</> + descriptor for the tuple structure. When working with Datums, you + pass the <structname>TupleDesc</> to <function>BlessTupleDesc</>, + and then call <function>heap_formtuple</> for each row. When working + with C strings, you pass the <structname>TupleDesc</> to + <function>TupleDescGetAttInMetadata</>, and then call + <function>BuildTupleFromCStrings</> for each row. In the case of a + function returning a set of tuples, the setup steps can all be done + once during the first call of the function. </para> <para> - To assist you in populating this structure, several functions and a macro - are available. Use + Several helper functions are available for setting up the initial + <structname>TupleDesc</>. If you want to use a named composite type, + you can fetch the information from the system catalogs. Use <programlisting> TupleDesc RelationNameGetTupleDesc(const char *relname) </programlisting> @@ -1741,36 +1737,43 @@ TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) </programlisting> to get a <structname>TupleDesc</> based on a type OID. This can be used to get a <structname>TupleDesc</> for a base or - composite type. Then + composite type. When writing a function that returns + <structname>record</>, the expected <structname>TupleDesc</> + must be passed in by the caller. + </para> + + <para> + Once you have a <structname>TupleDesc</>, call +<programlisting> +TupleDesc BlessTupleDesc(TupleDesc tupdesc) +</programlisting> + if you plan to work with Datums, or <programlisting> AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) </programlisting> - will return a pointer to an <structname>AttInMetadata</>, - initialized based on the given - <structname>TupleDesc</>. <structname>AttInMetadata</> can be - used in conjunction with C strings to produce a properly formed - row value (internally called tuple). + if you plan to work with C strings. If you are writing a function + returning set, you can save the results of these functions in the + <structname>FuncCallContext</> structure --- use the + <structfield>tuple_desc</> or <structfield>attinmeta</> field + respectively. </para> <para> - To return a tuple you must create a tuple slot based on the - <structname>TupleDesc</>. You can use + When working with Datums, use <programlisting> -TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc) +HeapTuple heap_formtuple(TupleDesc tupdesc, Datum *values, char *nulls) </programlisting> - to initialize this tuple slot, or obtain one through other (user provided) - means. The tuple slot is needed to create a <type>Datum</> for return by the - function. The same slot can (and should) be reused on each call. + to build a <structname>HeapTuple</> given user data in Datum form. </para> <para> - After constructing an <structname>AttInMetadata</> structure, + When working with C strings, use <programlisting> HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) </programlisting> - can be used to build a <structname>HeapTuple</> given user data - in C string form. <literal>values</literal> is an array of C strings, one for - each attribute of the return row. Each C string should be in + to build a <structname>HeapTuple</> given user data + in C string form. <literal>values</literal> is an array of C strings, + one for each attribute of the return row. Each C string should be in the form expected by the input function of the attribute data type. In order to return a null value for one of the attributes, the corresponding pointer in the <parameter>values</> array @@ -1778,25 +1781,13 @@ HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) be called again for each row you return. </para> - <para> - Building a tuple via <function>TupleDescGetAttInMetadata</> and - <function>BuildTupleFromCStrings</> is only convenient if your - function naturally computes the values to be returned as text - strings. If your code naturally computes the values as a set of - <type>Datum</> values, you should instead use the underlying - function <function>heap_formtuple</> to convert the - <type>Datum</type> values directly into a tuple. You will still need - the <structname>TupleDesc</> and a <structname>TupleTableSlot</>, - but not <structname>AttInMetadata</>. - </para> - <para> Once you have built a tuple to return from your function, it must be converted into a <type>Datum</>. Use <programlisting> -TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple) +HeapTupleGetDatum(HeapTuple tuple) </programlisting> - to get a <type>Datum</> given a tuple and a slot. This + to convert a <structname>HeapTuple</> into a valid Datum. This <type>Datum</> can be returned directly if you intend to return just a single row, or it can be used as the current return value in a set-returning function. @@ -1851,8 +1842,8 @@ typedef struct /* * OPTIONAL pointer to result slot * - * slot is for use when returning tuples (i.e., composite data types) - * and is not needed when returning base data types. + * This is obsolete and only present for backwards compatibility, viz, + * user-defined SRFs that use the deprecated TupleDescGetSlot(). */ TupleTableSlot *slot; @@ -1868,9 +1859,9 @@ typedef struct * OPTIONAL pointer to struct containing attribute type input metadata * * attinmeta is for use when returning tuples (i.e., composite data types) - * and is not needed when returning base data types. It - * is only needed if you intend to use BuildTupleFromCStrings() to create - * the return tuple. + * and is not used when returning base data types. It is only needed + * if you intend to use BuildTupleFromCStrings() to create the return + * tuple. */ AttInMetadata *attinmeta; @@ -1883,6 +1874,18 @@ typedef struct * of the SRF. */ MemoryContext multi_call_memory_ctx; + + /* + * OPTIONAL pointer to struct containing tuple description + * + * tuple_desc is for use when returning tuples (i.e. composite data types) + * and is only needed if you are going to build the tuples with + * heap_formtuple() rather than with BuildTupleFromCStrings(). Note that + * the TupleDesc pointer stored here should usually have been run through + * BlessTupleDesc() first. + */ + TupleDesc tuple_desc; + } FuncCallContext; </programlisting> </para> @@ -1956,8 +1959,6 @@ my_set_returning_function(PG_FUNCTION_ARGS) <replaceable>user code</replaceable> <replaceable>if returning composite</replaceable> <replaceable>build TupleDesc, and perhaps AttInMetadata</replaceable> - <replaceable>obtain slot</replaceable> - funcctx->slot = slot; <replaceable>endif returning composite</replaceable> <replaceable>user code</replaceable> MemoryContextSwitchTo(oldcontext); @@ -1998,7 +1999,6 @@ testpassbyval(PG_FUNCTION_ARGS) int call_cntr; int max_calls; TupleDesc tupdesc; - TupleTableSlot *slot; AttInMetadata *attinmeta; /* stuff done only on the first call of the function */ @@ -2018,12 +2018,6 @@ testpassbyval(PG_FUNCTION_ARGS) /* Build a tuple description for a __testpassbyval tuple */ tupdesc = RelationNameGetTupleDesc("__testpassbyval"); - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - - /* assign slot to function context */ - funcctx->slot = slot; - /* * generate attribute metadata needed later to produce tuples from raw * C strings @@ -2039,7 +2033,6 @@ testpassbyval(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - slot = funcctx->slot; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) /* do when there is more left to send */ @@ -2049,7 +2042,7 @@ testpassbyval(PG_FUNCTION_ARGS) Datum result; /* - * Prepare a values array for storage in our slot. + * Prepare a values array for building the returned tuple. * This should be an array of C strings which will * be processed later by the type input functions. */ @@ -2066,7 +2059,7 @@ testpassbyval(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values[0]); diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index f1b20ff27323436f4c4ee2984ecafe937ae1c03f..4355c0df4c704b744daca974b92f3c445dbbfaef 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.89 2004/01/16 20:51:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.90 2004/04/01 21:28:43 tgl Exp $ * * NOTES * The old interface functions have been converted to macros @@ -31,6 +31,8 @@ /* ---------------- * ComputeDataSize + * + * Determine size of the data area of a tuple to be constructed * ---------------- */ Size @@ -417,7 +419,7 @@ nocachegetattr(HeapTuple tuple, * ---------------- */ Datum -heap_getsysattr(HeapTuple tup, int attnum, bool *isnull) +heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) { Datum result; @@ -451,6 +453,31 @@ heap_getsysattr(HeapTuple tup, int attnum, bool *isnull) case TableOidAttributeNumber: result = ObjectIdGetDatum(tup->t_tableOid); break; + + /* + * If the attribute number is 0, then we are supposed to return + * the entire tuple as a row-type Datum. (Using zero for this + * purpose is unclean since it risks confusion with "invalid attr" + * result codes, but it's not worth changing now.) + * + * We have to make a copy of the tuple so we can safely insert the + * Datum overhead fields, which are not set in on-disk tuples. + */ + case InvalidAttrNumber: + { + HeapTupleHeader dtup; + + dtup = (HeapTupleHeader) palloc(tup->t_len); + memcpy((char *) dtup, (char *) tup->t_data, tup->t_len); + + HeapTupleHeaderSetDatumLength(dtup, tup->t_len); + HeapTupleHeaderSetTypeId(dtup, tupleDesc->tdtypeid); + HeapTupleHeaderSetTypMod(dtup, tupleDesc->tdtypmod); + + result = PointerGetDatum(dtup); + } + break; + default: elog(ERROR, "invalid attnum: %d", attnum); result = 0; /* keep compiler quiet */ @@ -547,19 +574,10 @@ heap_deformtuple(HeapTuple tuple, /* ---------------- * heap_formtuple * - * constructs a tuple from the given *value and *null arrays - * - * old comments - * Handles alignment by aligning 2 byte attributes on short boundries - * and 3 or 4 byte attributes on long word boundries on a vax; and - * aligning non-byte attributes on short boundries on a sun. Does - * not properly align fixed length arrays of 1 or 2 byte types (yet). + * constructs a tuple from the given *value and *nulls arrays * * Null attributes are indicated by a 'n' in the appropriate byte - * of the *null. Non-null attributes are indicated by a ' ' (space). - * - * Fix me. (Figure that must keep context if debug--allow give oid.) - * Assumes in order. + * of *nulls. Non-null attributes are indicated by a ' ' (space). * ---------------- */ HeapTuple @@ -581,6 +599,9 @@ heap_formtuple(TupleDesc tupleDescriptor, errmsg("number of columns (%d) exceeds limit (%d)", numberOfAttributes, MaxTupleAttributeNumber))); + /* + * Determine total space needed + */ for (i = 0; i < numberOfAttributes; i++) { if (nulls[i] != ' ') @@ -602,15 +623,26 @@ heap_formtuple(TupleDesc tupleDescriptor, len += ComputeDataSize(tupleDescriptor, value, nulls); - tuple = (HeapTuple) palloc(HEAPTUPLESIZE + len); + /* + * Allocate and zero the space needed. Note that the tuple body and + * HeapTupleData management structure are allocated in one chunk. + */ + tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len); tuple->t_datamcxt = CurrentMemoryContext; - td = tuple->t_data = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); - - MemSet((char *) td, 0, len); + tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); + /* + * And fill in the information. Note we fill the Datum fields even + * though this tuple may never become a Datum. + */ tuple->t_len = len; ItemPointerSetInvalid(&(tuple->t_self)); tuple->t_tableOid = InvalidOid; + + HeapTupleHeaderSetDatumLength(td, len); + HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid); + HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod); + td->t_natts = numberOfAttributes; td->t_hoff = hoff; @@ -759,15 +791,15 @@ heap_addheader(int natts, /* max domain index */ hoff = MAXALIGN(hoff); len = hoff + structlen; - tuple = (HeapTuple) palloc(HEAPTUPLESIZE + len); + tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len); + tuple->t_datamcxt = CurrentMemoryContext; + tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); tuple->t_len = len; ItemPointerSetInvalid(&(tuple->t_self)); tuple->t_tableOid = InvalidOid; - tuple->t_datamcxt = CurrentMemoryContext; - tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); - MemSet((char *) td, 0, hoff); + /* we don't bother to fill the Datum fields */ td->t_natts = natts; td->t_hoff = hoff; diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 614cb00f5c2532930d0a52678eba00964c751ec5..1a016d86f80302631e542faea5c11449ba7df802 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.101 2003/11/29 19:51:39 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.102 2004/04/01 21:28:43 tgl Exp $ * * NOTES * some of the executor utility code such as "ExecTypeFromTL" should be @@ -28,12 +28,16 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/typcache.h" /* ---------------------------------------------------------------- * CreateTemplateTupleDesc * * This function allocates and zeros a tuple descriptor structure. + * + * Tuple type ID information is initially set for an anonymous record type; + * caller can overwrite this if needed. * ---------------------------------------------------------------- */ TupleDesc @@ -47,24 +51,26 @@ CreateTemplateTupleDesc(int natts, bool hasoid) AssertArg(natts >= 0); /* - * allocate enough memory for the tuple descriptor and zero it as - * TupleDescInitEntry assumes that the descriptor is filled with NULL - * pointers. + * Allocate enough memory for the tuple descriptor, and zero the + * attrs[] array since TupleDescInitEntry assumes that the array + * is filled with NULL pointers. */ desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); - desc->natts = natts; - desc->tdhasoid = hasoid; - if (natts > 0) - { - uint32 size = natts * sizeof(Form_pg_attribute); - - desc->attrs = (Form_pg_attribute *) palloc0(size); - } + desc->attrs = (Form_pg_attribute *) + palloc0(natts * sizeof(Form_pg_attribute)); else desc->attrs = NULL; + + /* + * Initialize other fields of the tupdesc. + */ + desc->natts = natts; desc->constr = NULL; + desc->tdtypeid = RECORDOID; + desc->tdtypmod = -1; + desc->tdhasoid = hasoid; return desc; } @@ -74,6 +80,9 @@ CreateTemplateTupleDesc(int natts, bool hasoid) * * This function allocates a new TupleDesc pointing to a given * Form_pg_attribute array + * + * Tuple type ID information is initially set for an anonymous record type; + * caller can overwrite this if needed. * ---------------------------------------------------------------- */ TupleDesc @@ -90,6 +99,8 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) desc->attrs = attrs; desc->natts = natts; desc->constr = NULL; + desc->tdtypeid = RECORDOID; + desc->tdtypmod = -1; desc->tdhasoid = hasoid; return desc; @@ -101,22 +112,21 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) * This function creates a new TupleDesc by copying from an existing * TupleDesc * - * !!! Constraints are not copied !!! + * !!! Constraints and defaults are not copied !!! * ---------------------------------------------------------------- */ TupleDesc CreateTupleDescCopy(TupleDesc tupdesc) { TupleDesc desc; - int i, - size; + int i; desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); desc->natts = tupdesc->natts; if (desc->natts > 0) { - size = desc->natts * sizeof(Form_pg_attribute); - desc->attrs = (Form_pg_attribute *) palloc(size); + desc->attrs = (Form_pg_attribute *) + palloc(desc->natts * sizeof(Form_pg_attribute)); for (i = 0; i < desc->natts; i++) { desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); @@ -127,7 +137,11 @@ CreateTupleDescCopy(TupleDesc tupdesc) } else desc->attrs = NULL; + desc->constr = NULL; + + desc->tdtypeid = tupdesc->tdtypeid; + desc->tdtypmod = tupdesc->tdtypmod; desc->tdhasoid = tupdesc->tdhasoid; return desc; @@ -137,7 +151,7 @@ CreateTupleDescCopy(TupleDesc tupdesc) * CreateTupleDescCopyConstr * * This function creates a new TupleDesc by copying from an existing - * TupleDesc (with Constraints) + * TupleDesc (including its constraints and defaults) * ---------------------------------------------------------------- */ TupleDesc @@ -145,15 +159,14 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) { TupleDesc desc; TupleConstr *constr = tupdesc->constr; - int i, - size; + int i; desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); desc->natts = tupdesc->natts; if (desc->natts > 0) { - size = desc->natts * sizeof(Form_pg_attribute); - desc->attrs = (Form_pg_attribute *) palloc(size); + desc->attrs = (Form_pg_attribute *) + palloc(desc->natts * sizeof(Form_pg_attribute)); for (i = 0; i < desc->natts; i++) { desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); @@ -162,9 +175,10 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) } else desc->attrs = NULL; + if (constr) { - TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr)); + TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr)); cpy->has_not_null = constr->has_not_null; @@ -197,10 +211,16 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) else desc->constr = NULL; + desc->tdtypeid = tupdesc->tdtypeid; + desc->tdtypmod = tupdesc->tdtypmod; desc->tdhasoid = tupdesc->tdhasoid; + return desc; } +/* + * Free a TupleDesc including all substructure + */ void FreeTupleDesc(TupleDesc tupdesc) { @@ -244,6 +264,10 @@ FreeTupleDesc(TupleDesc tupdesc) /* * Compare two TupleDesc structures for logical equality + * + * Note: we deliberately do not check the attrelid and tdtypmod fields. + * This allows typcache.c to use this routine to see if a cached record type + * matches a requested type, and is harmless for relcache.c's uses. */ bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) @@ -254,8 +278,11 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) if (tupdesc1->natts != tupdesc2->natts) return false; + if (tupdesc1->tdtypeid != tupdesc2->tdtypeid) + return false; if (tupdesc1->tdhasoid != tupdesc2->tdhasoid) return false; + for (i = 0; i < tupdesc1->natts; i++) { Form_pg_attribute attr1 = tupdesc1->attrs[i]; @@ -265,6 +292,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) * We do not need to check every single field here: we can * disregard attrelid, attnum (it was used to place the row in the * attrs array) and everything derived from the column datatype. + * Also, attcacheoff must NOT be checked since it's possibly not + * set in both copies. */ if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0) return false; @@ -272,6 +301,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) return false; if (attr1->attstattarget != attr2->attstattarget) return false; + if (attr1->attndims != attr2->attndims) + return false; if (attr1->atttypmod != attr2->atttypmod) return false; if (attr1->attstorage != attr2->attstorage) @@ -287,6 +318,7 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) if (attr1->attinhcount != attr2->attinhcount) return false; } + if (tupdesc1->constr != NULL) { TupleConstr *constr1 = tupdesc1->constr; @@ -360,8 +392,7 @@ TupleDescInitEntry(TupleDesc desc, const char *attributeName, Oid oidtypeid, int32 typmod, - int attdim, - bool attisset) + int attdim) { HeapTuple tuple; Form_pg_type typeForm; @@ -403,7 +434,6 @@ TupleDescInitEntry(TupleDesc desc, att->attnum = attributeNumber; att->attndims = attdim; - att->attisset = attisset; att->attnotnull = false; att->atthasdef = false; @@ -416,70 +446,13 @@ TupleDescInitEntry(TupleDesc desc, 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for type %u", oidtypeid); - - /* - * type info exists so we initialize our attribute information from - * the type tuple we found.. - */ typeForm = (Form_pg_type) GETSTRUCT(tuple); - att->atttypid = HeapTupleGetOid(tuple); - - /* - * There are a couple of cases where we must override the information - * stored in pg_type. - * - * First: if this attribute is a set, what is really stored in the - * attribute is the OID of a tuple in the pg_proc catalog. The pg_proc - * tuple contains the query string which defines this set - i.e., the - * query to run to get the set. So the atttypid (just assigned above) - * refers to the type returned by this query, but the actual length of - * this attribute is the length (size) of an OID. - * - * (Why not just make the atttypid point to the OID type, instead of the - * type the query returns? Because the executor uses the atttypid to - * tell the front end what type will be returned, and in the end the - * type returned will be the result of the query, not an OID.) - * - * (Why not wait until the return type of the set is known (i.e., the - * recursive call to the executor to execute the set has returned) - * before telling the front end what the return type will be? Because - * the executor is a delicate thing, and making sure that the correct - * order of front-end commands is maintained is messy, especially - * considering that target lists may change as inherited attributes - * are considered, etc. Ugh.) - * - * Second: if we are dealing with a complex type (a tuple type), then - * pg_type will say that the representation is the same as Oid. But - * if typmod is sizeof(Pointer) then the internal representation is - * actually a pointer to a TupleTableSlot, and we have to substitute - * that information. - * - * A set of complex type is first and foremost a set, so its - * representation is Oid not pointer. So, test that case first. - */ - if (attisset) - { - att->attlen = sizeof(Oid); - att->attbyval = true; - att->attalign = 'i'; - att->attstorage = 'p'; - } - else if (typeForm->typtype == 'c' && typmod == sizeof(Pointer)) - { - att->attlen = sizeof(Pointer); - att->attbyval = true; - att->attalign = 'd'; /* kluge to work with 8-byte pointers */ - /* XXX ought to have a separate attalign value for pointers ... */ - att->attstorage = 'p'; - } - else - { - att->attlen = typeForm->typlen; - att->attbyval = typeForm->typbyval; - att->attalign = typeForm->typalign; - att->attstorage = typeForm->typstorage; - } + att->atttypid = oidtypeid; + att->attlen = typeForm->typlen; + att->attbyval = typeForm->typbyval; + att->attalign = typeForm->typalign; + att->attstorage = typeForm->typstorage; ReleaseSysCache(tuple); } @@ -491,7 +464,8 @@ TupleDescInitEntry(TupleDesc desc, * Given a relation schema (list of ColumnDef nodes), build a TupleDesc. * * Note: the default assumption is no OIDs; caller may modify the returned - * TupleDesc if it wants OIDs. + * TupleDesc if it wants OIDs. Also, tdtypeid will need to be filled in + * later on. */ TupleDesc BuildDescForRelation(List *schema) @@ -501,12 +475,11 @@ BuildDescForRelation(List *schema) List *p; TupleDesc desc; AttrDefault *attrdef = NULL; - TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr)); + TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); char *attname; int32 atttypmod; int attdim; int ndef = 0; - bool attisset; /* * allocate a new tuple descriptor @@ -529,13 +502,18 @@ BuildDescForRelation(List *schema) attnum++; attname = entry->colname; - attisset = entry->typename->setof; atttypmod = entry->typename->typmod; attdim = length(entry->typename->arrayBounds); + if (entry->typename->setof) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("column \"%s\" cannot be declared SETOF", + attname))); + TupleDescInitEntry(desc, attnum, attname, typenameTypeId(entry->typename), - atttypmod, attdim, attisset); + atttypmod, attdim); /* Fill in additional stuff not handled by TupleDescInitEntry */ if (entry->is_not_null) @@ -586,6 +564,7 @@ BuildDescForRelation(List *schema) pfree(constr); desc->constr = NULL; } + return desc; } @@ -603,7 +582,7 @@ RelationNameGetTupleDesc(const char *relname) TupleDesc tupdesc; List *relname_list; - /* Open relation and get the tuple description */ + /* Open relation and copy the tuple description */ relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc"); relvar = makeRangeVarFromNameList(relname_list); rel = relation_openrv(relvar, AccessShareLock); @@ -620,7 +599,8 @@ RelationNameGetTupleDesc(const char *relname) * * If the type is composite, *and* a colaliases List is provided, *and* * the List is of natts length, use the aliases instead of the relation - * attnames. + * attnames. (NB: this usage is deprecated since it may result in + * creation of unnecessary transient record types.) * * If the type is a base type, a single item alias List is required. */ @@ -635,22 +615,12 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) */ if (functyptype == 'c') { - /* Composite data type, i.e. a table's row type */ - Oid relid = typeidTypeRelid(typeoid); - Relation rel; - int natts; - - if (!OidIsValid(relid)) - elog(ERROR, "invalid typrelid for complex type %u", typeoid); - - rel = relation_open(relid, AccessShareLock); - tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); - natts = tupdesc->natts; - relation_close(rel, AccessShareLock); - /* XXX should we hold the lock to ensure table doesn't change? */ + /* Composite data type, e.g. a table's row type */ + tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(typeoid, -1)); if (colaliases != NIL) { + int natts = tupdesc->natts; int varattno; /* does the list length match the number of attributes? */ @@ -667,6 +637,10 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) if (label != NULL) namestrcpy(&(tupdesc->attrs[varattno]->attname), label); } + + /* The tuple type is now an anonymous record type */ + tupdesc->tdtypeid = RECORDOID; + tupdesc->tdtypmod = -1; } } else if (functyptype == 'b' || functyptype == 'd') @@ -695,13 +669,15 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) attname, typeoid, -1, - 0, - false); + 0); } - else if (functyptype == 'p' && typeoid == RECORDOID) + else if (typeoid == RECORDOID) + { + /* XXX can't support this because typmod wasn't passed in ... */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("could not determine row description for function returning record"))); + } else { /* crummy error message, but parser should have caught this */ diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 902f0621377d89620d00aa6fd2c16d072ab1f634..695ef36b5098833c452e5cfc429f3b5ef90c844d 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.163 2004/03/11 01:47:35 ishii Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.164 2004/04/01 21:28:43 tgl Exp $ * * * INTERFACE ROUTINES @@ -1116,6 +1116,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid) tup->t_data->t_infomask |= HEAP_XMAX_INVALID; HeapTupleHeaderSetXmin(tup->t_data, GetCurrentTransactionId()); HeapTupleHeaderSetCmin(tup->t_data, cid); + HeapTupleHeaderSetCmax(tup->t_data, 0); /* zero out Datum fields */ tup->t_tableOid = relation->rd_id; /* @@ -1576,6 +1577,7 @@ l2: newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED); HeapTupleHeaderSetXmin(newtup->t_data, GetCurrentTransactionId()); HeapTupleHeaderSetCmin(newtup->t_data, cid); + HeapTupleHeaderSetCmax(newtup->t_data, 0); /* zero out Datum fields */ /* * If the toaster needs to be activated, OR if the new tuple will not diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index f18fece398251bda4c66cd869a73b286974fdd1b..c7fcb40087331dac925077bd0fc302635ed5ce38 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.177 2004/02/25 19:41:22 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.178 2004/04/01 21:28:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -107,34 +107,55 @@ struct typinfo Oid oid; Oid elem; int16 len; + bool byval; + char align; + char storage; Oid inproc; Oid outproc; }; -static struct typinfo Procid[] = { - {"bool", BOOLOID, 0, 1, F_BOOLIN, F_BOOLOUT}, - {"bytea", BYTEAOID, 0, -1, F_BYTEAIN, F_BYTEAOUT}, - {"char", CHAROID, 0, 1, F_CHARIN, F_CHAROUT}, - {"name", NAMEOID, 0, NAMEDATALEN, F_NAMEIN, F_NAMEOUT}, - {"int2", INT2OID, 0, 2, F_INT2IN, F_INT2OUT}, - {"int2vector", INT2VECTOROID, 0, INDEX_MAX_KEYS * 2, F_INT2VECTORIN, F_INT2VECTOROUT}, - {"int4", INT4OID, 0, 4, F_INT4IN, F_INT4OUT}, - {"regproc", REGPROCOID, 0, 4, F_REGPROCIN, F_REGPROCOUT}, - {"regclass", REGCLASSOID, 0, 4, F_REGCLASSIN, F_REGCLASSOUT}, - {"regtype", REGTYPEOID, 0, 4, F_REGTYPEIN, F_REGTYPEOUT}, - {"text", TEXTOID, 0, -1, F_TEXTIN, F_TEXTOUT}, - {"oid", OIDOID, 0, 4, F_OIDIN, F_OIDOUT}, - {"tid", TIDOID, 0, 6, F_TIDIN, F_TIDOUT}, - {"xid", XIDOID, 0, 4, F_XIDIN, F_XIDOUT}, - {"cid", CIDOID, 0, 4, F_CIDIN, F_CIDOUT}, - {"oidvector", OIDVECTOROID, 0, INDEX_MAX_KEYS * 4, F_OIDVECTORIN, F_OIDVECTOROUT}, - {"smgr", 210, 0, 2, F_SMGRIN, F_SMGROUT}, - {"_int4", 1007, INT4OID, -1, F_ARRAY_IN, F_ARRAY_OUT}, - {"_text", 1009, TEXTOID, -1, F_ARRAY_IN, F_ARRAY_OUT}, - {"_aclitem", 1034, 1033, -1, F_ARRAY_IN, F_ARRAY_OUT} +static const struct typinfo TypInfo[] = { + {"bool", BOOLOID, 0, 1, true, 'c', 'p', + F_BOOLIN, F_BOOLOUT}, + {"bytea", BYTEAOID, 0, -1, false, 'i', 'x', + F_BYTEAIN, F_BYTEAOUT}, + {"char", CHAROID, 0, 1, true, 'c', 'p', + F_CHARIN, F_CHAROUT}, + {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'i', 'p', + F_NAMEIN, F_NAMEOUT}, + {"int2", INT2OID, 0, 2, true, 's', 'p', + F_INT2IN, F_INT2OUT}, + {"int4", INT4OID, 0, 4, true, 'i', 'p', + F_INT4IN, F_INT4OUT}, + {"regproc", REGPROCOID, 0, 4, true, 'i', 'p', + F_REGPROCIN, F_REGPROCOUT}, + {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', + F_REGCLASSIN, F_REGCLASSOUT}, + {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', + F_REGTYPEIN, F_REGTYPEOUT}, + {"text", TEXTOID, 0, -1, false, 'i', 'x', + F_TEXTIN, F_TEXTOUT}, + {"oid", OIDOID, 0, 4, true, 'i', 'p', + F_OIDIN, F_OIDOUT}, + {"tid", TIDOID, 0, 6, false, 's', 'p', + F_TIDIN, F_TIDOUT}, + {"xid", XIDOID, 0, 4, true, 'i', 'p', + F_XIDIN, F_XIDOUT}, + {"cid", CIDOID, 0, 4, true, 'i', 'p', + F_CIDIN, F_CIDOUT}, + {"int2vector", INT2VECTOROID, INT2OID, INDEX_MAX_KEYS * 2, false, 's', 'p', + F_INT2VECTORIN, F_INT2VECTOROUT}, + {"oidvector", OIDVECTOROID, OIDOID, INDEX_MAX_KEYS * 4, false, 'i', 'p', + F_OIDVECTORIN, F_OIDVECTOROUT}, + {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', + F_ARRAY_IN, F_ARRAY_OUT}, + {"_text", 1009, TEXTOID, -1, false, 'i', 'x', + F_ARRAY_IN, F_ARRAY_OUT}, + {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x', + F_ARRAY_IN, F_ARRAY_OUT} }; -static int n_types = sizeof(Procid) / sizeof(struct typinfo); +static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo); struct typmap { /* a hack */ @@ -697,44 +718,13 @@ DefineAttr(char *name, char *type, int attnum) } else { - attrtypes[attnum]->atttypid = Procid[typeoid].oid; - attlen = attrtypes[attnum]->attlen = Procid[typeoid].len; - - /* - * Cheat like mad to fill in these items from the length only. - * This only has to work for types that appear in Procid[]. - */ - switch (attlen) - { - case 1: - attrtypes[attnum]->attbyval = true; - attrtypes[attnum]->attstorage = 'p'; - attrtypes[attnum]->attalign = 'c'; - break; - case 2: - attrtypes[attnum]->attbyval = true; - attrtypes[attnum]->attstorage = 'p'; - attrtypes[attnum]->attalign = 's'; - break; - case 4: - attrtypes[attnum]->attbyval = true; - attrtypes[attnum]->attstorage = 'p'; - attrtypes[attnum]->attalign = 'i'; - break; - case -1: - attrtypes[attnum]->attbyval = false; - attrtypes[attnum]->attstorage = 'x'; - attrtypes[attnum]->attalign = 'i'; - break; - default: - /* TID and fixed-length arrays, such as oidvector */ - attrtypes[attnum]->attbyval = false; - attrtypes[attnum]->attstorage = 'p'; - attrtypes[attnum]->attalign = 'i'; - break; - } + attrtypes[attnum]->atttypid = TypInfo[typeoid].oid; + attlen = attrtypes[attnum]->attlen = TypInfo[typeoid].len; + attrtypes[attnum]->attbyval = TypInfo[typeoid].byval; + attrtypes[attnum]->attstorage = TypInfo[typeoid].storage; + attrtypes[attnum]->attalign = TypInfo[typeoid].align; /* if an array type, assume 1-dimensional attribute */ - if (Procid[typeoid].elem != InvalidOid && attlen < 0) + if (TypInfo[typeoid].elem != InvalidOid && attlen < 0) attrtypes[attnum]->attndims = 1; else attrtypes[attnum]->attndims = 0; @@ -844,19 +834,19 @@ InsertOneValue(char *value, int i) { for (typeindex = 0; typeindex < n_types; typeindex++) { - if (Procid[typeindex].oid == attrtypes[i]->atttypid) + if (TypInfo[typeindex].oid == attrtypes[i]->atttypid) break; } if (typeindex >= n_types) elog(ERROR, "type oid %u not found", attrtypes[i]->atttypid); elog(DEBUG4, "Typ == NULL, typeindex = %u", typeindex); - values[i] = OidFunctionCall3(Procid[typeindex].inproc, + values[i] = OidFunctionCall3(TypInfo[typeindex].inproc, CStringGetDatum(value), - ObjectIdGetDatum(Procid[typeindex].elem), + ObjectIdGetDatum(TypInfo[typeindex].elem), Int32GetDatum(-1)); - prt = DatumGetCString(OidFunctionCall3(Procid[typeindex].outproc, + prt = DatumGetCString(OidFunctionCall3(TypInfo[typeindex].outproc, values[i], - ObjectIdGetDatum(Procid[typeindex].elem), + ObjectIdGetDatum(TypInfo[typeindex].elem), Int32GetDatum(-1))); elog(DEBUG4, " -> %s", prt); pfree(prt); @@ -930,9 +920,9 @@ cleanup(void) /* ---------------- * gettype * - * NB: this is really ugly; it will return an integer index into Procid[], + * NB: this is really ugly; it will return an integer index into TypInfo[], * and not an OID at all, until the first reference to a type not known in - * Procid[]. At that point it will read and cache pg_type in the Typ array, + * TypInfo[]. At that point it will read and cache pg_type in the Typ array, * and subsequently return a real OID (and set the global pointer Ap to * point at the found row in Typ). So caller must check whether Typ is * still NULL to determine what the return value is! @@ -962,7 +952,7 @@ gettype(char *type) { for (i = 0; i < n_types; i++) { - if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0) + if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0) return i; } elog(DEBUG4, "external type: %s", type); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index ed68f9124d595cffe352f7f0cf7f9ff5cd7f76d8..087e2d7f23cd312fbe3951ba98b6556ff0047619 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.261 2004/03/23 19:35:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.262 2004/04/01 21:28:43 tgl Exp $ * * * INTERFACE ROUTINES @@ -97,37 +97,37 @@ static void SetRelationNumChecks(Relation rel, int numchecks); static FormData_pg_attribute a1 = { 0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData), SelfItemPointerAttributeNumber, 0, -1, -1, - false, 'p', false, 'i', true, false, false, true, 0 + false, 'p', 's', true, false, false, true, 0 }; static FormData_pg_attribute a2 = { 0, {"oid"}, OIDOID, 0, sizeof(Oid), ObjectIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false, false, true, 0 + true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a3 = { 0, {"xmin"}, XIDOID, 0, sizeof(TransactionId), MinTransactionIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false, false, true, 0 + true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a4 = { 0, {"cmin"}, CIDOID, 0, sizeof(CommandId), MinCommandIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false, false, true, 0 + true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a5 = { 0, {"xmax"}, XIDOID, 0, sizeof(TransactionId), MaxTransactionIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false, false, true, 0 + true, 'p', 'i', true, false, false, true, 0 }; static FormData_pg_attribute a6 = { 0, {"cmax"}, CIDOID, 0, sizeof(CommandId), MaxCommandIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false, false, true, 0 + true, 'p', 'i', true, false, false, true, 0 }; /* @@ -139,7 +139,7 @@ static FormData_pg_attribute a6 = { static FormData_pg_attribute a7 = { 0, {"tableoid"}, OIDOID, 0, sizeof(Oid), TableOidAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false, false, true, 0 + true, 'p', 'i', true, false, false, true, 0 }; static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; @@ -633,6 +633,8 @@ AddNewRelationTuple(Relation pg_class_desc, new_rel_reltup->reltype = new_type_oid; new_rel_reltup->relkind = relkind; + new_rel_desc->rd_att->tdtypeid = new_type_oid; + /* ---------------- * now form a tuple to add to pg_class * XXX Natts_pg_class_fixed is a hack - see pg_class.h @@ -660,7 +662,7 @@ AddNewRelationTuple(Relation pg_class_desc, /* -------------------------------- * AddNewRelationType - * - * define a complex type corresponding to the new relation + * define a composite type corresponding to the new relation * -------------------------------- */ static void @@ -670,27 +672,12 @@ AddNewRelationType(const char *typeName, char new_rel_kind, Oid new_type_oid) { - /* - * We set the I/O procedures of a complex type to record_in and - * record_out, so that a user will get an error message not a weird - * number if he tries to SELECT a complex type. - * - * OLD and probably obsolete comments: - * - * The sizes are set to oid size because it makes implementing sets MUCH - * easier, and no one (we hope) uses these fields to figure out how - * much space to allocate for the type. An oid is the type used for a - * set definition. When a user requests a set, what they actually get - * is the oid of a tuple in the pg_proc catalog, so the size of the - * "set" is the size of an oid. Similarly, byval being true makes sets - * much easier, and it isn't used by anything else. - */ TypeCreate(typeName, /* type name */ typeNamespace, /* type namespace */ new_type_oid, /* preassigned oid for type */ new_rel_oid, /* relation oid */ new_rel_kind, /* relation kind */ - sizeof(Oid), /* internal size */ + -1, /* internal size (varlena) */ 'c', /* type-type (complex) */ ',', /* default array delimiter */ F_RECORD_IN, /* input procedure */ @@ -702,9 +689,9 @@ AddNewRelationType(const char *typeName, InvalidOid, /* domain base type - irrelevant */ NULL, /* default type value - none */ NULL, /* default type binary representation */ - true, /* passed by value */ - 'i', /* default alignment - same as for OID */ - 'p', /* Not TOASTable */ + false, /* passed by reference */ + 'd', /* alignment - must be the largest! */ + 'x', /* fully TOASTable */ -1, /* typmod */ 0, /* array dimensions for typBaseType */ false); /* Type NOT NULL */ diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 6fe64eadd0d9ba459dadb40723a778009d9466db..0640aacbe5a735133b9228eb69bfbcd9924bc5cc 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.113 2004/03/21 22:29:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.114 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,7 +32,6 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" -#include "utils/sets.h" #include "utils/syscache.h" @@ -137,44 +136,6 @@ ProcedureCreate(const char *procedureName, /* Process param names, if given */ namesarray = create_parameternames_array(parameterCount, parameterNames); - if (languageObjectId == SQLlanguageId) - { - /* - * If this call is defining a set, check if the set is already - * defined by looking to see whether this call's function text - * matches a function already in pg_proc. If so just return the - * OID of the existing set. - */ - if (strcmp(procedureName, GENERICSETNAME) == 0) - { -#ifdef SETS_FIXED - - /* - * The code below doesn't work any more because the PROSRC - * system cache and the pg_proc_prosrc_index have been - * removed. Instead a sequential heap scan or something better - * must get implemented. The reason for removing is that - * nbtree index crashes if sources exceed 2K --- what's likely - * for procedural languages. - * - * 1999/09/30 Jan - */ - text *prosrctext; - - prosrctext = DatumGetTextP(DirectFunctionCall1(textin, - CStringGetDatum(prosrc))); - retval = GetSysCacheOid(PROSRC, - PointerGetDatum(prosrctext), - 0, 0, 0); - pfree(prosrctext); - if (OidIsValid(retval)) - return retval; -#else - elog(ERROR, "lookup for procedure by source needs fix (Jan)"); -#endif /* SETS_FIXED */ - } - } - /* * don't allow functions of complex types that have the same name as * existing attributes of the type diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 3c134a5c16606faf6436bb0532bfd61a3818b3de..e2f3d4aa8136d10497418db50b134399e11be6fc 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.119 2004/01/31 05:09:40 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.120 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -125,7 +125,7 @@ ExplainResultDesc(ExplainStmt *stmt) /* need a tuple descriptor representing a single TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); return tupdesc; } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1a6bd2fdfc0d004dc14a565b5cdbaa2f2ffec0b7..a6e3a93d349512634f89184c89ec2d4484c14472 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.101 2004/03/23 19:35:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.102 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1796,7 +1796,6 @@ AlterTableAddColumn(Oid myrelid, attribute->attnum = i; attribute->attbyval = tform->typbyval; attribute->attndims = attndims; - attribute->attisset = (bool) (tform->typtype == 'c'); attribute->attstorage = tform->typstorage; attribute->attalign = tform->typalign; attribute->attnotnull = colDef->is_not_null; @@ -4084,15 +4083,15 @@ AlterTableCreateToastTable(Oid relOid, bool silent) TupleDescInitEntry(tupdesc, (AttrNumber) 1, "chunk_id", OIDOID, - -1, 0, false); + -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "chunk_seq", INT4OID, - -1, 0, false); + -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "chunk_data", BYTEAOID, - -1, 0, false); + -1, 0); /* * Ensure that the toast table doesn't itself get toasted, or we'll be diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 4c6f95a9a6f04e9dc27b4b32a0d7aae42ab4da0d..b27e86122bc871255c997441d99e85276d3c21fb 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.157 2004/03/24 22:40:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.158 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/typcache.h" /* static function decls */ @@ -110,7 +111,7 @@ static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate, static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalFieldSelect(GenericExprState *fstate, +static Datum ExecEvalFieldSelect(FieldSelectState *fstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalRelabelType(GenericExprState *exprstate, @@ -420,16 +421,25 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, *isDone = ExprSingleResult; /* - * get the slot we want + * Get the slot and attribute number we want + * + * The asserts check that references to system attributes only appear + * at the level of a relation scan; at higher levels, system attributes + * must be treated as ordinary variables (since we no longer have access + * to the original tuple). */ + attnum = variable->varattno; + switch (variable->varno) { case INNER: /* get the tuple from the inner node */ slot = econtext->ecxt_innertuple; + Assert(attnum > 0); break; case OUTER: /* get the tuple from the outer node */ slot = econtext->ecxt_outertuple; + Assert(attnum > 0); break; default: /* get the tuple from the relation being @@ -444,8 +454,6 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, heapTuple = slot->val; tuple_type = slot->ttc_tupleDescriptor; - attnum = variable->varattno; - /* * Some checks that are only applied for user attribute numbers * (bogus system attnums will be caught inside heap_getattr). @@ -481,38 +489,6 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid); } - /* - * If the attribute number is invalid, then we are supposed to return - * the entire tuple; we give back a whole slot so that callers know - * what the tuple looks like. - * - * XXX this is a horrid crock: since the pointer to the slot might live - * longer than the current evaluation context, we are forced to copy - * the tuple and slot into a long-lived context --- we use the - * econtext's per-query memory which should be safe enough. This - * represents a serious memory leak if many such tuples are processed - * in one command, however. We ought to redesign the representation - * of whole-tuple datums so that this is not necessary. - * - * We assume it's OK to point to the existing tupleDescriptor, rather - * than copy that too. - */ - if (attnum == InvalidAttrNumber) - { - MemoryContext oldContext; - TupleTableSlot *tempSlot; - HeapTuple tup; - - oldContext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); - tempSlot = MakeTupleTableSlot(); - tup = heap_copytuple(heapTuple); - ExecStoreTuple(tup, tempSlot, InvalidBuffer, true); - ExecSetSlotDescriptor(tempSlot, tuple_type, false); - MemoryContextSwitchTo(oldContext); - *isNull = false; - return PointerGetDatum(tempSlot); - } - result = heap_getattr(heapTuple, /* tuple containing attribute */ attnum, /* attribute number of desired * attribute */ @@ -656,17 +632,23 @@ ExecEvalParam(ExprState *exprstate, ExprContext *econtext, * GetAttributeByName * GetAttributeByNum * - * These are functions which return the value of the - * named attribute out of the tuple from the arg slot. User defined + * These functions return the value of the requested attribute + * out of the given tuple Datum. * C functions which take a tuple as an argument are expected - * to use this. Ex: overpaid(EMP) might call GetAttributeByNum(). + * to use these. Ex: overpaid(EMP) might call GetAttributeByNum(). + * Note: these are actually rather slow because they do a typcache + * lookup on each call. */ Datum -GetAttributeByNum(TupleTableSlot *slot, +GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, bool *isNull) { - Datum retval; + Datum result; + Oid tupType; + int32 tupTypmod; + TupleDesc tupDesc; + HeapTupleData tmptup; if (!AttributeNumberIsValid(attrno)) elog(ERROR, "invalid attribute number %d", attrno); @@ -674,29 +656,43 @@ GetAttributeByNum(TupleTableSlot *slot, if (isNull == NULL) elog(ERROR, "a NULL isNull pointer was passed"); - if (TupIsNull(slot)) + if (tuple == NULL) { + /* Kinda bogus but compatible with old behavior... */ *isNull = true; return (Datum) 0; } - retval = heap_getattr(slot->val, + tupType = HeapTupleHeaderGetTypeId(tuple); + tupTypmod = HeapTupleHeaderGetTypMod(tuple); + tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + + /* + * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set + * all the fields in the struct just in case user tries to inspect + * system columns. + */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); + ItemPointerSetInvalid(&(tmptup.t_self)); + tmptup.t_tableOid = InvalidOid; + tmptup.t_data = tuple; + + result = heap_getattr(&tmptup, attrno, - slot->ttc_tupleDescriptor, + tupDesc, isNull); - if (*isNull) - return (Datum) 0; - - return retval; + return result; } Datum -GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull) +GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull) { AttrNumber attrno; - TupleDesc tupdesc; - Datum retval; - int natts; + Datum result; + Oid tupType; + int32 tupTypmod; + TupleDesc tupDesc; + HeapTupleData tmptup; int i; if (attname == NULL) @@ -705,21 +701,23 @@ GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull) if (isNull == NULL) elog(ERROR, "a NULL isNull pointer was passed"); - if (TupIsNull(slot)) + if (tuple == NULL) { + /* Kinda bogus but compatible with old behavior... */ *isNull = true; return (Datum) 0; } - tupdesc = slot->ttc_tupleDescriptor; - natts = slot->val->t_data->t_natts; + tupType = HeapTupleHeaderGetTypeId(tuple); + tupTypmod = HeapTupleHeaderGetTypMod(tuple); + tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod); attrno = InvalidAttrNumber; - for (i = 0; i < tupdesc->natts; i++) + for (i = 0; i < tupDesc->natts; i++) { - if (namestrcmp(&(tupdesc->attrs[i]->attname), attname) == 0) + if (namestrcmp(&(tupDesc->attrs[i]->attname), attname) == 0) { - attrno = tupdesc->attrs[i]->attnum; + attrno = tupDesc->attrs[i]->attnum; break; } } @@ -727,14 +725,21 @@ GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull) if (attrno == InvalidAttrNumber) elog(ERROR, "attribute \"%s\" does not exist", attname); - retval = heap_getattr(slot->val, + /* + * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set + * all the fields in the struct just in case user tries to inspect + * system columns. + */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); + ItemPointerSetInvalid(&(tmptup.t_self)); + tmptup.t_tableOid = InvalidOid; + tmptup.t_data = tuple; + + result = heap_getattr(&tmptup, attrno, - tupdesc, + tupDesc, isNull); - if (*isNull) - return (Datum) 0; - - return retval; + return result; } /* @@ -1133,14 +1138,14 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, Tuplestorestate *tupstore = NULL; TupleDesc tupdesc = NULL; Oid funcrettype; + bool returnsTuple; FunctionCallInfoData fcinfo; ReturnSetInfo rsinfo; + HeapTupleData tmptup; MemoryContext callerContext; MemoryContext oldcontext; - TupleTableSlot *slot; bool direct_function_call; bool first_time = true; - bool returnsTuple = false; /* * Normally the passed expression tree will be a FuncExprState, since @@ -1216,6 +1221,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, funcrettype = exprType((Node *) funcexpr->expr); + returnsTuple = (funcrettype == RECORDOID || + get_typtype(funcrettype) == 'c'); + /* * Prepare a resultinfo node for communication. We always do this * even if not expecting a set result, so that we can pass @@ -1281,6 +1289,16 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, if (rsinfo.isDone == ExprEndResult) break; + /* + * Can't do anything useful with NULL rowtype values. Currently + * we raise an error, but another alternative is to just ignore + * the result and "continue" to get another row. + */ + if (returnsTuple && fcinfo.isnull) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("function returning row cannot return null value"))); + /* * If first time through, build tupdesc and tuplestore for * result @@ -1288,25 +1306,18 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, if (first_time) { oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); - if (funcrettype == RECORDOID || - get_typtype(funcrettype) == 'c') + if (returnsTuple) { /* - * Composite type, so function should have returned a - * TupleTableSlot; use its descriptor + * Use the type info embedded in the rowtype Datum to + * look up the needed tupdesc. Make a copy for the query. */ - slot = (TupleTableSlot *) DatumGetPointer(result); - if (fcinfo.isnull || !slot) - ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("function returning row cannot return null value"))); - if (!IsA(slot, TupleTableSlot) || - !slot->ttc_tupleDescriptor) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function returning row did not return a valid tuple slot"))); - tupdesc = CreateTupleDescCopy(slot->ttc_tupleDescriptor); - returnsTuple = true; + HeapTupleHeader td; + + td = DatumGetHeapTupleHeader(result); + tupdesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(td), + HeapTupleHeaderGetTypMod(td)); + tupdesc = CreateTupleDescCopy(tupdesc); } else { @@ -1319,8 +1330,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, "column", funcrettype, -1, - 0, - false); + 0); } tupstore = tuplestore_begin_heap(true, false, work_mem); MemoryContextSwitchTo(oldcontext); @@ -1333,15 +1343,17 @@ ExecMakeTableFunctionResult(ExprState *funcexpr, */ if (returnsTuple) { - slot = (TupleTableSlot *) DatumGetPointer(result); - if (fcinfo.isnull || - !slot || - !IsA(slot, TupleTableSlot) || - TupIsNull(slot)) - ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("function returning row cannot return null value"))); - tuple = slot->val; + HeapTupleHeader td; + + td = DatumGetHeapTupleHeader(result); + + /* + * tuplestore_puttuple needs a HeapTuple not a bare + * HeapTupleHeader, but it doesn't need all the fields. + */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(td); + tmptup.t_data = td; + tuple = &tmptup; } else { @@ -2415,26 +2427,62 @@ ExecEvalCoerceToDomainValue(ExprState *exprstate, * ---------------------------------------------------------------- */ static Datum -ExecEvalFieldSelect(GenericExprState *fstate, +ExecEvalFieldSelect(FieldSelectState *fstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone) { FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr; Datum result; - TupleTableSlot *resSlot; + Datum tupDatum; + HeapTupleHeader tuple; + Oid tupType; + int32 tupTypmod; + TupleDesc tupDesc; + HeapTupleData tmptup; - result = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); + tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone); /* this test covers the isDone exception too: */ if (*isNull) - return result; + return tupDatum; + + tuple = DatumGetHeapTupleHeader(tupDatum); + + tupType = HeapTupleHeaderGetTypeId(tuple); + tupTypmod = HeapTupleHeaderGetTypMod(tuple); + + /* Lookup tupdesc if first time through or if type changes */ + tupDesc = fstate->argdesc; + if (tupDesc == NULL || + tupType != tupDesc->tdtypeid || + tupTypmod != tupDesc->tdtypmod) + { + MemoryContext oldcontext; + + tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + /* Copy the tupdesc into query storage for safety */ + oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); + tupDesc = CreateTupleDescCopy(tupDesc); + if (fstate->argdesc) + FreeTupleDesc(fstate->argdesc); + fstate->argdesc = tupDesc; + MemoryContextSwitchTo(oldcontext); + } - resSlot = (TupleTableSlot *) DatumGetPointer(result); - Assert(resSlot != NULL && IsA(resSlot, TupleTableSlot)); - result = heap_getattr(resSlot->val, + /* + * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set + * all the fields in the struct just in case user tries to inspect + * system columns. + */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); + ItemPointerSetInvalid(&(tmptup.t_self)); + tmptup.t_tableOid = InvalidOid; + tmptup.t_data = tuple; + + result = heap_getattr(&tmptup, fselect->fieldnum, - resSlot->ttc_tupleDescriptor, + tupDesc, isNull); return result; } @@ -2703,11 +2751,12 @@ ExecInitExpr(Expr *node, PlanState *parent) case T_FieldSelect: { FieldSelect *fselect = (FieldSelect *) node; - GenericExprState *gstate = makeNode(GenericExprState); + FieldSelectState *fstate = makeNode(FieldSelectState); - gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFieldSelect; - gstate->arg = ExecInitExpr(fselect->arg, parent); - state = (ExprState *) gstate; + fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFieldSelect; + fstate->arg = ExecInitExpr(fselect->arg, parent); + fstate->argdesc = NULL; + state = (ExprState *) fstate; } break; case T_RelabelType: @@ -3088,8 +3137,6 @@ ExecTargetList(List *targetlist, List *tl; bool isNull; bool haveDoneSets; - static struct tupleDesc NullTupleDesc; /* we assume this inits to - * zeroes */ /* * debugging stuff @@ -3106,13 +3153,8 @@ ExecTargetList(List *targetlist, /* * There used to be some klugy and demonstrably broken code here that * special-cased the situation where targetlist == NIL. Now we just - * fall through and return an empty-but-valid tuple. We do, however, - * have to cope with the possibility that targettype is NULL --- - * heap_formtuple won't like that, so pass a dummy descriptor with - * natts = 0 to deal with it. + * fall through and return an empty-but-valid tuple. */ - if (targettype == NULL) - targettype = &NullTupleDesc; /* * evaluate all the expressions in the target list @@ -3285,8 +3327,8 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) /* * store the tuple in the projection slot and return the slot. */ - return ExecStoreTuple(newTuple, /* tuple to store */ - slot, /* slot to store in */ - InvalidBuffer, /* tuple has no buffer */ + return ExecStoreTuple(newTuple, /* tuple to store */ + slot, /* slot to store in */ + InvalidBuffer, /* tuple has no buffer */ true); } diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 0bb59d26b11758c755fa7d2ff934a4ff43092194..faf910b736f9828f43d90c37dab839ee02bf9e46 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.75 2004/01/07 18:56:26 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.76 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -109,8 +109,11 @@ #include "funcapi.h" #include "access/heapam.h" +#include "catalog/pg_type.h" #include "executor/executor.h" #include "utils/lsyscache.h" +#include "utils/typcache.h" + static TupleDesc ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk); @@ -144,16 +147,11 @@ ExecCreateTupleTable(int initialSize) /* initial number of slots in /* * Now allocate our new table along with space for the pointers to the - * tuples. + * tuples. Zero out the slots. */ newtable = (TupleTable) palloc(sizeof(TupleTableData)); - array = (TupleTableSlot *) palloc(initialSize * sizeof(TupleTableSlot)); - - /* - * clean out the slots we just allocated - */ - MemSet(array, 0, initialSize * sizeof(TupleTableSlot)); + array = (TupleTableSlot *) palloc0(initialSize * sizeof(TupleTableSlot)); /* * initialize the new table and return it to the caller. @@ -514,6 +512,10 @@ TupleTableSlot * ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) { TupleTableSlot *slot = ExecInitExtraTupleSlot(estate); + struct tupleDesc nullTupleDesc; + HeapTuple nullTuple; + Datum values[1]; + char nulls[1]; /* * Since heap_getattr() will treat attributes beyond a tuple's t_natts @@ -521,15 +523,12 @@ ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) * of zero length. However, the slot descriptor must match the real * tupType. */ - HeapTuple nullTuple; - Datum values[1]; - char nulls[1]; - static struct tupleDesc NullTupleDesc; /* we assume this inits to - * zeroes */ + nullTupleDesc = *tupType; + nullTupleDesc.natts = 0; - ExecSetSlotDescriptor(slot, tupType, false); + nullTuple = heap_formtuple(&nullTupleDesc, values, nulls); - nullTuple = heap_formtuple(&NullTupleDesc, values, nulls); + ExecSetSlotDescriptor(slot, tupType, false); return ExecStoreTuple(nullTuple, slot, InvalidBuffer, true); } @@ -590,21 +589,45 @@ ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk) resdom->resname, resdom->restype, resdom->restypmod, - 0, - false); + 0); } return typeInfo; } +/* + * BlessTupleDesc - make a completed tuple descriptor useful for SRFs + * + * Rowtype Datums returned by a function must contain valid type information. + * This happens "for free" if the tupdesc came from a relcache entry, but + * not if we have manufactured a tupdesc for a transient RECORD datatype. + * In that case we have to notify typcache.c of the existence of the type. + */ +TupleDesc +BlessTupleDesc(TupleDesc tupdesc) +{ + if (tupdesc->tdtypeid == RECORDOID && + tupdesc->tdtypmod < 0) + assign_record_type_typmod(tupdesc); + + return tupdesc; /* just for notational convenience */ +} + /* * TupleDescGetSlot - Initialize a slot based on the supplied tupledesc + * + * Note: this is obsolete; it is sufficient to call BlessTupleDesc on + * the tupdesc. We keep it around just for backwards compatibility with + * existing user-written SRFs. */ TupleTableSlot * TupleDescGetSlot(TupleDesc tupdesc) { TupleTableSlot *slot; + /* The useful work is here */ + BlessTupleDesc(tupdesc); + /* Make a standalone slot */ slot = MakeTupleTableSlot(); @@ -634,6 +657,9 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc) attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata)); + /* "Bless" the tupledesc so that we can make rowtype datums with it */ + attinmeta->tupdesc = BlessTupleDesc(tupdesc); + /* * Gather info needed later to call the "in" function for each * attribute @@ -653,7 +679,6 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc) atttypmods[i] = tupdesc->attrs[i]->atttypmod; } } - attinmeta->tupdesc = tupdesc; attinmeta->attinfuncs = attinfuncinfo; attinmeta->attelems = attelems; attinmeta->atttypmods = atttypmods; diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 8dec6131fb4ea7326eabdbccb666814c764c9e54..aa7652e07ef567eabcb72e1b82cee8c276330003 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.78 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.79 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,8 +24,10 @@ #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "utils/builtins.h" +#include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/typcache.h" /* @@ -61,10 +63,6 @@ typedef struct bool returnsTuple; /* true if return type is a tuple */ bool shutdown_reg; /* true if registered shutdown callback */ - TupleTableSlot *funcSlot; /* if one result we need to copy it before - * we end execution of the function and - * free stuff */ - ParamListInfo paramLI; /* Param list representing current args */ /* head of linked list of execution_state records */ @@ -196,34 +194,9 @@ init_sql_fcache(FmgrInfo *finfo) * get the type length and by-value flag from the type tuple */ fcache->typlen = typeStruct->typlen; - - if (typeStruct->typtype != 'c' && rettype != RECORDOID) - { - /* The return type is not a composite type, so just use byval */ - fcache->typbyval = typeStruct->typbyval; - fcache->returnsTuple = false; - } - else - { - /* - * This is a hack. We assume here that any function returning a - * tuple returns it by reference. This needs to be fixed, since - * actually the mechanism isn't quite like return-by-reference. - */ - fcache->typbyval = false; - fcache->returnsTuple = true; - } - - /* - * If we are returning exactly one result then we have to copy tuples - * and by reference results because we have to end the execution - * before we return the results. When you do this everything - * allocated by the executor (i.e. slots and tuples) is freed. - */ - if (!finfo->fn_retset && !fcache->typbyval) - fcache->funcSlot = MakeTupleTableSlot(); - else - fcache->funcSlot = NULL; + fcache->typbyval = typeStruct->typbyval; + fcache->returnsTuple = (typeStruct->typtype == 'c' || + rettype == RECORDOID); /* * Parse and plan the queries. We need the argument type info to pass @@ -366,39 +339,6 @@ postquel_sub_params(SQLFunctionCachePtr fcache, fcache->paramLI = paramLI; } -static TupleTableSlot * -copy_function_result(SQLFunctionCachePtr fcache, - TupleTableSlot *resultSlot) -{ - TupleTableSlot *funcSlot; - TupleDesc resultTd; - HeapTuple resultTuple; - HeapTuple newTuple; - - Assert(!TupIsNull(resultSlot)); - resultTuple = resultSlot->val; - - funcSlot = fcache->funcSlot; - - if (funcSlot == NULL) - return resultSlot; /* no need to copy result */ - - /* - * If first time through, we have to initialize the funcSlot's tuple - * descriptor. - */ - if (funcSlot->ttc_tupleDescriptor == NULL) - { - resultTd = CreateTupleDescCopy(resultSlot->ttc_tupleDescriptor); - ExecSetSlotDescriptor(funcSlot, resultTd, true); - ExecSetSlotDescriptorIsNew(funcSlot, true); - } - - newTuple = heap_copytuple(resultTuple); - - return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true); -} - static Datum postquel_execute(execution_state *es, FunctionCallInfo fcinfo, @@ -429,43 +369,51 @@ postquel_execute(execution_state *es, if (LAST_POSTQUEL_COMMAND(es)) { - TupleTableSlot *resSlot; - /* - * Copy the result. copy_function_result is smart enough to do - * nothing when no action is called for. This helps reduce the - * logic and code redundancy here. + * Set up to return the function value. */ - resSlot = copy_function_result(fcache, slot); + HeapTuple tup = slot->val; + TupleDesc tupDesc = slot->ttc_tupleDescriptor; - /* - * If we are supposed to return a tuple, we return the tuple slot - * pointer converted to Datum. If we are supposed to return a - * simple value, then project out the first attribute of the - * result tuple (ie, take the first result column of the final - * SELECT). - */ if (fcache->returnsTuple) { /* + * We are returning the whole tuple, so copy it into current + * execution context and make sure it is a valid Datum. + * * XXX do we need to remove junk attrs from the result tuple? * Probably OK to leave them, as long as they are at the end. */ - value = PointerGetDatum(resSlot); + HeapTupleHeader dtup; + + dtup = (HeapTupleHeader) palloc(tup->t_len); + memcpy((char *) dtup, (char *) tup->t_data, tup->t_len); + + /* + * For RECORD results, make sure a typmod has been assigned. + */ + if (tupDesc->tdtypeid == RECORDOID && + tupDesc->tdtypmod < 0) + assign_record_type_typmod(tupDesc); + + HeapTupleHeaderSetDatumLength(dtup, tup->t_len); + HeapTupleHeaderSetTypeId(dtup, tupDesc->tdtypeid); + HeapTupleHeaderSetTypMod(dtup, tupDesc->tdtypmod); + + value = PointerGetDatum(dtup); fcinfo->isnull = false; } else { - value = heap_getattr(resSlot->val, - 1, - resSlot->ttc_tupleDescriptor, - &(fcinfo->isnull)); - /* - * Note: if result type is pass-by-reference then we are - * returning a pointer into the tuple copied by - * copy_function_result. This is OK. + * Returning a scalar, which we have to extract from the + * first column of the SELECT result, and then copy into current + * execution context if needed. */ + value = heap_getattr(tup, 1, tupDesc, &(fcinfo->isnull)); + + if (!fcinfo->isnull) + value = datumCopy(value, fcache->typbyval, fcache->typlen); } /* diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index f3fa17c888167190c46861e6d80575802447e246..7847b24ffe20f2e316e847cf2fefe1a36c4ad6f7 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.23 2003/11/29 19:51:48 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.24 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +32,7 @@ #include "parser/parse_expr.h" #include "parser/parse_type.h" #include "utils/lsyscache.h" +#include "utils/typcache.h" static TupleTableSlot *FunctionNext(FunctionScanState *node); @@ -194,25 +195,12 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) if (functyptype == 'c') { - /* - * Composite data type, i.e. a table's row type - */ - Oid funcrelid; - Relation rel; - - funcrelid = typeidTypeRelid(funcrettype); - if (!OidIsValid(funcrelid)) - elog(ERROR, "invalid typrelid for complex type %u", - funcrettype); - rel = relation_open(funcrelid, AccessShareLock); - tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); - relation_close(rel, AccessShareLock); + /* Composite data type, e.g. a table's row type */ + tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(funcrettype, -1)); } else if (functyptype == 'b' || functyptype == 'd') { - /* - * Must be a base data type, i.e. scalar - */ + /* Must be a base data type, i.e. scalar */ char *attname = strVal(lfirst(rte->eref->colnames)); tupdesc = CreateTemplateTupleDesc(1, false); @@ -221,14 +209,11 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) attname, funcrettype, -1, - 0, - false); + 0); } - else if (functyptype == 'p' && funcrettype == RECORDOID) + else if (funcrettype == RECORDOID) { - /* - * Must be a pseudo type, i.e. record - */ + /* Must be a pseudo type, i.e. record */ tupdesc = BuildDescForRelation(rte->coldeflist); } else @@ -237,6 +222,14 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) elog(ERROR, "function in FROM has unsupported return type"); } + /* + * For RECORD results, make sure a typmod has been assigned. (The + * function should do this for itself, but let's cover things in case + * it doesn't.) + */ + if (tupdesc->tdtypeid == RECORDOID && tupdesc->tdtypmod < 0) + assign_record_type_typmod(tupdesc); + scanstate->tupdesc = tupdesc; ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot, tupdesc, false); diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 1fb60fff02d60f16f4c5f2d98f9202a4546c17ba..bcf7f8d52b68cffd345aee4f0f3c580840a1c4f8 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.112 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.113 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include "executor/spi_priv.h" #include "tcop/tcopprot.h" #include "utils/lsyscache.h" +#include "utils/typcache.h" uint32 SPI_processed = 0; @@ -380,40 +381,11 @@ SPI_copytuple(HeapTuple tuple) return ctuple; } -TupleDesc -SPI_copytupledesc(TupleDesc tupdesc) +HeapTupleHeader +SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc) { MemoryContext oldcxt = NULL; - TupleDesc ctupdesc; - - if (tupdesc == NULL) - { - SPI_result = SPI_ERROR_ARGUMENT; - return NULL; - } - - if (_SPI_curid + 1 == _SPI_connected) /* connected */ - { - if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) - elog(ERROR, "SPI stack corrupted"); - oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); - } - - ctupdesc = CreateTupleDescCopy(tupdesc); - - if (oldcxt) - MemoryContextSwitchTo(oldcxt); - - return ctupdesc; -} - -TupleTableSlot * -SPI_copytupleintoslot(HeapTuple tuple, TupleDesc tupdesc) -{ - MemoryContext oldcxt = NULL; - TupleTableSlot *cslot; - HeapTuple ctuple; - TupleDesc ctupdesc; + HeapTupleHeader dtup; if (tuple == NULL || tupdesc == NULL) { @@ -421,6 +393,11 @@ SPI_copytupleintoslot(HeapTuple tuple, TupleDesc tupdesc) return NULL; } + /* For RECORD results, make sure a typmod has been assigned */ + if (tupdesc->tdtypeid == RECORDOID && + tupdesc->tdtypmod < 0) + assign_record_type_typmod(tupdesc); + if (_SPI_curid + 1 == _SPI_connected) /* connected */ { if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) @@ -428,17 +405,17 @@ SPI_copytupleintoslot(HeapTuple tuple, TupleDesc tupdesc) oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } - ctuple = heap_copytuple(tuple); - ctupdesc = CreateTupleDescCopy(tupdesc); + dtup = (HeapTupleHeader) palloc(tuple->t_len); + memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len); - cslot = MakeTupleTableSlot(); - ExecSetSlotDescriptor(cslot, ctupdesc, true); - cslot = ExecStoreTuple(ctuple, cslot, InvalidBuffer, true); + HeapTupleHeaderSetDatumLength(dtup, tuple->t_len); + HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid); + HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod); if (oldcxt) MemoryContextSwitchTo(oldcxt); - return cslot; + return dtup; } HeapTuple diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 24b2fefe16af3ef0b1c01f67d71701a00a6a6cbb..1677493abbcea97c925275b8662adfedc8e08644 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.165 2004/01/07 18:56:27 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.166 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -170,9 +170,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, * tuple from the relation. We build a special VarNode to * reflect this -- it has varno set to the correct range table * entry, but has varattno == 0 to signal that the whole tuple - * is the argument. Also, it has typmod set to - * sizeof(Pointer) to signal that the runtime representation - * will be a pointer not an Oid. + * is the argument. */ switch (rte->rtekind) { @@ -185,7 +183,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, lfirst(i) = makeVar(vnum, InvalidAttrNumber, toid, - sizeof(Pointer), + -1, sublevels_up); break; case RTE_FUNCTION: @@ -196,7 +194,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, lfirst(i) = makeVar(vnum, InvalidAttrNumber, toid, - sizeof(Pointer), + -1, sublevels_up); } else @@ -214,6 +212,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, /* * RTE is a join or subselect; must fail for lack of a * named tuple type + * + * XXX FIXME */ if (is_column) unknown_attribute(schemaname, relname, diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e66eb905f563a198f485b9872e80ffb95eaea900..d83e8ac45805bec8661681b51c9cefc552a45b20 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.133 2004/01/14 23:01:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.134 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -523,16 +523,7 @@ build_column_default(Relation rel, int attrno) * No per-column default, so look for a default for the type * itself. */ - if (att_tup->attisset) - { - /* - * Set attributes are represented as OIDs no matter what the - * set element type is, and the element type's default is - * irrelevant too. - */ - } - else - expr = get_typdefault(atttype); + expr = get_typdefault(atttype); } if (expr == NULL) diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 5223e33816ec12757e85e4ffe58464a1240ef55b..427d6334cd43850c1e5f38757e60ca04a4c6b68f 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -1,7 +1,7 @@ # # Makefile for utils/adt # -# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.56 2003/11/29 19:51:57 pgsql Exp $ +# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.57 2004/04/01 21:28:45 tgl Exp $ # subdir = src/backend/utils/adt @@ -19,8 +19,8 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \ cash.o char.o date.o datetime.o datum.o float.o format_type.o \ geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \ misc.o nabstime.o name.o not_in.o numeric.o numutils.o \ - oid.o oracle_compat.o pseudotypes.o \ - regexp.o regproc.o ruleutils.o selfuncs.o sets.o \ + oid.o oracle_compat.o pseudotypes.o rowtypes.o \ + regexp.o regproc.o ruleutils.o selfuncs.o \ tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \ network.o mac.o inet_net_ntop.o inet_net_pton.o \ ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \ diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index b009e167a3fc4c4a3e9abc8eec894fa738270217..bc4901aa5463c634533340e8e874219e1277c1ec 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -6,7 +6,7 @@ * Copyright (c) 2002-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.12 2003/11/29 19:51:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.13 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,22 +52,22 @@ pg_lock_status(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ - /* this had better match pg_locks view in initdb.sh */ + /* this had better match pg_locks view in system_views.sql */ tupdesc = CreateTemplateTupleDesc(6, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation", - OIDOID, -1, 0, false); + OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", - OIDOID, -1, 0, false); + OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction", - XIDOID, -1, 0, false); + XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid", - INT4OID, -1, 0, false); + INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted", - BOOLOID, -1, 0, false); + BOOLOID, -1, 0); - funcctx->slot = TupleDescGetSlot(tupdesc); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and @@ -173,9 +173,8 @@ pg_lock_status(PG_FUNCTION_ARGS) CStringGetDatum(GetLockmodeName(mode))); values[5] = BoolGetDatum(granted); - tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor, - values, nulls); - result = TupleGetDatum(funcctx->slot, tuple); + tuple = heap_formtuple(funcctx->tuple_desc, values, nulls); + result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 71b99553bc16128bcc243fbcd136dfd2bd416d77..0526f52e67784bf7aef35bfa68bc0a248d1c3b9d 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.12 2003/11/29 19:51:59 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.13 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,59 +27,6 @@ #include "utils/builtins.h" -/* - * record_in - input routine for pseudo-type RECORD. - */ -Datum -record_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type record"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * record_out - output routine for pseudo-type RECORD. - */ -Datum -record_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type record"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * record_recv - binary input routine for pseudo-type RECORD. - */ -Datum -record_recv(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type record"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * record_send - binary output routine for pseudo-type RECORD. - */ -Datum -record_send(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot display a value of type record"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - - /* * cstring_in - input routine for pseudo-type CSTRING. * diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c new file mode 100644 index 0000000000000000000000000000000000000000..b487dfc9047e7afaa54466897af27905d86dc07d --- /dev/null +++ b/src/backend/utils/adt/rowtypes.c @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * rowtypes.c + * I/O functions for generic composite types. + * + * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.1 2004/04/01 21:28:45 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "libpq/pqformat.h" +#include "utils/builtins.h" + + +/* + * record_in - input routine for any composite type. + */ +Datum +record_in(PG_FUNCTION_ARGS) +{ + /* Need to decide on external format before we can write this */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("input of composite types not implemented yet"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + +/* + * record_out - output routine for any composite type. + */ +Datum +record_out(PG_FUNCTION_ARGS) +{ + /* Need to decide on external format before we can write this */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("output of composite types not implemented yet"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + +/* + * record_recv - binary input routine for any composite type. + */ +Datum +record_recv(PG_FUNCTION_ARGS) +{ + /* Need to decide on external format before we can write this */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("input of composite types not implemented yet"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + +/* + * record_send - binary output routine for any composite type. + */ +Datum +record_send(PG_FUNCTION_ARGS) +{ + /* Need to decide on external format before we can write this */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("output of composite types not implemented yet"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c deleted file mode 100644 index 33f1ed1a4a84265d3819bb17e93d45ac4c6f2488..0000000000000000000000000000000000000000 --- a/src/backend/utils/adt/sets.c +++ /dev/null @@ -1,213 +0,0 @@ -/*------------------------------------------------------------------------- - * - * sets.c - * Functions for sets, which are defined by queries. - * Example: a set is defined as being the result of the query - * retrieve (X.all) - * - * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/sets.c,v 1.62 2004/01/06 23:55:18 tgl Exp $ - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - -#include "access/heapam.h" -#include "catalog/catname.h" -#include "catalog/indexing.h" -#include "catalog/pg_language.h" -#include "catalog/pg_namespace.h" -#include "catalog/pg_proc.h" -#include "executor/executor.h" -#include "utils/fmgroids.h" -#include "utils/sets.h" -#include "utils/syscache.h" - - -/* - * SetDefine - converts query string defining set to an oid - * - * We create an SQL function having the given querystring as its body. - * The name of the function is then changed to use the OID of its tuple - * in pg_proc. - */ -Oid -SetDefine(char *querystr, Oid elemType) -{ - Oid setoid; - char *procname = GENERICSETNAME; - char *fileName = "-"; - char realprocname[NAMEDATALEN]; - HeapTuple tup, - newtup = NULL; - Form_pg_proc proc; - Relation procrel; - int i; - Datum replValue[Natts_pg_proc]; - char replNull[Natts_pg_proc]; - char repl[Natts_pg_proc]; - - setoid = ProcedureCreate(procname, /* changed below, after oid known */ - PG_CATALOG_NAMESPACE, /* XXX wrong */ - false, /* don't replace */ - true, /* returnsSet */ - elemType, /* returnType */ - SQLlanguageId, /* language */ - F_FMGR_SQL_VALIDATOR, - querystr, /* prosrc */ - fileName, /* probin */ - false, /* not aggregate */ - false, /* security invoker */ - false, /* isStrict (irrelevant, no args) */ - PROVOLATILE_VOLATILE, /* assume unsafe */ - 0, /* parameterCount */ - NULL, /* parameterTypes */ - NULL); /* parameterNames */ - - /* - * Since we're still inside this command of the transaction, we can't - * see the results of the procedure definition unless we pretend we've - * started the next command. (Postgres's solution to the Halloween - * problem is to not allow you to see the results of your command - * until you start the next command.) - */ - CommandCounterIncrement(); - - procrel = heap_openr(ProcedureRelationName, RowExclusiveLock); - - tup = SearchSysCache(PROCOID, - ObjectIdGetDatum(setoid), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for function %u", setoid); - - /* - * We can tell whether the set was already defined by checking the - * name. If it's GENERICSETNAME, the set is new. If it's "set<some - * oid>" it's already defined. - */ - proc = (Form_pg_proc) GETSTRUCT(tup); - if (strcmp(procname, NameStr(proc->proname)) == 0) - { - /* make the real proc name */ - snprintf(realprocname, sizeof(realprocname), "set%u", setoid); - - /* set up the attributes to be modified or kept the same */ - repl[0] = 'r'; - for (i = 1; i < Natts_pg_proc; i++) - repl[i] = ' '; - replValue[0] = (Datum) realprocname; - for (i = 1; i < Natts_pg_proc; i++) - replValue[i] = (Datum) 0; - for (i = 0; i < Natts_pg_proc; i++) - replNull[i] = ' '; - - /* change the pg_proc tuple */ - newtup = heap_modifytuple(tup, - procrel, - replValue, - replNull, - repl); - - simple_heap_update(procrel, &newtup->t_self, newtup); - - setoid = HeapTupleGetOid(newtup); - - CatalogUpdateIndexes(procrel, newtup); - - heap_freetuple(newtup); - } - - ReleaseSysCache(tup); - - heap_close(procrel, RowExclusiveLock); - - return setoid; -} - -/* - * This function executes set evaluation. The parser sets up a set reference - * as a call to this function with the OID of the set to evaluate as argument. - * - * We build a new fcache for execution of the set's function and run the - * function until it says "no mas". The fn_extra field of the call's - * FmgrInfo record is a handy place to hold onto the fcache. (Since this - * is a built-in function, there is no competing use of fn_extra.) - */ -Datum -seteval(PG_FUNCTION_ARGS) -{ - Oid funcoid = PG_GETARG_OID(0); - FuncExprState *fcache; - Datum result; - bool isNull; - ExprDoneCond isDone; - - /* - * If this is the first call, we need to set up the fcache for the - * target set's function. - */ - fcache = (FuncExprState *) fcinfo->flinfo->fn_extra; - if (fcache == NULL) - { - MemoryContext oldcontext; - FuncExpr *func; - - oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - - func = makeNode(FuncExpr); - func->funcid = funcoid; - func->funcresulttype = InvalidOid; /* nothing will look at - * this */ - func->funcretset = true; - func->funcformat = COERCE_EXPLICIT_CALL; - func->args = NIL; /* there are no arguments */ - - fcache = (FuncExprState *) ExecInitExpr((Expr *) func, NULL); - - MemoryContextSwitchTo(oldcontext); - - init_fcache(funcoid, fcache, fcinfo->flinfo->fn_mcxt); - - fcinfo->flinfo->fn_extra = (void *) fcache; - } - - /* - * Evaluate the function. NOTE: we need no econtext because there are - * no arguments to evaluate. - */ - - /* ExecMakeFunctionResult assumes these are initialized at call: */ - isNull = false; - isDone = ExprSingleResult; - - result = ExecMakeFunctionResult(fcache, - NULL, /* no econtext, see above */ - &isNull, - &isDone); - - /* - * Return isNull/isDone status. - */ - fcinfo->isnull = isNull; - - if (isDone != ExprSingleResult) - { - ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; - - if (rsi && IsA(rsi, ReturnSetInfo)) - rsi->isDone = isDone; - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that " - "cannot accept a set"))); - } - - PG_RETURN_DATUM(result); -} diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 5c302e18d39630ed8c6badffa3f02253211ca181..85ad6ffe78867490ac8ad45a0c75991dbe351c35 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.200 2004/03/16 05:05:58 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.201 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,6 +63,7 @@ #include "utils/lsyscache.h" #include "utils/relcache.h" #include "utils/syscache.h" +#include "utils/typcache.h" /* @@ -432,7 +433,10 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, AttrDefault *attrdef = NULL; int ndef = 0; - relation->rd_att->tdhasoid = RelationGetForm(relation)->relhasoids; + /* copy some fields from pg_class row to rd_att */ + relation->rd_att->tdtypeid = relation->rd_rel->reltype; + relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ + relation->rd_att->tdhasoid = relation->rd_rel->relhasoids; constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext, sizeof(TupleConstr)); @@ -1312,9 +1316,12 @@ formrdesc(const char *relationName, * Unlike the case with the relation tuple, this data had better be right * because it will never be replaced. The input values must be * correctly defined by macros in src/include/catalog/ headers. + * + * Note however that rd_att's tdtypeid, tdtypmod, tdhasoid fields are + * not right at this point. They will be fixed later when the real + * pg_class row is loaded. */ - relation->rd_att = CreateTemplateTupleDesc(natts, - relation->rd_rel->relhasoids); + relation->rd_att = CreateTemplateTupleDesc(natts, false); /* * initialize tuple desc info @@ -1595,6 +1602,7 @@ RelationReloadClassinfo(Relation relation) static void RelationClearRelation(Relation relation, bool rebuild) { + Oid old_reltype = relation->rd_rel->reltype; MemoryContext oldcxt; /* @@ -1679,6 +1687,7 @@ RelationClearRelation(Relation relation, bool rebuild) if (!rebuild) { /* ok to zap remaining substructure */ + flush_rowtype_cache(old_reltype); FreeTupleDesc(relation->rd_att); if (relation->rd_rulescxt) MemoryContextDelete(relation->rd_rulescxt); @@ -1704,6 +1713,7 @@ RelationClearRelation(Relation relation, bool rebuild) if (RelationBuildDesc(buildinfo, relation) != relation) { /* Should only get here if relation was deleted */ + flush_rowtype_cache(old_reltype); FreeTupleDesc(old_att); if (old_rulescxt) MemoryContextDelete(old_rulescxt); @@ -1715,11 +1725,15 @@ RelationClearRelation(Relation relation, bool rebuild) relation->rd_isnew = old_isnew; if (equalTupleDescs(old_att, relation->rd_att)) { + /* needn't flush typcache here */ FreeTupleDesc(relation->rd_att); relation->rd_att = old_att; } else + { + flush_rowtype_cache(old_reltype); FreeTupleDesc(old_att); + } if (equalRuleLocks(old_rules, relation->rd_rules)) { if (relation->rd_rulescxt) @@ -2329,6 +2343,12 @@ RelationCacheInitializePhase2(void) */ Assert(relation->rd_rel != NULL); memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE); + + /* + * Also update the derived fields in rd_att. + */ + relation->rd_att->tdtypeid = relp->reltype; + relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ relation->rd_att->tdhasoid = relp->relhasoids; ReleaseSysCache(htup); @@ -2918,6 +2938,8 @@ load_relcache_init_file(void) /* initialize attribute tuple forms */ rel->rd_att = CreateTemplateTupleDesc(relform->relnatts, relform->relhasoids); + rel->rd_att->tdtypeid = relform->reltype; + rel->rd_att->tdtypmod = -1; /* unnecessary, but... */ /* next read all the attribute tuple form data entries */ has_not_null = false; diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index d6e560c34c502c388f7dbc9953c460bc17eab2cf..7a8e67c83c8f82944b421130b2b5db0209833239 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -28,12 +28,15 @@ * doesn't cope with opclasses changing under it, either, so this seems * a low-priority problem. * + * We do support clearing the tuple descriptor part of a rowtype's cache + * entry, since that may need to change as a consequence of ALTER TABLE. + * * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.4 2003/11/29 19:52:00 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.5 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,11 +56,42 @@ #include "utils/fmgroids.h" #include "utils/hsearch.h" #include "utils/lsyscache.h" +#include "utils/syscache.h" #include "utils/typcache.h" +/* The main type cache hashtable searched by lookup_type_cache */ static HTAB *TypeCacheHash = NULL; +/* + * We use a separate table for storing the definitions of non-anonymous + * record types. Once defined, a record type will be remembered for the + * life of the backend. Subsequent uses of the "same" record type (where + * sameness means equalTupleDescs) will refer to the existing table entry. + * + * Stored record types are remembered in a linear array of TupleDescs, + * which can be indexed quickly with the assigned typmod. There is also + * a hash table to speed searches for matching TupleDescs. The hash key + * uses just the first N columns' type OIDs, and so we may have multiple + * entries with the same hash key. + */ +#define REC_HASH_KEYS 16 /* use this many columns in hash key */ + +typedef struct RecordCacheEntry +{ + /* the hash lookup key MUST BE FIRST */ + Oid hashkey[REC_HASH_KEYS]; /* column type IDs, zero-filled */ + + /* list of TupleDescs for record types with this hashkey */ + List *tupdescs; +} RecordCacheEntry; + +static HTAB *RecordCacheHash = NULL; + +static TupleDesc *RecordCacheArray = NULL; +static int32 RecordCacheArrayLen = 0; /* allocated length of array */ +static int32 NextRecordTypmod = 0; /* number of entries used */ + static Oid lookup_default_opclass(Oid type_id, Oid am_id); @@ -102,16 +136,26 @@ lookup_type_cache(Oid type_id, int flags) if (typentry == NULL) { /* - * If we didn't find one, we want to make one. But first get the - * required info from the pg_type row, just to make sure we don't - * make a cache entry for an invalid type OID. + * If we didn't find one, we want to make one. But first look up + * the pg_type row, just to make sure we don't make a cache entry + * for an invalid type OID. */ - int16 typlen; - bool typbyval; - char typalign; + HeapTuple tp; + Form_pg_type typtup; - get_typlenbyvalalign(type_id, &typlen, &typbyval, &typalign); + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(type_id), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for type %u", type_id); + typtup = (Form_pg_type) GETSTRUCT(tp); + if (!typtup->typisdefined) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" is only a shell", + NameStr(typtup->typname)))); + /* Now make the typcache entry */ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, (void *) &type_id, HASH_ENTER, &found); @@ -123,13 +167,20 @@ lookup_type_cache(Oid type_id, int flags) MemSet(typentry, 0, sizeof(TypeCacheEntry)); typentry->type_id = type_id; - typentry->typlen = typlen; - typentry->typbyval = typbyval; - typentry->typalign = typalign; + typentry->typlen = typtup->typlen; + typentry->typbyval = typtup->typbyval; + typentry->typalign = typtup->typalign; + typentry->typtype = typtup->typtype; + typentry->typrelid = typtup->typrelid; + + ReleaseSysCache(tp); } /* If we haven't already found the opclass, try to do so */ - if (flags != 0 && typentry->btree_opc == InvalidOid) + if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR | + TYPECACHE_CMP_PROC | + TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO)) && + typentry->btree_opc == InvalidOid) { typentry->btree_opc = lookup_default_opclass(type_id, BTREE_AM_OID); @@ -215,6 +266,30 @@ lookup_type_cache(Oid type_id, int flags) CacheMemoryContext); } + /* + * If it's a composite type (row type), get tupdesc if requested + */ + if ((flags & TYPECACHE_TUPDESC) && + typentry->tupDesc == NULL && + typentry->typtype == 'c') + { + Relation rel; + + if (!OidIsValid(typentry->typrelid)) /* should not happen */ + elog(ERROR, "invalid typrelid for composite type %u", + typentry->type_id); + rel = relation_open(typentry->typrelid, AccessShareLock); + Assert(rel->rd_rel->reltype == typentry->type_id); + /* + * Notice that we simply store a link to the relcache's tupdesc. + * Since we are relying on relcache to detect cache flush events, + * there's not a lot of point to maintaining an independent copy. + */ + typentry->tupDesc = RelationGetDescr(rel); + + relation_close(rel, AccessShareLock); + } + return typentry; } @@ -296,3 +371,172 @@ lookup_default_opclass(Oid type_id, Oid am_id) return InvalidOid; } + + +/* + * lookup_rowtype_tupdesc + * + * Given a typeid/typmod that should describe a known composite type, + * return the tuple descriptor for the type. Will ereport on failure. + * + * Note: returned TupleDesc points to cached copy; caller must copy it + * if intending to scribble on it or keep a reference for a long time. + */ +TupleDesc +lookup_rowtype_tupdesc(Oid type_id, int32 typmod) +{ + if (type_id != RECORDOID) + { + /* + * It's a named composite type, so use the regular typcache. + */ + TypeCacheEntry *typentry; + + typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC); + /* this should not happen unless caller messed up: */ + if (typentry->tupDesc == NULL) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("type %u is not composite", + type_id))); + return typentry->tupDesc; + } + else + { + /* + * It's a transient record type, so look in our record-type table. + */ + if (typmod < 0 || typmod >= NextRecordTypmod) + { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("record type has not been registered"))); + } + return RecordCacheArray[typmod]; + } +} + + +/* + * assign_record_type_typmod + * + * Given a tuple descriptor for a RECORD type, find or create a cache entry + * for the type, and set the tupdesc's tdtypmod field to a value that will + * identify this cache entry to lookup_rowtype_tupdesc. + */ +void +assign_record_type_typmod(TupleDesc tupDesc) +{ + RecordCacheEntry *recentry; + TupleDesc entDesc; + Oid hashkey[REC_HASH_KEYS]; + bool found; + int i; + List *l; + int32 newtypmod; + MemoryContext oldcxt; + + Assert(tupDesc->tdtypeid == RECORDOID); + + if (RecordCacheHash == NULL) + { + /* First time through: initialize the hash table */ + HASHCTL ctl; + + if (!CacheMemoryContext) + CreateCacheMemoryContext(); + + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = REC_HASH_KEYS * sizeof(Oid); + ctl.entrysize = sizeof(RecordCacheEntry); + ctl.hash = tag_hash; + RecordCacheHash = hash_create("Record information cache", 64, + &ctl, HASH_ELEM | HASH_FUNCTION); + } + + /* Find or create a hashtable entry for this hash class */ + MemSet(hashkey, 0, sizeof(hashkey)); + for (i = 0; i < tupDesc->natts; i++) + { + if (i >= REC_HASH_KEYS) + break; + hashkey[i] = tupDesc->attrs[i]->atttypid; + } + recentry = (RecordCacheEntry *) hash_search(RecordCacheHash, + (void *) hashkey, + HASH_ENTER, &found); + if (recentry == NULL) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + if (!found) + { + /* New entry ... hash_search initialized only the hash key */ + recentry->tupdescs = NIL; + } + + /* Look for existing record cache entry */ + foreach(l, recentry->tupdescs) + { + entDesc = (TupleDesc) lfirst(l); + if (equalTupleDescs(tupDesc, entDesc)) + { + tupDesc->tdtypmod = entDesc->tdtypmod; + return; + } + } + + /* Not present, so need to manufacture an entry */ + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + + if (RecordCacheArray == NULL) + { + RecordCacheArray = (TupleDesc *) palloc(64 * sizeof(TupleDesc)); + RecordCacheArrayLen = 64; + } + else if (NextRecordTypmod >= RecordCacheArrayLen) + { + int32 newlen = RecordCacheArrayLen * 2; + + RecordCacheArray = (TupleDesc *) repalloc(RecordCacheArray, + newlen * sizeof(TupleDesc)); + RecordCacheArrayLen = newlen; + } + + /* if fail in subrs, no damage except possibly some wasted memory... */ + entDesc = CreateTupleDescCopy(tupDesc); + recentry->tupdescs = lcons(entDesc, recentry->tupdescs); + /* now it's safe to advance NextRecordTypmod */ + newtypmod = NextRecordTypmod++; + entDesc->tdtypmod = newtypmod; + RecordCacheArray[newtypmod] = entDesc; + + /* report to caller as well */ + tupDesc->tdtypmod = newtypmod; + + MemoryContextSwitchTo(oldcxt); +} + +/* + * flush_rowtype_cache + * + * If a typcache entry exists for a rowtype, delete the entry's cached + * tuple descriptor link. This is called from relcache.c when a cached + * relation tupdesc is about to be dropped. + */ +void +flush_rowtype_cache(Oid type_id) +{ + TypeCacheEntry *typentry; + + if (TypeCacheHash == NULL) + return; /* no table, so certainly no entry */ + + typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, + (void *) &type_id, + HASH_FIND, NULL); + if (typentry == NULL) + return; /* no matching entry */ + + typentry->tupDesc = NULL; +} diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index e6ef3fcec3c9e9c7e82c8d239436a3023fc0950e..dac4a8916e14c8042e9ae672a5ded426e3d2913e 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -7,7 +7,7 @@ * Copyright (c) 2002-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.13 2003/12/19 00:02:11 joe Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.14 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,9 +49,8 @@ init_MultiFuncCall(PG_FUNCTION_ARGS) * Allocate suitably long-lived space and zero it */ retval = (FuncCallContext *) - MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(FuncCallContext)); - MemSet(retval, 0, sizeof(FuncCallContext)); + MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, + sizeof(FuncCallContext)); /* * initialize the elements @@ -61,6 +60,7 @@ init_MultiFuncCall(PG_FUNCTION_ARGS) retval->slot = NULL; retval->user_fctx = NULL; retval->attinmeta = NULL; + retval->tuple_desc = NULL; retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt; /* @@ -104,8 +104,11 @@ per_MultiFuncCall(PG_FUNCTION_ARGS) * FuncCallContext is pointing to it), but in most usage patterns the * tuples stored in it will be in the function's per-tuple context. So * at the beginning of each call, the Slot will hold a dangling - * pointer to an already-recycled tuple. We clear it out here. (See - * also the definition of TupleGetDatum() in funcapi.h!) + * pointer to an already-recycled tuple. We clear it out here. + * + * Note: use of retval->slot is obsolete as of 7.5, and we expect that + * it will always be NULL. This is just here for backwards compatibility + * in case someone creates a slot anyway. */ if (retval->slot != NULL) ExecClearTuple(retval->slot); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index bc2499ed3afc6956a967c02104a4152f38836e47..26f4210ad0e035f0ed128717b08b8d2556a4fd7d 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.194 2004/04/01 14:25:47 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.195 2004/04/01 21:28:45 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -3453,9 +3453,9 @@ GetPGVariableResultDesc(const char *name) /* need a tuple descriptor representing two TEXT columns */ tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); } else { @@ -3467,7 +3467,7 @@ GetPGVariableResultDesc(const char *name) /* need a tuple descriptor representing a single TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); } return tupdesc; } @@ -3507,7 +3507,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest) /* need a tuple descriptor representing a single TEXT column */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); /* prepare for projection of tuples */ tstate = begin_tup_output_tupdesc(dest, tupdesc); @@ -3532,9 +3532,9 @@ ShowAllGUCConfig(DestReceiver *dest) /* need a tuple descriptor representing two TEXT columns */ tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); /* prepare for projection of tuples */ tstate = begin_tup_output_tupdesc(dest, tupdesc); @@ -3740,7 +3740,6 @@ show_all_settings(PG_FUNCTION_ARGS) TupleDesc tupdesc; int call_cntr; int max_calls; - TupleTableSlot *slot; AttInMetadata *attinmeta; MemoryContext oldcontext; @@ -3762,31 +3761,25 @@ show_all_settings(PG_FUNCTION_ARGS) */ tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "category", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "short_desc", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "extra_desc", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "context", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "vartype", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "source", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "min_val", - TEXTOID, -1, 0, false); + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 10, "max_val", - TEXTOID, -1, 0, false); - - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - - /* assign slot to function context */ - funcctx->slot = slot; + TEXTOID, -1, 0); /* * Generate attribute metadata needed later to produce tuples from @@ -3806,7 +3799,6 @@ show_all_settings(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - slot = funcctx->slot; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) /* do when there is more left to send */ @@ -3837,7 +3829,7 @@ show_all_settings(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index c6579ea246282c2adeb1b7a55c52558947251ad9..9f91d81107ddb3cc032d7493ffb5bdc482846c08 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.87 2004/03/11 01:47:41 ishii Exp $ + * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.88 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -111,11 +111,12 @@ extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, fastgetattr((tup), (attnum), (tupleDesc), (isnull)) \ ) \ : \ - heap_getsysattr((tup), (attnum), (isnull)) \ + heap_getsysattr((tup), (attnum), (tupleDesc), (isnull)) \ ) \ ) -extern Datum heap_getsysattr(HeapTuple tup, int attnum, bool *isnull); +extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, + bool *isnull); /* ---------------- diff --git a/src/include/access/htup.h b/src/include/access/htup.h index a47e668f9b26d1e242a881452ea3fb94ca8480aa..3d48b5f45a3ad5657647881150453152cfb367b4 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.64 2004/01/16 20:51:30 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.65 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,10 +47,19 @@ #define MaxHeapAttributeNumber 1600 /* 8 * 200 */ /*---------- - * On-disk heap tuple header. Currently this is also used as the header - * format for tuples formed in memory, although in principle they could - * be different. To avoid wasting space, the fields should be layed out - * in such a way to avoid structure padding. + * Heap tuple header. To avoid wasting space, the fields should be + * layed out in such a way to avoid structure padding. + * + * Datums of composite types (row types) share the same general structure + * as on-disk tuples, so that the same routines can be used to build and + * examine them. However the requirements are slightly different: a Datum + * does not need any transaction visibility information, and it does need + * a length word and some embedded type information. We can achieve this + * by overlaying the xmin/cmin/xmax/cmax/xvac fields of a heap tuple + * with the fields needed in the Datum case. Typically, all tuples built + * in-memory will be initialized with the Datum fields; but when a tuple is + * about to be inserted in a table, the transaction fields will be filled, + * overwriting the datum fields. * * The overall structure of a heap tuple looks like: * fixed fields (HeapTupleHeaderData struct) @@ -96,7 +105,8 @@ * MAXALIGN. *---------- */ -typedef struct HeapTupleHeaderData + +typedef struct HeapTupleFields { TransactionId t_xmin; /* inserting xact ID */ @@ -111,6 +121,28 @@ typedef struct HeapTupleHeaderData CommandId t_cmax; /* deleting command ID */ TransactionId t_xvac; /* VACUUM FULL xact ID */ } t_field3; +} HeapTupleFields; + +typedef struct DatumTupleFields +{ + int32 datum_len; /* required to be a varlena type */ + + int32 datum_typmod; /* -1, or identifier of a record type */ + + Oid datum_typeid; /* composite type OID, or RECORDOID */ + /* + * Note: field ordering is chosen with thought that Oid might someday + * widen to 64 bits. + */ +} DatumTupleFields; + +typedef struct HeapTupleHeaderData +{ + union + { + HeapTupleFields t_heap; + DatumTupleFields t_datum; + } t_choice; ItemPointerData t_ctid; /* current TID of this or newer tuple */ @@ -169,31 +201,31 @@ typedef HeapTupleHeaderData *HeapTupleHeader; #define HeapTupleHeaderGetXmin(tup) \ ( \ - (tup)->t_xmin \ + (tup)->t_choice.t_heap.t_xmin \ ) #define HeapTupleHeaderSetXmin(tup, xid) \ ( \ - TransactionIdStore((xid), &(tup)->t_xmin) \ + TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_xmin) \ ) #define HeapTupleHeaderGetXmax(tup) \ ( \ ((tup)->t_infomask & HEAP_XMAX_IS_XMIN) ? \ - (tup)->t_xmin \ + (tup)->t_choice.t_heap.t_xmin \ : \ - (tup)->t_field2.t_xmax \ + (tup)->t_choice.t_heap.t_field2.t_xmax \ ) #define HeapTupleHeaderSetXmax(tup, xid) \ do { \ TransactionId _newxid = (xid); \ - if (TransactionIdEquals((tup)->t_xmin, _newxid)) \ + if (TransactionIdEquals((tup)->t_choice.t_heap.t_xmin, _newxid)) \ (tup)->t_infomask |= HEAP_XMAX_IS_XMIN; \ else \ { \ (tup)->t_infomask &= ~HEAP_XMAX_IS_XMIN; \ - TransactionIdStore(_newxid, &(tup)->t_field2.t_xmax); \ + TransactionIdStore(_newxid, &(tup)->t_choice.t_heap.t_field2.t_xmax); \ } \ } while (0) @@ -207,13 +239,13 @@ do { \ */ #define HeapTupleHeaderGetCmin(tup) \ ( \ - (tup)->t_field2.t_cmin \ + (tup)->t_choice.t_heap.t_field2.t_cmin \ ) #define HeapTupleHeaderSetCmin(tup, cid) \ do { \ Assert((tup)->t_infomask & HEAP_XMAX_INVALID); \ - (tup)->t_field2.t_cmin = (cid); \ + (tup)->t_choice.t_heap.t_field2.t_cmin = (cid); \ } while (0) /* @@ -222,19 +254,19 @@ do { \ */ #define HeapTupleHeaderGetCmax(tup) \ ( \ - (tup)->t_field3.t_cmax \ + (tup)->t_choice.t_heap.t_field3.t_cmax \ ) #define HeapTupleHeaderSetCmax(tup, cid) \ do { \ Assert(!((tup)->t_infomask & HEAP_MOVED)); \ - (tup)->t_field3.t_cmax = (cid); \ + (tup)->t_choice.t_heap.t_field3.t_cmax = (cid); \ } while (0) #define HeapTupleHeaderGetXvac(tup) \ ( \ ((tup)->t_infomask & HEAP_MOVED) ? \ - (tup)->t_field3.t_xvac \ + (tup)->t_choice.t_heap.t_field3.t_xvac \ : \ InvalidTransactionId \ ) @@ -242,9 +274,39 @@ do { \ #define HeapTupleHeaderSetXvac(tup, xid) \ do { \ Assert((tup)->t_infomask & HEAP_MOVED); \ - TransactionIdStore((xid), &(tup)->t_field3.t_xvac); \ + TransactionIdStore((xid), &(tup)->t_choice.t_heap.t_field3.t_xvac); \ } while (0) +#define HeapTupleHeaderGetDatumLength(tup) \ +( \ + (tup)->t_choice.t_datum.datum_len \ +) + +#define HeapTupleHeaderSetDatumLength(tup, len) \ +( \ + (tup)->t_choice.t_datum.datum_len = (len) \ +) + +#define HeapTupleHeaderGetTypeId(tup) \ +( \ + (tup)->t_choice.t_datum.datum_typeid \ +) + +#define HeapTupleHeaderSetTypeId(tup, typeid) \ +( \ + (tup)->t_choice.t_datum.datum_typeid = (typeid) \ +) + +#define HeapTupleHeaderGetTypMod(tup) \ +( \ + (tup)->t_choice.t_datum.datum_typmod \ +) + +#define HeapTupleHeaderSetTypMod(tup, typmod) \ +( \ + (tup)->t_choice.t_datum.datum_typmod = (typmod) \ +) + #define HeapTupleHeaderGetOid(tup) \ ( \ ((tup)->t_infomask & HEAP_HASOID) ? \ @@ -261,95 +323,10 @@ do { \ /* - * WAL record definitions for heapam.c's WAL operations - * - * XLOG allows to store some information in high 4 bits of log - * record xl_info field - */ -#define XLOG_HEAP_INSERT 0x00 -#define XLOG_HEAP_DELETE 0x10 -#define XLOG_HEAP_UPDATE 0x20 -#define XLOG_HEAP_MOVE 0x30 -#define XLOG_HEAP_CLEAN 0x40 -#define XLOG_HEAP_OPMASK 0x70 -/* - * When we insert 1st item on new page in INSERT/UPDATE - * we can (and we do) restore entire page in redo - */ -#define XLOG_HEAP_INIT_PAGE 0x80 - -/* - * All what we need to find changed tuple (14 bytes) - * - * NB: on most machines, sizeof(xl_heaptid) will include some trailing pad - * bytes for alignment. We don't want to store the pad space in the XLOG, - * so use SizeOfHeapTid for space calculations. Similar comments apply for - * the other xl_FOO structs. - */ -typedef struct xl_heaptid -{ - RelFileNode node; - ItemPointerData tid; /* changed tuple id */ -} xl_heaptid; - -#define SizeOfHeapTid (offsetof(xl_heaptid, tid) + SizeOfIptrData) - -/* This is what we need to know about delete */ -typedef struct xl_heap_delete -{ - xl_heaptid target; /* deleted tuple id */ -} xl_heap_delete; - -#define SizeOfHeapDelete (offsetof(xl_heap_delete, target) + SizeOfHeapTid) - -/* - * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted - * or updated tuple in WAL; we can save a few bytes by reconstructing the - * fields that are available elsewhere in the WAL record, or perhaps just - * plain needn't be reconstructed. These are the fields we must store. - * NOTE: t_hoff could be recomputed, but we may as well store it because - * it will come for free due to alignment considerations. + * BITMAPLEN(NATTS) - + * Computes size of null bitmap given number of data columns. */ -typedef struct xl_heap_header -{ - int16 t_natts; - uint16 t_infomask; - uint8 t_hoff; -} xl_heap_header; - -#define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8)) - -/* This is what we need to know about insert */ -typedef struct xl_heap_insert -{ - xl_heaptid target; /* inserted tuple id */ - /* xl_heap_header & TUPLE DATA FOLLOWS AT END OF STRUCT */ -} xl_heap_insert; - -#define SizeOfHeapInsert (offsetof(xl_heap_insert, target) + SizeOfHeapTid) - -/* This is what we need to know about update|move */ -typedef struct xl_heap_update -{ - xl_heaptid target; /* deleted tuple id */ - ItemPointerData newtid; /* new inserted tuple id */ - /* NEW TUPLE xl_heap_header (PLUS xmax & xmin IF MOVE OP) */ - /* and TUPLE DATA FOLLOWS AT END OF STRUCT */ -} xl_heap_update; - -#define SizeOfHeapUpdate (offsetof(xl_heap_update, newtid) + SizeOfIptrData) - -/* This is what we need to know about page cleanup */ -typedef struct xl_heap_clean -{ - RelFileNode node; - BlockNumber block; - /* UNUSED OFFSET NUMBERS FOLLOW AT THE END */ -} xl_heap_clean; - -#define SizeOfHeapClean (offsetof(xl_heap_clean, block) + sizeof(BlockNumber)) - - +#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) /* * MaxTupleSize is the maximum allowed size of a tuple, including header and @@ -388,6 +365,7 @@ typedef struct xl_heap_clean #define TableOidAttributeNumber (-7) #define FirstLowInvalidHeapAttributeNumber (-8) + /* * HeapTupleData is an in-memory data structure that points to a tuple. * @@ -417,22 +395,13 @@ typedef HeapTupleData *HeapTuple; #define HEAPTUPLESIZE MAXALIGN(sizeof(HeapTupleData)) - /* * GETSTRUCT - given a HeapTuple pointer, return address of the user data */ #define GETSTRUCT(TUP) ((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff) - /* - * BITMAPLEN(NATTS) - - * Computes size of null bitmap given number of data columns. - */ -#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) - -/* - * HeapTupleIsValid - * True iff the heap tuple is valid. + * Accessor macros to be used with HeapTuple pointers. */ #define HeapTupleIsValid(tuple) PointerIsValid(tuple) @@ -463,4 +432,94 @@ typedef HeapTupleData *HeapTuple; #define HeapTupleSetOid(tuple, oid) \ HeapTupleHeaderSetOid((tuple)->t_data, (oid)) + +/* + * WAL record definitions for heapam.c's WAL operations + * + * XLOG allows to store some information in high 4 bits of log + * record xl_info field + */ +#define XLOG_HEAP_INSERT 0x00 +#define XLOG_HEAP_DELETE 0x10 +#define XLOG_HEAP_UPDATE 0x20 +#define XLOG_HEAP_MOVE 0x30 +#define XLOG_HEAP_CLEAN 0x40 +#define XLOG_HEAP_OPMASK 0x70 +/* + * When we insert 1st item on new page in INSERT/UPDATE + * we can (and we do) restore entire page in redo + */ +#define XLOG_HEAP_INIT_PAGE 0x80 + +/* + * All what we need to find changed tuple (14 bytes) + * + * NB: on most machines, sizeof(xl_heaptid) will include some trailing pad + * bytes for alignment. We don't want to store the pad space in the XLOG, + * so use SizeOfHeapTid for space calculations. Similar comments apply for + * the other xl_FOO structs. + */ +typedef struct xl_heaptid +{ + RelFileNode node; + ItemPointerData tid; /* changed tuple id */ +} xl_heaptid; + +#define SizeOfHeapTid (offsetof(xl_heaptid, tid) + SizeOfIptrData) + +/* This is what we need to know about delete */ +typedef struct xl_heap_delete +{ + xl_heaptid target; /* deleted tuple id */ +} xl_heap_delete; + +#define SizeOfHeapDelete (offsetof(xl_heap_delete, target) + SizeOfHeapTid) + +/* + * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted + * or updated tuple in WAL; we can save a few bytes by reconstructing the + * fields that are available elsewhere in the WAL record, or perhaps just + * plain needn't be reconstructed. These are the fields we must store. + * NOTE: t_hoff could be recomputed, but we may as well store it because + * it will come for free due to alignment considerations. + */ +typedef struct xl_heap_header +{ + int16 t_natts; + uint16 t_infomask; + uint8 t_hoff; +} xl_heap_header; + +#define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8)) + +/* This is what we need to know about insert */ +typedef struct xl_heap_insert +{ + xl_heaptid target; /* inserted tuple id */ + /* xl_heap_header & TUPLE DATA FOLLOWS AT END OF STRUCT */ +} xl_heap_insert; + +#define SizeOfHeapInsert (offsetof(xl_heap_insert, target) + SizeOfHeapTid) + +/* This is what we need to know about update|move */ +typedef struct xl_heap_update +{ + xl_heaptid target; /* deleted tuple id */ + ItemPointerData newtid; /* new inserted tuple id */ + /* NEW TUPLE xl_heap_header (PLUS xmax & xmin IF MOVE OP) */ + /* and TUPLE DATA FOLLOWS AT END OF STRUCT */ +} xl_heap_update; + +#define SizeOfHeapUpdate (offsetof(xl_heap_update, newtid) + SizeOfIptrData) + +/* This is what we need to know about page cleanup */ +typedef struct xl_heap_clean +{ + RelFileNode node; + BlockNumber block; + /* UNUSED OFFSET NUMBERS FOLLOW AT THE END */ +} xl_heap_clean; + +#define SizeOfHeapClean (offsetof(xl_heap_clean, block) + sizeof(BlockNumber)) + #endif /* HTUP_H */ diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index bf4e3aa105528f78930a4ca7e9403de9275b4fa8..c7e560c0c65e53c5c50fa446bbce05cc9861aa6f 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.42 2003/11/29 22:40:55 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.43 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,15 @@ typedef struct tupleConstr /* * This structure contains all information (i.e. from Classes * pg_attribute, pg_attrdef, pg_constraint) for the structure of a tuple. + * + * Note that only user attributes, not system attributes, are mentioned in + * TupleDesc; with the exception that tdhasoid indicates if OID is present. + * + * If the tuple is known to correspond to a named rowtype (such as a table's + * rowtype) then tdtypeid identifies that type and tdtypmod is -1. Otherwise + * tdtypeid is RECORDOID, and tdtypmod can be either -1 for a fully anonymous + * row type, or a value >= 0 to allow the rowtype to be looked up in the + * typcache.c type cache. */ typedef struct tupleDesc { @@ -51,6 +60,8 @@ typedef struct tupleDesc Form_pg_attribute *attrs; /* attrs[N] is a pointer to the description of Attribute Number N+1. */ TupleConstr *constr; + Oid tdtypeid; /* composite type ID for tuple type */ + int32 tdtypmod; /* typmod for tuple type */ bool tdhasoid; /* Tuple has oid attribute in its header */ } *TupleDesc; @@ -73,8 +84,7 @@ extern void TupleDescInitEntry(TupleDesc desc, const char *attributeName, Oid oidtypeid, int32 typmod, - int attdim, - bool attisset); + int attdim); extern TupleDesc BuildDescForRelation(List *schema); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 5344d7afe8690d9564a60d14a0b15658ad11280f..82900e55f340db36b18a6e3698e18e78821d9053 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.222 2004/03/22 01:38:17 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.223 2004/04/01 21:28:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200403211 +#define CATALOG_VERSION_NO 200403291 #endif diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 754878f0148be7680d3e42e4b8a8d076eb7647fe..896a06ada86eaf112baed40da976b149695aa109 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.108 2004/02/12 23:41:04 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.109 2004/04/01 21:28:45 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -129,9 +129,6 @@ CATALOG(pg_attribute) BOOTSTRAP BKI_WITHOUT_OIDS */ char attstorage; - /* This flag indicates that the attribute is really a set */ - bool attisset; - /* * attalign is a copy of the typalign field from pg_type for this * attribute. See atttypid comments above. @@ -174,7 +171,7 @@ typedef FormData_pg_attribute *Form_pg_attribute; * ---------------- */ -#define Natts_pg_attribute 18 +#define Natts_pg_attribute 17 #define Anum_pg_attribute_attrelid 1 #define Anum_pg_attribute_attname 2 #define Anum_pg_attribute_atttypid 3 @@ -186,13 +183,12 @@ typedef FormData_pg_attribute *Form_pg_attribute; #define Anum_pg_attribute_atttypmod 9 #define Anum_pg_attribute_attbyval 10 #define Anum_pg_attribute_attstorage 11 -#define Anum_pg_attribute_attisset 12 -#define Anum_pg_attribute_attalign 13 -#define Anum_pg_attribute_attnotnull 14 -#define Anum_pg_attribute_atthasdef 15 -#define Anum_pg_attribute_attisdropped 16 -#define Anum_pg_attribute_attislocal 17 -#define Anum_pg_attribute_attinhcount 18 +#define Anum_pg_attribute_attalign 12 +#define Anum_pg_attribute_attnotnull 13 +#define Anum_pg_attribute_atthasdef 14 +#define Anum_pg_attribute_attisdropped 15 +#define Anum_pg_attribute_attislocal 16 +#define Anum_pg_attribute_attinhcount 17 @@ -226,278 +222,276 @@ typedef FormData_pg_attribute *Form_pg_attribute; * ---------------- */ #define Schema_pg_type \ -{ 1247, {"typname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typowner"}, 23, -1, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typlen"}, 21, -1, 2, 4, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1247, {"typbyval"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typtype"}, 18, -1, 1, 6, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typisdefined"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typdelim"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typelem"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typinput"}, 24, -1, 4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typanalyze"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typalign"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typstorage"}, 18, -1, 1, 17, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typnotnull"}, 16, -1, 1, 18, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typbasetype"}, 26, -1, 4, 19, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typtypmod"}, 23, -1, 4, 20, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typndims"}, 23, -1, 4, 21, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typdefaultbin"}, 25, -1, -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \ -{ 1247, {"typdefault"}, 25, -1, -1, 23, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 } - - -DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typowner 23 -1 4 3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typlen 21 -1 2 4 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1247 typbyval 16 -1 1 5 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typtype 18 -1 1 6 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typisdefined 16 -1 1 7 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typdelim 18 -1 1 8 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typrelid 26 -1 4 9 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typelem 26 -1 4 10 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typanalyze 24 -1 4 15 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typalign 18 -1 1 16 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typstorage 18 -1 1 17 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typnotnull 16 -1 1 18 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typbasetype 26 -1 4 19 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typtypmod 23 -1 4 20 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typndims 23 -1 4 21 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typdefaultbin 25 -1 -1 22 0 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1247 typdefault 25 -1 -1 23 0 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +{ 1247, {"typname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typowner"}, 23, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typlen"}, 21, -1, 2, 4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1247, {"typbyval"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typtype"}, 18, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typisdefined"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typdelim"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typelem"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typinput"}, 24, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typanalyze"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typalign"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typstorage"}, 18, -1, 1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typnotnull"}, 16, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typbasetype"}, 26, -1, 4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typtypmod"}, 23, -1, 4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typndims"}, 23, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typdefaultbin"}, 25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 1247, {"typdefault"}, 25, -1, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 } + + +DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typowner 23 -1 4 3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typlen 21 -1 2 4 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1247 typbyval 16 -1 1 5 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typtype 18 -1 1 6 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typisdefined 16 -1 1 7 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typdelim 18 -1 1 8 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typelem 26 -1 4 10 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typanalyze 24 -1 4 15 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typalign 18 -1 1 16 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typstorage 18 -1 1 17 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typnotnull 16 -1 1 18 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typbasetype 26 -1 4 19 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typtypmod 23 -1 4 20 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typndims 23 -1 4 21 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typdefaultbin 25 -1 -1 22 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1247 typdefault 25 -1 -1 23 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); +DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_database * ---------------- */ -DATA(insert ( 1262 datname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1262 datdba 23 -1 4 2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 encoding 23 -1 4 3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 datistemplate 16 -1 1 4 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1262 datallowconn 16 -1 1 5 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1262 datlastsysoid 26 -1 4 6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 datvacuumxid 28 -1 4 7 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 datfrozenxid 28 -1 4 8 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1262 datname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1262 datdba 23 -1 4 2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 encoding 23 -1 4 3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 datistemplate 16 -1 1 4 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1262 datallowconn 16 -1 1 5 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1262 datlastsysoid 26 -1 4 6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 datvacuumxid 28 -1 4 7 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 datfrozenxid 28 -1 4 8 0 -1 -1 t p i t f f t 0)); /* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */ -DATA(insert ( 1262 datpath 25 -1 -1 9 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1262 datconfig 1009 -1 -1 10 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1262 datacl 1034 -1 -1 11 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1262 oid 26 0 4 -2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1262 datpath 25 -1 -1 9 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1262 datconfig 1009 -1 -1 10 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1262 datacl 1034 -1 -1 11 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); +DATA(insert ( 1262 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_proc * ---------------- */ #define Schema_pg_proc \ -{ 1255, {"proname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1255, {"pronamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1255, {"proowner"}, 23, -1, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1255, {"prolang"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1255, {"proisagg"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1255, {"prosecdef"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1255, {"proisstrict"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1255, {"proretset"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1255, {"provolatile"}, 18, -1, 1, 9, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1255, {"pronargs"}, 21, -1, 2, 10, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1255, {"prorettype"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1255, {"proargtypes"}, 30, -1, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1255, {"proargnames"}, 1009, -1, -1, 13, 1, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \ -{ 1255, {"prosrc"}, 25, -1, -1, 14, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \ -{ 1255, {"probin"}, 17, -1, -1, 15, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \ -{ 1255, {"proacl"}, 1034, -1, -1, 16, 1, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 } - -DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 proowner 23 -1 4 3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 prolang 26 -1 4 4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 proisagg 16 -1 1 5 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1255 prosecdef 16 -1 1 6 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1255 proisstrict 16 -1 1 7 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1255 proretset 16 -1 1 8 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1255 provolatile 18 -1 1 9 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1255 pronargs 21 -1 2 10 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1255 prorettype 26 -1 4 11 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 proargtypes 30 -1 INDEX_MAX_KEYS*4 12 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1255 proargnames 1009 -1 -1 13 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1255 prosrc 25 -1 -1 14 0 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1255 probin 17 -1 -1 15 0 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1255 proacl 1034 -1 -1 16 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +{ 1255, {"proname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"pronamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"proowner"}, 23, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"prolang"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"proisagg"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1255, {"prosecdef"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1255, {"proisstrict"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1255, {"proretset"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1255, {"provolatile"}, 18, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1255, {"pronargs"}, 21, -1, 2, 10, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1255, {"prorettype"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"proargtypes"}, 30, -1, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"proargnames"}, 1009, -1, -1, 13, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 1255, {"prosrc"}, 25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 1255, {"probin"}, 17, -1, -1, 15, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 1255, {"proacl"}, 1034, -1, -1, 16, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } + +DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 proowner 23 -1 4 3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 prolang 26 -1 4 4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 proisagg 16 -1 1 5 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1255 prosecdef 16 -1 1 6 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1255 proisstrict 16 -1 1 7 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1255 proretset 16 -1 1 8 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1255 provolatile 18 -1 1 9 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1255 pronargs 21 -1 2 10 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1255 prorettype 26 -1 4 11 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 proargtypes 30 -1 INDEX_MAX_KEYS*4 12 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1255 proargnames 1009 -1 -1 13 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1255 prosrc 25 -1 -1 14 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1255 probin 17 -1 -1 15 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1255 proacl 1034 -1 -1 16 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); +DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_shadow * ---------------- */ -DATA(insert ( 1260 usename 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1260 usesysid 23 -1 4 2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1260 usecreatedb 16 -1 1 3 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1260 usesuper 16 -1 1 4 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1260 usecatupd 16 -1 1 5 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1260 passwd 25 -1 -1 6 0 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1260 valuntil 702 -1 4 7 0 -1 -1 t p f i f f f t 0)); -DATA(insert ( 1260 useconfig 1009 -1 -1 8 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1260 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); +DATA(insert ( 1260 usename 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1260 usesysid 23 -1 4 2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1260 usecreatedb 16 -1 1 3 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1260 usesuper 16 -1 1 4 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1260 usecatupd 16 -1 1 5 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1260 passwd 25 -1 -1 6 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1260 valuntil 702 -1 4 7 0 -1 -1 t p i f f f t 0)); +DATA(insert ( 1260 useconfig 1009 -1 -1 8 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1260 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); /* no OIDs in pg_shadow */ -DATA(insert ( 1260 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1260 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1260 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1260 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1260 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1260 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1260 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1260 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1260 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1260 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_group * ---------------- */ -DATA(insert ( 1261 groname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1261 grosysid 23 -1 4 2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1261 grolist 1007 -1 -1 3 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1261 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); +DATA(insert ( 1261 groname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1261 grosysid 23 -1 4 2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1261 grolist 1007 -1 -1 3 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1261 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); /* no OIDs in pg_group */ -DATA(insert ( 1261 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1261 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1261 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1261 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1261 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1261 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1261 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1261 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1261 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1261 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_attribute * ---------------- */ #define Schema_pg_attribute \ -{ 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"atttypid"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"attstattarget"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"attlen"}, 21, -1, 2, 5, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1249, {"attnum"}, 21, -1, 2, 6, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1249, {"attndims"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"attcacheoff"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"atttypmod"}, 23, -1, 4, 9, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1249, {"attbyval"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attstorage"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attisset"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attalign"}, 18, -1, 1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attnotnull"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"atthasdef"}, 16, -1, 1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attisdropped"}, 16, -1, 1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attislocal"}, 16, -1, 1, 17, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1249, {"attinhcount"}, 23, -1, 4, 18, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 } - -DATA(insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1249 atttypid 26 -1 4 3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 attstattarget 23 -1 4 4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 attlen 21 -1 2 5 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1249 attnum 21 -1 2 6 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1249 attndims 23 -1 4 7 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 attcacheoff 23 -1 4 8 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 atttypmod 23 -1 4 9 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 attbyval 16 -1 1 10 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attstorage 18 -1 1 11 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attisset 16 -1 1 12 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attalign 18 -1 1 13 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attnotnull 16 -1 1 14 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 atthasdef 16 -1 1 15 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attisdropped 16 -1 1 16 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attislocal 16 -1 1 17 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1249 attinhcount 23 -1 4 18 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); +{ 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"atttypid"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"attstattarget"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"attlen"}, 21, -1, 2, 5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1249, {"attnum"}, 21, -1, 2, 6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1249, {"attndims"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"attcacheoff"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"atttypmod"}, 23, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1249, {"attbyval"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"attstorage"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"attalign"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"attnotnull"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"atthasdef"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"attisdropped"}, 16, -1, 1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"attislocal"}, 16, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1249, {"attinhcount"}, 23, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 } + +DATA(insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1249 atttypid 26 -1 4 3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 attstattarget 23 -1 4 4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 attlen 21 -1 2 5 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1249 attnum 21 -1 2 6 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1249 attndims 23 -1 4 7 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 attcacheoff 23 -1 4 8 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 atttypmod 23 -1 4 9 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 attbyval 16 -1 1 10 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 attstorage 18 -1 1 11 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 attalign 18 -1 1 12 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 attnotnull 16 -1 1 13 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 atthasdef 16 -1 1 14 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 attisdropped 16 -1 1 15 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 attislocal 16 -1 1 16 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1249 attinhcount 23 -1 4 17 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); /* no OIDs in pg_attribute */ -DATA(insert ( 1249 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1249 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_class * ---------------- */ #define Schema_pg_class \ -{ 1259, {"relname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"relnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"reltype"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"relowner"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"relam"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"relfilenode"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"relpages"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"reltuples"}, 700, -1, 4, 8, 0, -1, -1, false, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"reltoastrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"reltoastidxid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1259, {"relhasindex"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relisshared"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relkind"}, 18, -1, 1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relnatts"}, 21, -1, 2, 14, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1259, {"relchecks"}, 21, -1, 2, 15, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1259, {"reltriggers"}, 21, -1, 2, 16, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1259, {"relukeys"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1259, {"relfkeys"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1259, {"relrefs"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', false, 's', true, false, false, true, 0 }, \ -{ 1259, {"relhasoids"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relhaspkey"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relhasrules"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relhassubclass"},16, -1, 1, 23, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1259, {"relacl"}, 1034, -1, -1, 24, 1, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 } - -DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 reltype 26 -1 4 3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 relowner 23 -1 4 4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 relam 26 -1 4 5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 relfilenode 26 -1 4 6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 relpages 23 -1 4 7 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 reltuples 700 -1 4 8 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1259 reltoastrelid 26 -1 4 9 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 reltoastidxid 26 -1 4 10 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 relhasindex 16 -1 1 11 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relisshared 16 -1 1 12 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relkind 18 -1 1 13 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relnatts 21 -1 2 14 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1259 relchecks 21 -1 2 15 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1259 reltriggers 21 -1 2 16 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1259 relukeys 21 -1 2 17 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1259 relfkeys 21 -1 2 18 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1259 relrefs 21 -1 2 19 0 -1 -1 t p f s t f f t 0)); -DATA(insert ( 1259 relhasoids 16 -1 1 20 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relhaspkey 16 -1 1 21 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relhasrules 16 -1 1 22 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relhassubclass 16 -1 1 23 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1259 relacl 1034 -1 -1 24 1 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); -DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 cmin 29 0 4 -4 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); +{ 1259, {"relname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"relnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"reltype"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"relowner"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"relam"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"relfilenode"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"relpages"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"reltuples"}, 700, -1, 4, 8, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"reltoastrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"reltoastidxid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1259, {"relhasindex"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relisshared"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relkind"}, 18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relnatts"}, 21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1259, {"relchecks"}, 21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1259, {"reltriggers"}, 21, -1, 2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1259, {"relukeys"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1259, {"relfkeys"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1259, {"relrefs"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 1259, {"relhasoids"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relhaspkey"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relhasrules"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relhassubclass"},16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1259, {"relacl"}, 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } + +DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 reltype 26 -1 4 3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 relowner 23 -1 4 4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 relam 26 -1 4 5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 relfilenode 26 -1 4 6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 relpages 23 -1 4 7 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 reltuples 700 -1 4 8 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1259 reltoastrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 reltoastidxid 26 -1 4 10 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 relhasindex 16 -1 1 11 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relisshared 16 -1 1 12 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relkind 18 -1 1 13 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relnatts 21 -1 2 14 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1259 relchecks 21 -1 2 15 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1259 reltriggers 21 -1 2 16 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1259 relukeys 21 -1 2 17 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1259 relfkeys 21 -1 2 18 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1259 relrefs 21 -1 2 19 0 -1 -1 t p s t f f t 0)); +DATA(insert ( 1259 relhasoids 16 -1 1 20 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relhaspkey 16 -1 1 21 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relhasrules 16 -1 1 22 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relhassubclass 16 -1 1 23 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1259 relacl 1034 -1 -1 24 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); +DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_xactlock - this is not a real relation, but is a placeholder @@ -507,6 +501,6 @@ DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f t 0)); * table; and this entry is just to link to that one. * ---------------- */ -DATA(insert ( 376 xactlockfoo 26 0 4 1 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 376 xactlockfoo 26 0 4 1 0 -1 -1 t p i t f f t 0)); #endif /* PG_ATTRIBUTE_H */ diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index eafe5ceb3285641c273afcd2a6a663fb1d7d41fc..8f044b0459ae02408d80018855c1313be9d9b214 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.80 2004/02/12 23:41:04 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.81 2004/04/01 21:28:45 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -136,7 +136,7 @@ typedef FormData_pg_class *Form_pg_class; DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ )); DESCR(""); -DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 18 0 0 0 0 0 f f f f _null_ )); +DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 17 0 0 0 0 0 f f f f _null_ )); DESCR(""); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 16 0 0 0 0 0 t f f f _null_ )); DESCR(""); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 739e1b0da64f73287e006e3be1d65f2ad6f9ae18..7da13b33c9082fd370fc2fbf65255b3f489e2f37 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.322 2004/03/22 01:38:18 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.323 2004/04/01 21:28:45 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -1334,8 +1334,6 @@ DATA(insert OID = 1062 ( aclitemeq PGNSP PGUID 12 f f t f i 2 16 "1033 1033 DESCR("equality operator for ACL items"); DATA(insert OID = 1365 ( makeaclitem PGNSP PGUID 12 f f t f i 5 1033 "23 23 23 25 16" _null_ makeaclitem - _null_ )); DESCR("make ACL item"); -DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" _null_ seteval - _null_ )); -DESCR("internal function supporting PostQuel-style sets"); DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" _null_ bpcharin - _null_ )); DESCR("I/O"); DATA(insert OID = 1045 ( bpcharout PGNSP PGUID 12 f f t f i 1 2275 "1042" _null_ bpcharout - _null_ )); @@ -3155,9 +3153,9 @@ DATA(insert OID = 2273 ( has_schema_privilege PGNSP PGUID 12 f f t f s 2 16 DESCR("current user privilege on schema by schema oid"); -DATA(insert OID = 2290 ( record_in PGNSP PGUID 12 f f t f i 1 2249 "2275" _null_ record_in - _null_ )); +DATA(insert OID = 2290 ( record_in PGNSP PGUID 12 f f t f v 1 2249 "2275" _null_ record_in - _null_ )); DESCR("I/O"); -DATA(insert OID = 2291 ( record_out PGNSP PGUID 12 f f t f i 1 2275 "2249" _null_ record_out - _null_ )); +DATA(insert OID = 2291 ( record_out PGNSP PGUID 12 f f t f v 1 2275 "2249" _null_ record_out - _null_ )); DESCR("I/O"); DATA(insert OID = 2292 ( cstring_in PGNSP PGUID 12 f f t f i 1 2275 "2275" _null_ cstring_in - _null_ )); DESCR("I/O"); @@ -3298,9 +3296,9 @@ DATA(insert OID = 2400 ( array_recv PGNSP PGUID 12 f f t f s 2 2277 "2281 2 DESCR("I/O"); DATA(insert OID = 2401 ( array_send PGNSP PGUID 12 f f t f s 2 17 "2277 26" _null_ array_send - _null_ )); DESCR("I/O"); -DATA(insert OID = 2402 ( record_recv PGNSP PGUID 12 f f t f i 1 2249 "2281" _null_ record_recv - _null_ )); +DATA(insert OID = 2402 ( record_recv PGNSP PGUID 12 f f t f v 1 2249 "2281" _null_ record_recv - _null_ )); DESCR("I/O"); -DATA(insert OID = 2403 ( record_send PGNSP PGUID 12 f f t f i 1 17 "2249" _null_ record_send - _null_ )); +DATA(insert OID = 2403 ( record_send PGNSP PGUID 12 f f t f v 1 17 "2249" _null_ record_send - _null_ )); DESCR("I/O"); DATA(insert OID = 2404 ( int2recv PGNSP PGUID 12 f f t f i 1 21 "2281" _null_ int2recv - _null_ )); DESCR("I/O"); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 8cbc0aa8e67a5ddb1a00e6d645ddb678d684c253..9f68e22fdb8064e301496a46c3c5be77b88cf283 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.151 2004/03/19 18:58:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.152 2004/04/01 21:28:45 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -268,7 +268,7 @@ DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b t \054 0 0 int2in int2out int2 DESCR("-32 thousand to 32 thousand, 2-byte storage"); #define INT2OID 21 -DATA(insert OID = 22 ( int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 22 ( int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - s p f 0 -1 0 _null_ _null_ )); DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables"); #define INT2VECTOROID 22 @@ -288,7 +288,7 @@ DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b t \054 0 0 oidin oidout oidrec DESCR("object identifier(oid), maximum 4 billion"); #define OIDOID 26 -DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b t \054 0 0 tidin tidout tidrecv tidsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b t \054 0 0 tidin tidout tidrecv tidsend - s p f 0 -1 0 _null_ _null_ )); DESCR("(Block, offset), physical location of tuple"); #define TIDOID 27 @@ -307,13 +307,13 @@ DESCR("array of INDEX_MAX_KEYS oids, used in system tables"); DATA(insert OID = 32 ( SET PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout - - - i p f 0 -1 0 _null_ _null_ )); DESCR("set of tuples"); -DATA(insert OID = 71 ( pg_type PGNSP PGUID 4 t c t \054 1247 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 75 ( pg_attribute PGNSP PGUID 4 t c t \054 1249 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 81 ( pg_proc PGNSP PGUID 4 t c t \054 1255 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 83 ( pg_class PGNSP PGUID 4 t c t \054 1259 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 86 ( pg_shadow PGNSP PGUID 4 t c t \054 1260 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 87 ( pg_group PGNSP PGUID 4 t c t \054 1261 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 88 ( pg_database PGNSP PGUID 4 t c t \054 1262 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c t \054 1247 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c t \054 1249 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c t \054 1255 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c t \054 1259 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 86 ( pg_shadow PGNSP PGUID -1 f c t \054 1260 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 87 ( pg_group PGNSP PGUID -1 f c t \054 1261 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 88 ( pg_database PGNSP PGUID -1 f c t \054 1262 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); /* OIDS 100 - 199 */ @@ -526,7 +526,7 @@ DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in a * argument and result types (if supported by the function's implementation * language). */ -DATA(insert OID = 2249 ( record PGNSP PGUID 4 t p t \054 0 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p t \054 0 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); #define RECORDOID 2249 DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out cstring_recv cstring_send - c p f 0 -1 0 _null_ _null_ )); #define CSTRINGOID 2275 diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 1eb158440b1c11680ee856e020efbea1f523c864..a3088ca7f628483ff645d73daf7669a4ddcca9af 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.108 2004/03/17 01:02:24 tgl Exp $ + * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.109 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -120,9 +120,9 @@ extern void ExecEndNode(PlanState *node); /* * prototypes from functions in execQual.c */ -extern Datum GetAttributeByNum(TupleTableSlot *slot, AttrNumber attrno, +extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, bool *isNull); -extern Datum GetAttributeByName(TupleTableSlot *slot, char *attname, +extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull); extern void init_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt); diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index ac2b494b53231fa3d2a561c650ce426396784730..2e477e70f87c2c6953dab682396f37526ab4e981 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -2,7 +2,7 @@ * * spi.h * - * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.43 2004/03/17 01:05:10 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.44 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -95,9 +95,7 @@ extern int SPI_getargcount(void *plan); extern bool SPI_is_cursor_plan(void *plan); extern HeapTuple SPI_copytuple(HeapTuple tuple); -extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc); -extern TupleTableSlot *SPI_copytupleintoslot(HeapTuple tuple, - TupleDesc tupdesc); +extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc); extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, Datum *Values, const char *Nulls); extern int SPI_fnumber(TupleDesc tupdesc, const char *fname); diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 6ed389e8f95acc8aa742bf2e7b40e43b2964e8b7..acdcb4ff4754a47324a72938c57899e0eff6fa26 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.33 2004/01/19 02:06:42 tgl Exp $ + * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.34 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -192,11 +192,13 @@ extern struct varlena *pg_detoast_datum_slice(struct varlena * datum, #define DatumGetTextP(X) ((text *) PG_DETOAST_DATUM(X)) #define DatumGetBpCharP(X) ((BpChar *) PG_DETOAST_DATUM(X)) #define DatumGetVarCharP(X) ((VarChar *) PG_DETOAST_DATUM(X)) +#define DatumGetHeapTupleHeader(X) ((HeapTupleHeader) PG_DETOAST_DATUM(X)) /* And we also offer variants that return an OK-to-write copy */ #define DatumGetByteaPCopy(X) ((bytea *) PG_DETOAST_DATUM_COPY(X)) #define DatumGetTextPCopy(X) ((text *) PG_DETOAST_DATUM_COPY(X)) #define DatumGetBpCharPCopy(X) ((BpChar *) PG_DETOAST_DATUM_COPY(X)) #define DatumGetVarCharPCopy(X) ((VarChar *) PG_DETOAST_DATUM_COPY(X)) +#define DatumGetHeapTupleHeaderCopy(X) ((HeapTupleHeader) PG_DETOAST_DATUM_COPY(X)) /* Variants which return n bytes starting at pos. m */ #define DatumGetByteaPSlice(X,m,n) ((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n)) #define DatumGetTextPSlice(X,m,n) ((text *) PG_DETOAST_DATUM_SLICE(X,m,n)) @@ -207,11 +209,13 @@ extern struct varlena *pg_detoast_datum_slice(struct varlena * datum, #define PG_GETARG_TEXT_P(n) DatumGetTextP(PG_GETARG_DATUM(n)) #define PG_GETARG_BPCHAR_P(n) DatumGetBpCharP(PG_GETARG_DATUM(n)) #define PG_GETARG_VARCHAR_P(n) DatumGetVarCharP(PG_GETARG_DATUM(n)) +#define PG_GETARG_HEAPTUPLEHEADER(n) DatumGetHeapTupleHeader(PG_GETARG_DATUM(n)) /* And we also offer variants that return an OK-to-write copy */ #define PG_GETARG_BYTEA_P_COPY(n) DatumGetByteaPCopy(PG_GETARG_DATUM(n)) #define PG_GETARG_TEXT_P_COPY(n) DatumGetTextPCopy(PG_GETARG_DATUM(n)) #define PG_GETARG_BPCHAR_P_COPY(n) DatumGetBpCharPCopy(PG_GETARG_DATUM(n)) #define PG_GETARG_VARCHAR_P_COPY(n) DatumGetVarCharPCopy(PG_GETARG_DATUM(n)) +#define PG_GETARG_HEAPTUPLEHEADER_COPY(n) DatumGetHeapTupleHeaderCopy(PG_GETARG_DATUM(n)) /* And a b-byte slice from position a -also OK to write */ #define PG_GETARG_BYTEA_P_SLICE(n,a,b) DatumGetByteaPSlice(PG_GETARG_DATUM(n),a,b) #define PG_GETARG_TEXT_P_SLICE(n,a,b) DatumGetTextPSlice(PG_GETARG_DATUM(n),a,b) @@ -246,6 +250,7 @@ extern struct varlena *pg_detoast_datum_slice(struct varlena * datum, #define PG_RETURN_TEXT_P(x) PG_RETURN_POINTER(x) #define PG_RETURN_BPCHAR_P(x) PG_RETURN_POINTER(x) #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x) +#define PG_RETURN_HEAPTUPLEHEADER(x) PG_RETURN_POINTER(x) /*------------------------------------------------------------------------- diff --git a/src/include/funcapi.h b/src/include/funcapi.h index a8051fc27f0399a43da930768b463578bc88e113..fd1660423e1eb1a06933170ef8afde82540ceaee 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -9,7 +9,7 @@ * * Copyright (c) 2002-2003, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/funcapi.h,v 1.10 2003/11/29 22:40:53 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/funcapi.h,v 1.11 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -57,7 +57,7 @@ typedef struct AttInMetadata typedef struct FuncCallContext { /* - * Number of times we've been called before. + * Number of times we've been called before * * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and * incremented for you every time SRF_RETURN_NEXT() is called. @@ -67,7 +67,7 @@ typedef struct FuncCallContext /* * OPTIONAL maximum number of calls * - * max_calls is here for convenience ONLY and setting it is OPTIONAL. If + * max_calls is here for convenience only and setting it is optional. If * not set, you must provide alternative means to know when the * function is done. */ @@ -76,41 +76,50 @@ typedef struct FuncCallContext /* * OPTIONAL pointer to result slot * - * slot is for use when returning tuples (i.e. composite data types) and - * is not needed when returning base (i.e. scalar) data types. + * This is obsolete and only present for backwards compatibility, viz, + * user-defined SRFs that use the deprecated TupleDescGetSlot(). */ TupleTableSlot *slot; /* - * OPTIONAL pointer to misc user provided context info + * OPTIONAL pointer to miscellaneous user-provided context information * * user_fctx is for use as a pointer to your own struct to retain - * arbitrary context information between calls for your function. + * arbitrary context information between calls of your function. */ void *user_fctx; /* - * OPTIONAL pointer to struct containing arrays of attribute type - * input metainfo + * OPTIONAL pointer to struct containing attribute type input metadata * * attinmeta is for use when returning tuples (i.e. composite data types) - * and is not needed when returning base (i.e. scalar) data types. It - * is ONLY needed if you intend to use BuildTupleFromCStrings() to - * create the return tuple. + * and is not used when returning base data types. It is only needed + * if you intend to use BuildTupleFromCStrings() to create the return + * tuple. */ AttInMetadata *attinmeta; /* - * memory context used for structures which must live for multiple - * calls + * memory context used for structures that must live for multiple calls * * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory - * context for any memory that is to be re-used across multiple calls + * context for any memory that is to be reused across multiple calls * of the SRF. */ MemoryContext multi_call_memory_ctx; + /* + * OPTIONAL pointer to struct containing tuple description + * + * tuple_desc is for use when returning tuples (i.e. composite data types) + * and is only needed if you are going to build the tuples with + * heap_formtuple() rather than with BuildTupleFromCStrings(). Note that + * the TupleDesc pointer stored here should usually have been run through + * BlessTupleDesc() first. + */ + TupleDesc tuple_desc; + } FuncCallContext; /*---------- @@ -122,38 +131,43 @@ typedef struct FuncCallContext * TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) - Use to get a * TupleDesc based on a type OID. This can be used to get * a TupleDesc for a base (scalar) or composite (relation) type. - * TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc) - Initialize a slot - * given a TupleDesc. + * TupleDesc BlessTupleDesc(TupleDesc tupdesc) - "Bless" a completed tuple + * descriptor so that it can be used to return properly labeled tuples. + * You need to call this if you are going to use heap_formtuple directly. + * TupleDescGetAttInMetadata does it for you, however, so no need to call + * it if you call TupleDescGetAttInMetadata. * AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) - Build an * AttInMetadata struct based on the given TupleDesc. AttInMetadata can * be used in conjunction with C strings to produce a properly formed - * tuple. Store the metadata here for use across calls to avoid redundant - * work. + * tuple. * HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) - * build a HeapTuple given user data in C string form. values is an array * of C strings, one for each attribute of the return tuple. * * Macro declarations: + * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum. + * + * Obsolete routines and macros: + * TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc) - Builds a + * TupleTableSlot, which is not needed anymore. * TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple) - get a Datum * given a tuple and a slot. *---------- */ +#define HeapTupleGetDatum(_tuple) PointerGetDatum((_tuple)->t_data) +/* obsolete version of above */ +#define TupleGetDatum(_slot, _tuple) PointerGetDatum((_tuple)->t_data) + /* from tupdesc.c */ extern TupleDesc RelationNameGetTupleDesc(const char *relname); extern TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases); /* from execTuples.c */ -extern TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc); +extern TupleDesc BlessTupleDesc(TupleDesc tupdesc); extern AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc); extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values); - -/* - * Note we pass shouldFree = false; this is needed because the tuple will - * typically be in a shorter-lived memory context than the TupleTableSlot. - */ -#define TupleGetDatum(_slot, _tuple) \ - PointerGetDatum(ExecStoreTuple(_tuple, _slot, InvalidBuffer, false)) +extern TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc); /*---------- @@ -176,8 +190,7 @@ extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) * oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); * <user defined code> * <if returning composite> - * <obtain slot> - * funcctx->slot = slot; + * <build TupleDesc, and perhaps AttInMetaData> * <endif returning composite> * <user defined code> * // return to original context when allocating transient memory diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 440fcc4d576d7035b982e3c9114edb84e3acf8b6..8a0fbf7be0f38473edd2c16d92bfee615a906f6c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.114 2004/03/17 20:48:42 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.115 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -563,6 +563,17 @@ typedef struct SubPlanState FmgrInfo *hashfunctions; /* lookup data for hash functions */ } SubPlanState; +/* ---------------- + * FieldSelectState node + * ---------------- + */ +typedef struct FieldSelectState +{ + ExprState xprstate; + ExprState *arg; /* input expression */ + TupleDesc argdesc; /* tupdesc for most recent input */ +} FieldSelectState; + /* ---------------- * CaseExprState node * ---------------- diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 5c34b8d8559a3042790b3b3107bf9e141a99c4ea..d5d4f0832a7b8e157fbe5ab2fb1924f513415ab2 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.151 2004/03/17 20:48:43 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.152 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -141,6 +141,7 @@ typedef enum NodeTag T_ScalarArrayOpExprState, T_BoolExprState, T_SubPlanState, + T_FieldSelectState, T_CaseExprState, T_CaseWhenState, T_ArrayExprState, diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index d94196d740069b2507e083147ec9f6eee58808d6..567310fa1c3bae831fdb1c338ac71484bcc7eb13 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.96 2004/03/17 20:48:43 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.97 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -525,9 +525,8 @@ typedef struct SubPlan * FieldSelect * * FieldSelect represents the operation of extracting one field from a tuple - * value. At runtime, the input expression is expected to yield a Datum - * that contains a pointer-to-TupleTableSlot. The specified field number - * is extracted and returned as a Datum. + * value. At runtime, the input expression is expected to yield a rowtype + * Datum. The specified field number is extracted and returned as a Datum. * ---------------- */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index b7c1f5fea7741d270a4a3d3cfa533b2ea46f0204..02e6cbca49d814072c598952548ef3f4fb1207f1 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.235 2004/03/15 03:29:22 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.236 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -384,10 +384,6 @@ extern Datum oidvectorge(PG_FUNCTION_ARGS); extern Datum oidvectorgt(PG_FUNCTION_ARGS); /* pseudotypes.c */ -extern Datum record_in(PG_FUNCTION_ARGS); -extern Datum record_out(PG_FUNCTION_ARGS); -extern Datum record_recv(PG_FUNCTION_ARGS); -extern Datum record_send(PG_FUNCTION_ARGS); extern Datum cstring_in(PG_FUNCTION_ARGS); extern Datum cstring_out(PG_FUNCTION_ARGS); extern Datum cstring_recv(PG_FUNCTION_ARGS); @@ -452,6 +448,12 @@ extern List *stringToQualifiedNameList(const char *string, const char *caller); extern char *format_procedure(Oid procedure_oid); extern char *format_operator(Oid operator_oid); +/* rowtypes.c */ +extern Datum record_in(PG_FUNCTION_ARGS); +extern Datum record_out(PG_FUNCTION_ARGS); +extern Datum record_recv(PG_FUNCTION_ARGS); +extern Datum record_send(PG_FUNCTION_ARGS); + /* ruleutils.c */ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); extern Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS); diff --git a/src/include/utils/sets.h b/src/include/utils/sets.h deleted file mode 100644 index 82350f2806acde4a590bc2ae97ca39d602b1c5c8..0000000000000000000000000000000000000000 --- a/src/include/utils/sets.h +++ /dev/null @@ -1,27 +0,0 @@ -/*------------------------------------------------------------------------- - * - * sets.h - * - * - * - * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * $PostgreSQL: pgsql/src/include/utils/sets.h,v 1.16 2003/11/29 22:41:16 pgsql Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef SETS_H -#define SETS_H - -#include "fmgr.h" - - -/* Temporary name of a set function, before SetDefine changes it. */ -#define GENERICSETNAME "ZYX#Set#ZYX" - -extern Oid SetDefine(char *querystr, Oid elemType); - -extern Datum seteval(PG_FUNCTION_ARGS); - -#endif /* SETS_H */ diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h index 93f3f163c46ef5701d8706e1d2a273ba4fda710d..8b85f51700024b7eb84cc0aa9f2cec2371a873ac 100644 --- a/src/include/utils/typcache.h +++ b/src/include/utils/typcache.h @@ -9,13 +9,14 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/typcache.h,v 1.2 2003/11/29 22:41:16 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/utils/typcache.h,v 1.3 2004/04/01 21:28:46 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef TYPCACHE_H #define TYPCACHE_H +#include "access/tupdesc.h" #include "fmgr.h" @@ -28,6 +29,8 @@ typedef struct TypeCacheEntry int16 typlen; bool typbyval; char typalign; + char typtype; + Oid typrelid; /* * Information obtained from opclass entries @@ -51,6 +54,13 @@ typedef struct TypeCacheEntry */ FmgrInfo eq_opr_finfo; FmgrInfo cmp_proc_finfo; + + /* + * Tuple descriptor if it's a composite type (row type). NULL if not + * composite or information hasn't yet been requested. (NOTE: this + * is actually just a link to information maintained by relcache.c.) + */ + TupleDesc tupDesc; } TypeCacheEntry; /* Bit flags to indicate which fields a given caller needs to have set */ @@ -60,7 +70,14 @@ typedef struct TypeCacheEntry #define TYPECACHE_CMP_PROC 0x0008 #define TYPECACHE_EQ_OPR_FINFO 0x0010 #define TYPECACHE_CMP_PROC_FINFO 0x0020 +#define TYPECACHE_TUPDESC 0x0040 extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags); +extern TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod); + +extern void assign_record_type_typmod(TupleDesc tupDesc); + +extern void flush_rowtype_cache(Oid type_id); + #endif /* TYPCACHE_H */ diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index f7b690f71cef3381dbd7a2390a38fdde10b5eccd..8c3680ae19cced6ff5a1c17bfe0fbbd889cfd268 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -33,7 +33,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.42 2004/01/06 23:55:19 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.43 2004/04/01 21:28:46 tgl Exp $ * **********************************************************************/ @@ -45,15 +45,16 @@ #include <setjmp.h> /* postgreSQL stuff */ -#include "executor/spi.h" -#include "commands/trigger.h" -#include "fmgr.h" #include "access/heapam.h" -#include "tcop/tcopprot.h" -#include "utils/syscache.h" #include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "commands/trigger.h" +#include "executor/spi.h" +#include "fmgr.h" +#include "tcop/tcopprot.h" +#include "utils/syscache.h" +#include "utils/typcache.h" /* perl stuff */ #include "EXTERN.h" @@ -82,7 +83,7 @@ typedef struct plperl_proc_desc int nargs; FmgrInfo arg_out_func[FUNC_MAX_ARGS]; Oid arg_out_elem[FUNC_MAX_ARGS]; - int arg_is_rel[FUNC_MAX_ARGS]; + bool arg_is_rowtype[FUNC_MAX_ARGS]; SV *reference; } plperl_proc_desc; @@ -388,19 +389,34 @@ plperl_call_perl_func(plperl_proc_desc * desc, FunctionCallInfo fcinfo) PUSHMARK(SP); for (i = 0; i < desc->nargs; i++) { - if (desc->arg_is_rel[i]) + if (desc->arg_is_rowtype[i]) { - TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i]; - SV *hashref; - - Assert(slot != NULL && !fcinfo->argnull[i]); - - /* - * plperl_build_tuple_argument better return a mortal SV. - */ - hashref = plperl_build_tuple_argument(slot->val, - slot->ttc_tupleDescriptor); - XPUSHs(hashref); + if (fcinfo->argnull[i]) + XPUSHs(&PL_sv_undef); + else + { + HeapTupleHeader td; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + SV *hashref; + + td = DatumGetHeapTupleHeader(fcinfo->arg[i]); + /* Extract rowtype info and find a tupdesc */ + tupType = HeapTupleHeaderGetTypeId(td); + tupTypmod = HeapTupleHeaderGetTypMod(td); + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + /* Build a temporary HeapTuple control structure */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(td); + tmptup.t_data = td; + + /* + * plperl_build_tuple_argument better return a mortal SV. + */ + hashref = plperl_build_tuple_argument(&tmptup, tupdesc); + XPUSHs(hashref); + } } else { @@ -645,7 +661,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) } } - if (typeStruct->typrelid != InvalidOid) + if (typeStruct->typtype == 'c') { free(prodesc->proname); free(prodesc); @@ -692,13 +708,16 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) format_type_be(procStruct->proargtypes[i])))); } - if (typeStruct->typrelid != InvalidOid) - prodesc->arg_is_rel[i] = 1; + if (typeStruct->typtype == 'c') + prodesc->arg_is_rowtype[i] = true; else - prodesc->arg_is_rel[i] = 0; + { + prodesc->arg_is_rowtype[i] = false; + perm_fmgr_info(typeStruct->typoutput, + &(prodesc->arg_out_func[i])); + prodesc->arg_out_elem[i] = typeStruct->typelem; + } - perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i])); - prodesc->arg_out_elem[i] = typeStruct->typelem; ReleaseSysCache(typeTup); } } diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index b984f0932bbf55a5a459eaaf1e42d30d937651b7..b71a71bbaac23e42a11a5622610adba87920353a 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.98 2004/03/17 20:48:43 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.99 2004/04/01 21:28:46 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -52,6 +52,7 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/typcache.h" static const char *const raise_skip_msg = "RAISE"; @@ -258,16 +259,26 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo) case PLPGSQL_DTYPE_ROW: { PLpgSQL_row *row = (PLpgSQL_row *) estate.datums[n]; - TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i]; - HeapTuple tup; - TupleDesc tupdesc; if (!fcinfo->argnull[i]) { - Assert(slot != NULL); - tup = slot->val; - tupdesc = slot->ttc_tupleDescriptor; - exec_move_row(&estate, NULL, row, tup, tupdesc); + HeapTupleHeader td; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + + td = DatumGetHeapTupleHeader(fcinfo->arg[i]); + /* Extract rowtype info and find a tupdesc */ + tupType = HeapTupleHeaderGetTypeId(td); + tupTypmod = HeapTupleHeaderGetTypMod(td); + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + /* Build a temporary HeapTuple control structure */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(td); + ItemPointerSetInvalid(&(tmptup.t_self)); + tmptup.t_tableOid = InvalidOid; + tmptup.t_data = td; + exec_move_row(&estate, NULL, row, &tmptup, tupdesc); } else { @@ -371,11 +382,10 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo) { if (estate.retistuple) { - /* Copy tuple to upper executor memory */ - /* Here we need to return a TupleTableSlot not just a tuple */ - estate.retval = (Datum) - SPI_copytupleintoslot((HeapTuple) (estate.retval), - estate.rettupdesc); + /* Copy tuple to upper executor memory, as a tuple Datum */ + estate.retval = + PointerGetDatum(SPI_returntuple((HeapTuple) (estate.retval), + estate.rettupdesc)); } else { diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index 0da1399d836cd2089c2c979c13a560007a2cd6ec..010f1e1645ec541261e5be0dee406e175c26732c 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -29,26 +29,19 @@ * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.45 2004/01/07 18:56:30 neilc Exp $ + * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.46 2004/04/01 21:28:46 tgl Exp $ * ********************************************************************* */ #include "postgres.h" -/* system stuff - */ -#include <dlfcn.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> +/* system stuff */ #include <unistd.h> #include <fcntl.h> -#include <string.h> #include <setjmp.h> -/* postgreSQL stuff - */ +/* postgreSQL stuff */ #include "access/heapam.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" @@ -59,6 +52,7 @@ #include "parser/parse_type.h" #include "tcop/tcopprot.h" #include "utils/syscache.h" +#include "utils/typcache.h" #include <Python.h> #include <compile.h> @@ -121,7 +115,14 @@ typedef struct PLyTypeInfo { PLyTypeInput in; PLyTypeOutput out; - int is_rel; + int is_rowtype; + /* + * is_rowtype can be: + * -1 not known yet (initial state) + * 0 scalar datatype + * 1 rowtype + * 2 rowtype, but I/O functions not set up yet + */ } PLyTypeInfo; @@ -916,16 +917,40 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc) args = PyList_New(proc->nargs); for (i = 0; i < proc->nargs; i++) { - if (proc->args[i].is_rel == 1) + if (proc->args[i].is_rowtype > 0) { - TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i]; - - arg = PLyDict_FromTuple(&(proc->args[i]), slot->val, - slot->ttc_tupleDescriptor); + if (fcinfo->argnull[i]) + arg = NULL; + else + { + HeapTupleHeader td; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + + td = DatumGetHeapTupleHeader(fcinfo->arg[i]); + /* Extract rowtype info and find a tupdesc */ + tupType = HeapTupleHeaderGetTypeId(td); + tupTypmod = HeapTupleHeaderGetTypMod(td); + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + + /* Set up I/O funcs if not done yet */ + if (proc->args[i].is_rowtype != 1) + PLy_input_tuple_funcs(&(proc->args[i]), tupdesc); + + /* Build a temporary HeapTuple control structure */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(td); + tmptup.t_data = td; + + arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc); + } } else { - if (!fcinfo->argnull[i]) + if (fcinfo->argnull[i]) + arg = NULL; + else { char *ct; Datum dt; @@ -938,8 +963,6 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc) arg = (proc->args[i].in.d.func) (ct); pfree(ct); } - else - arg = NULL; } if (arg == NULL) @@ -1096,7 +1119,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid, procStruct->prorettype); rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup); - if (rvTypeStruct->typrelid == InvalidOid) + if (rvTypeStruct->typtype != 'c') PLy_output_datum_func(&proc->result, rvTypeStruct); else ereport(ERROR, @@ -1135,17 +1158,12 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid, procStruct->proargtypes[i]); argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); - if (argTypeStruct->typrelid == InvalidOid) + if (argTypeStruct->typtype != 'c') PLy_input_datum_func(&(proc->args[i]), procStruct->proargtypes[i], argTypeStruct); else - { - TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i]; - - PLy_input_tuple_funcs(&(proc->args[i]), - slot->ttc_tupleDescriptor); - } + proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */ ReleaseSysCache(argTypeTup); } @@ -1279,7 +1297,7 @@ PLy_procedure_delete(PLyProcedure * proc) if (proc->pyname) PLy_free(proc->pyname); for (i = 0; i < proc->nargs; i++) - if (proc->args[i].is_rel == 1) + if (proc->args[i].is_rowtype == 1) { if (proc->args[i].in.r.atts) PLy_free(proc->args[i].in.r.atts); @@ -1300,10 +1318,10 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc) enter(); - if (arg->is_rel == 0) + if (arg->is_rowtype == 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Datum"); - arg->is_rel = 1; + arg->is_rowtype = 1; arg->in.r.natts = desc->natts; arg->in.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb)); @@ -1338,10 +1356,10 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc) enter(); - if (arg->is_rel == 0) + if (arg->is_rowtype == 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Datum"); - arg->is_rel = 1; + arg->is_rowtype = 1; arg->out.r.natts = desc->natts; arg->out.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb)); @@ -1372,9 +1390,9 @@ PLy_output_datum_func(PLyTypeInfo * arg, Form_pg_type typeStruct) { enter(); - if (arg->is_rel == 1) + if (arg->is_rowtype > 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple"); - arg->is_rel = 0; + arg->is_rowtype = 0; PLy_output_datum_func2(&(arg->out.d), typeStruct); } @@ -1393,9 +1411,9 @@ PLy_input_datum_func(PLyTypeInfo * arg, Oid typeOid, Form_pg_type typeStruct) { enter(); - if (arg->is_rel == 1) + if (arg->is_rowtype > 0) elog(ERROR, "PLyTypeInfo struct is initialized for Tuple"); - arg->is_rel = 0; + arg->is_rowtype = 0; PLy_input_datum_func2(&(arg->in.d), typeOid, typeStruct); } @@ -1434,7 +1452,7 @@ PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, Form_pg_type typeStruct) void PLy_typeinfo_init(PLyTypeInfo * arg) { - arg->is_rel = -1; + arg->is_rowtype = -1; arg->in.r.natts = arg->out.r.natts = 0; arg->in.r.atts = NULL; arg->out.r.atts = NULL; @@ -1443,7 +1461,7 @@ PLy_typeinfo_init(PLyTypeInfo * arg) void PLy_typeinfo_dealloc(PLyTypeInfo * arg) { - if (arg->is_rel == 1) + if (arg->is_rowtype == 1) { if (arg->in.r.atts) PLy_free(arg->in.r.atts); @@ -1515,7 +1533,7 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc) enter(); - if (info->is_rel != 1) + if (info->is_rowtype != 1) elog(ERROR, "PLyTypeInfo structure describes a datum"); dict = PyDict_New(); @@ -2009,7 +2027,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args) plan->types[i] = HeapTupleGetOid(typeTup); typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - if (typeStruct->typrelid == InvalidOid) + if (typeStruct->typtype != 'c') PLy_output_datum_func(&plan->args[i], typeStruct); else { diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 37e515ff66b590e42891d19a7689a354302c9058..d9382aff83bd73ca423edd2f756075dce333f8fd 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -31,7 +31,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.82 2004/01/24 23:06:29 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.83 2004/04/01 21:28:46 tgl Exp $ * **********************************************************************/ @@ -60,6 +60,8 @@ #include "tcop/tcopprot.h" #include "utils/builtins.h" #include "utils/syscache.h" +#include "utils/typcache.h" + #if defined(UNICODE_CONVERSION) && TCL_MAJOR_VERSION == 8 \ && TCL_MINOR_VERSION > 0 @@ -107,7 +109,7 @@ typedef struct pltcl_proc_desc int nargs; FmgrInfo arg_out_func[FUNC_MAX_ARGS]; Oid arg_out_elem[FUNC_MAX_ARGS]; - int arg_is_rel[FUNC_MAX_ARGS]; + bool arg_is_rowtype[FUNC_MAX_ARGS]; } pltcl_proc_desc; @@ -497,21 +499,35 @@ pltcl_func_handler(PG_FUNCTION_ARGS) ************************************************************/ for (i = 0; i < prodesc->nargs; i++) { - if (prodesc->arg_is_rel[i]) + if (prodesc->arg_is_rowtype[i]) { /************************************************** * For tuple values, add a list for 'array set ...' **************************************************/ - TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i]; - - Assert(slot != NULL && !fcinfo->argnull[i]); - Tcl_DStringInit(&list_tmp); - pltcl_build_tuple_argument(slot->val, - slot->ttc_tupleDescriptor, - &list_tmp); - Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&list_tmp)); - Tcl_DStringFree(&list_tmp); - Tcl_DStringInit(&list_tmp); + if (fcinfo->argnull[i]) + Tcl_DStringAppendElement(&tcl_cmd, ""); + else + { + HeapTupleHeader td; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + + td = DatumGetHeapTupleHeader(fcinfo->arg[i]); + /* Extract rowtype info and find a tupdesc */ + tupType = HeapTupleHeaderGetTypeId(td); + tupTypmod = HeapTupleHeaderGetTypMod(td); + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + /* Build a temporary HeapTuple control structure */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(td); + tmptup.t_data = td; + + Tcl_DStringSetLength(&list_tmp, 0); + pltcl_build_tuple_argument(&tmptup, tupdesc, &list_tmp); + Tcl_DStringAppendElement(&tcl_cmd, + Tcl_DStringValue(&list_tmp)); + } } else { @@ -1041,11 +1057,11 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid) Form_pg_type typeStruct; Tcl_DString proc_internal_def; Tcl_DString proc_internal_body; - char proc_internal_args[4096]; + char proc_internal_args[33 * FUNC_MAX_ARGS]; Datum prosrcdatum; bool isnull; char *proc_source; - char buf[512]; + char buf[32]; /************************************************************ * Allocate a new procedure description block @@ -1124,7 +1140,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid) } } - if (typeStruct->typrelid != InvalidOid) + if (typeStruct->typtype == 'c') { free(prodesc->proname); free(prodesc); @@ -1172,25 +1188,22 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid) format_type_be(procStruct->proargtypes[i])))); } - if (typeStruct->typrelid != InvalidOid) + if (typeStruct->typtype == 'c') { - prodesc->arg_is_rel[i] = 1; - if (i > 0) - strcat(proc_internal_args, " "); + prodesc->arg_is_rowtype[i] = true; snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1); - strcat(proc_internal_args, buf); - ReleaseSysCache(typeTup); - continue; } else - prodesc->arg_is_rel[i] = 0; - - perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i])); - prodesc->arg_out_elem[i] = typeStruct->typelem; + { + prodesc->arg_is_rowtype[i] = false; + perm_fmgr_info(typeStruct->typoutput, + &(prodesc->arg_out_func[i])); + prodesc->arg_out_elem[i] = typeStruct->typelem; + snprintf(buf, sizeof(buf), "%d", i + 1); + } if (i > 0) strcat(proc_internal_args, " "); - snprintf(buf, sizeof(buf), "%d", i + 1); strcat(proc_internal_args, buf); ReleaseSysCache(typeTup); @@ -1225,11 +1238,13 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid) { for (i = 0; i < prodesc->nargs; i++) { - if (!prodesc->arg_is_rel[i]) - continue; - snprintf(buf, sizeof(buf), "array set %d $__PLTcl_Tup_%d\n", - i + 1, i + 1); - Tcl_DStringAppend(&proc_internal_body, buf, -1); + if (prodesc->arg_is_rowtype[i]) + { + snprintf(buf, sizeof(buf), + "array set %d $__PLTcl_Tup_%d\n", + i + 1, i + 1); + Tcl_DStringAppend(&proc_internal_body, buf, -1); + } } } else diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source index c10f73c5c657d732977674bd54f429af49c25166..ebf13626c7fabf3f74deb4696e19218cad48af13 100644 --- a/src/test/regress/input/misc.source +++ b/src/test/regress/input/misc.source @@ -212,10 +212,12 @@ SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p; SELECT user_relns() AS user_relns ORDER BY user_relns; ---SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name; +SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); SELECT hobbies_by_name('basketball'); +SELECT name, overpaid(emp.*) FROM emp; + -- -- check that old-style C functions work properly with TOASTed values -- diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source index c478dd71897478f69a07400f216369dd297b1683..3173f718c6c8268a141055801efde138d0c1ec95 100644 --- a/src/test/regress/output/misc.source +++ b/src/test/regress/output/misc.source @@ -663,13 +663,29 @@ SELECT user_relns() AS user_relns xacttest (97 rows) ---SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name; +SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); + name +------ + guts +(1 row) + SELECT hobbies_by_name('basketball'); hobbies_by_name ----------------- joe (1 row) +SELECT name, overpaid(emp.*) FROM emp; + name | overpaid +--------+---------- + sharon | t + sam | t + bill | t + jeff | f + cim | f + linda | f +(6 rows) + -- -- check that old-style C functions work properly with TOASTed values -- diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index b26eed5b371463feffbaf3fc8afc35a05b646c3f..31210a8e0d94c765d0e13c8e690a448c7a26b970 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.59 2003/11/29 19:52:14 pgsql Exp $ + * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.60 2004/04/01 21:28:47 tgl Exp $ */ #include "postgres.h" @@ -15,8 +15,6 @@ #define RDELIM ')' #define DELIM ',' -typedef TupleTableSlot *TUPLE; - extern Datum regress_dist_ptpath(PG_FUNCTION_ARGS); extern Datum regress_path_dist(PG_FUNCTION_ARGS); extern PATH *poly2path(POLYGON *poly); @@ -196,7 +194,7 @@ PG_FUNCTION_INFO_V1(overpaid); Datum overpaid(PG_FUNCTION_ARGS) { - TUPLE tuple = (TUPLE) PG_GETARG_POINTER(0); + HeapTupleHeader tuple = PG_GETARG_HEAPTUPLEHEADER(0); bool isnull; int32 salary; diff --git a/src/tutorial/funcs.c b/src/tutorial/funcs.c index d2c123a0094be295d2f8986cdca0d1ece2a8edae..5e8ad6ee7074f6e06153125d43ebf0f8c9aa8212 100644 --- a/src/tutorial/funcs.c +++ b/src/tutorial/funcs.c @@ -22,7 +22,7 @@ float8 *add_one_float8(float8 *arg); Point *makepoint(Point *pointx, Point *pointy); text *copytext(text *t); text *concat_text(text *arg1, text *arg2); -bool c_overpaid(TupleTableSlot *t, /* the current instance of EMP */ +bool c_overpaid(HeapTupleHeader t, /* the current instance of EMP */ int32 limit); @@ -94,7 +94,7 @@ concat_text(text *arg1, text *arg2) /* Composite types */ bool -c_overpaid(TupleTableSlot *t, /* the current instance of EMP */ +c_overpaid(HeapTupleHeader t, /* the current instance of EMP */ int32 limit) { bool isnull; diff --git a/src/tutorial/funcs_new.c b/src/tutorial/funcs_new.c index c9413096bcf8da55da1bc331b8f002bf8d477a81..e548b85ee415a8d8919f79cc2f6f1b11378703f5 100644 --- a/src/tutorial/funcs_new.c +++ b/src/tutorial/funcs_new.c @@ -115,7 +115,7 @@ PG_FUNCTION_INFO_V1(c_overpaid); Datum c_overpaid(PG_FUNCTION_ARGS) { - TupleTableSlot *t = (TupleTableSlot *) PG_GETARG_POINTER(0); + HeapTupleHeader t = PG_GETARG_HEAPTUPLEHEADER(0); int32 limit = PG_GETARG_INT32(1); bool isnull; int32 salary;