|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* tupconvert.c
|
|
|
|
|
* Tuple conversion support.
|
|
|
|
|
*
|
|
|
|
|
* These functions provide conversion between rowtypes that are logically
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
* equivalent but might have columns in a different order or different sets of
|
|
|
|
|
* dropped columns.
|
|
|
|
|
*
|
|
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
|
|
|
|
* src/backend/access/common/tupconvert.c
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
|
|
#include "access/htup_details.h"
|
|
|
|
|
#include "access/tupconvert.h"
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
#include "executor/tuptable.h"
|
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The conversion setup routines have the following common API:
|
|
|
|
|
*
|
|
|
|
|
* The setup routine checks whether the given source and destination tuple
|
|
|
|
|
* descriptors are logically compatible. If not, it throws an error.
|
|
|
|
|
* If so, it returns NULL if they are physically compatible (ie, no conversion
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
* is needed), else a TupleConversionMap that can be used by execute_attr_map_tuple
|
|
|
|
|
* to perform the conversion.
|
|
|
|
|
*
|
|
|
|
|
* The TupleConversionMap, if needed, is palloc'd in the caller's memory
|
|
|
|
|
* context. Also, the given tuple descriptors are referenced by the map,
|
|
|
|
|
* so they must survive as long as the map is needed.
|
|
|
|
|
*
|
|
|
|
|
* The caller must supply a suitable primary error message to be used if
|
|
|
|
|
* a compatibility error is thrown. Recommended coding practice is to use
|
|
|
|
|
* gettext_noop() on this string, so that it is translatable but won't
|
|
|
|
|
* actually be translated unless the error gets thrown.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Implementation notes:
|
|
|
|
|
*
|
|
|
|
|
* The key component of a TupleConversionMap is an attrMap[] array with
|
|
|
|
|
* one entry per output column. This entry contains the 1-based index of
|
|
|
|
|
* the corresponding input column, or zero to force a NULL value (for
|
|
|
|
|
* a dropped output column). The TupleConversionMap also contains workspace
|
|
|
|
|
* arrays.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up for tuple conversion, matching input and output columns by
|
|
|
|
|
* position. (Dropped columns are ignored in both input and output.)
|
|
|
|
|
*
|
|
|
|
|
* Note: the errdetail messages speak of indesc as the "returned" rowtype,
|
|
|
|
|
* outdesc as the "expected" rowtype. This is okay for current uses but
|
|
|
|
|
* might need generalization in future.
|
|
|
|
|
*/
|
|
|
|
|
TupleConversionMap *
|
|
|
|
|
convert_tuples_by_position(TupleDesc indesc,
|
|
|
|
|
TupleDesc outdesc,
|
|
|
|
|
const char *msg)
|
|
|
|
|
{
|
|
|
|
|
TupleConversionMap *map;
|
|
|
|
|
AttrNumber *attrMap;
|
|
|
|
|
int nincols;
|
|
|
|
|
int noutcols;
|
|
|
|
|
int n;
|
|
|
|
|
int i;
|
|
|
|
|
int j;
|
|
|
|
|
bool same;
|
|
|
|
|
|
|
|
|
|
/* Verify compatibility and prepare attribute-number map */
|
|
|
|
|
n = outdesc->natts;
|
|
|
|
|
attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
|
|
|
|
|
j = 0; /* j is next physical input attribute */
|
|
|
|
|
nincols = noutcols = 0; /* these count non-dropped attributes */
|
|
|
|
|
same = true;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_attribute att = TupleDescAttr(outdesc, i);
|
|
|
|
|
Oid atttypid;
|
|
|
|
|
int32 atttypmod;
|
|
|
|
|
|
|
|
|
|
if (att->attisdropped)
|
|
|
|
|
continue; /* attrMap[i] is already 0 */
|
|
|
|
|
noutcols++;
|
|
|
|
|
atttypid = att->atttypid;
|
|
|
|
|
atttypmod = att->atttypmod;
|
|
|
|
|
for (; j < indesc->natts; j++)
|
|
|
|
|
{
|
|
|
|
|
att = TupleDescAttr(indesc, j);
|
|
|
|
|
if (att->attisdropped)
|
|
|
|
|
continue;
|
|
|
|
|
nincols++;
|
|
|
|
|
/* Found matching column, check type */
|
|
|
|
|
if (atttypid != att->atttypid ||
|
|
|
|
|
(atttypmod != att->atttypmod && atttypmod >= 0))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
|
errmsg_internal("%s", _(msg)),
|
|
|
|
|
errdetail("Returned type %s does not match expected type %s in column %d.",
|
|
|
|
|
format_type_with_typemod(att->atttypid,
|
|
|
|
|
att->atttypmod),
|
|
|
|
|
format_type_with_typemod(atttypid,
|
|
|
|
|
atttypmod),
|
|
|
|
|
noutcols)));
|
|
|
|
|
attrMap[i] = (AttrNumber) (j + 1);
|
|
|
|
|
j++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (attrMap[i] == 0)
|
|
|
|
|
same = false; /* we'll complain below */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for unused input columns */
|
|
|
|
|
for (; j < indesc->natts; j++)
|
|
|
|
|
{
|
|
|
|
|
if (TupleDescAttr(indesc, j)->attisdropped)
|
|
|
|
|
continue;
|
|
|
|
|
nincols++;
|
|
|
|
|
same = false; /* we'll complain below */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Report column count mismatch using the non-dropped-column counts */
|
|
|
|
|
if (!same)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
|
errmsg_internal("%s", _(msg)),
|
|
|
|
|
errdetail("Number of returned columns (%d) does not match "
|
|
|
|
|
"expected column count (%d).",
|
|
|
|
|
nincols, noutcols)));
|
|
|
|
|
|
|
|
|
|
/*
|
Clean up after insufficiently-researched optimization of tuple conversions.
tupconvert.c's functions formerly considered that an explicit tuple
conversion was necessary if the input and output tupdescs contained
different type OIDs. The point of that was to make sure that a composite
datum resulting from the conversion would contain the destination rowtype
OID in its composite-datum header. However, commit 3838074f8 entirely
misunderstood what that check was for, thinking that it had something to do
with presence or absence of an OID column within the tuple. Removal of the
check broke the no-op conversion path in ExecEvalConvertRowtype, as
reported by Ashutosh Bapat.
It turns out that of the dozen or so call sites for tupconvert.c functions,
ExecEvalConvertRowtype is the only one that cares about the composite-datum
header fields in the output tuple. In all the rest, we'd much rather avoid
an unnecessary conversion whenever the tuples are physically compatible.
Moreover, the comments in tupconvert.c only promise physical compatibility
not a metadata match. So, let's accept the removal of the guarantee about
the output tuple's rowtype marking, recognizing that this is a API change
that could conceivably break third-party callers of tupconvert.c. (So,
let's remember to mention it in the v10 release notes.)
However, commit 3838074f8 did have a bit of a point here, in that two
tuples mustn't be considered physically compatible if one has HEAP_HASOID
set and the other doesn't. (Some of the callers of tupconvert.c might not
really care about that, but we can't assume it in general.) The previous
check accidentally covered that issue, because no RECORD types ever have
OIDs, while if two tupdescs have the same named composite type OID then,
a fortiori, they have the same tdhasoid setting. If we're removing the
type OID match check then we'd better include tdhasoid match as part of
the physical compatibility check.
Without that hack in tupconvert.c, we need ExecEvalConvertRowtype to take
responsibility for inserting the correct rowtype OID label whenever
tupconvert.c decides it need not do anything. This is easily done with
heap_copy_tuple_as_datum, which will be considerably faster than a tuple
disassembly and reassembly anyway; so from a performance standpoint this
change is a win all around compared to what happened in earlier branches.
It just means a couple more lines of code in ExecEvalConvertRowtype.
Ashutosh Bapat and Tom Lane
Discussion: https://postgr.es/m/CAFjFpRfvHABV6+oVvGcshF8rHn+1LfRUhj7Jz1CDZ4gPUwehBg@mail.gmail.com
9 years ago
|
|
|
* Check to see if the map is one-to-one, in which case we need not do a
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
7 years ago
|
|
|
* tuple conversion.
|
|
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
7 years ago
|
|
|
if (indesc->natts == outdesc->natts)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_attribute inatt;
|
|
|
|
|
Form_pg_attribute outatt;
|
|
|
|
|
|
|
|
|
|
if (attrMap[i] == (i + 1))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If it's a dropped column and the corresponding input column is
|
|
|
|
|
* also dropped, we needn't convert. However, attlen and attalign
|
|
|
|
|
* must agree.
|
|
|
|
|
*/
|
|
|
|
|
inatt = TupleDescAttr(indesc, i);
|
|
|
|
|
outatt = TupleDescAttr(outdesc, i);
|
|
|
|
|
if (attrMap[i] == 0 &&
|
|
|
|
|
inatt->attisdropped &&
|
|
|
|
|
inatt->attlen == outatt->attlen &&
|
|
|
|
|
inatt->attalign == outatt->attalign)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
same = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
same = false;
|
|
|
|
|
|
|
|
|
|
if (same)
|
|
|
|
|
{
|
|
|
|
|
/* Runtime conversion is not needed */
|
|
|
|
|
pfree(attrMap);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prepare the map structure */
|
|
|
|
|
map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
|
|
|
|
|
map->indesc = indesc;
|
|
|
|
|
map->outdesc = outdesc;
|
|
|
|
|
map->attrMap = attrMap;
|
|
|
|
|
/* preallocate workspace for Datum arrays */
|
|
|
|
|
map->outvalues = (Datum *) palloc(n * sizeof(Datum));
|
|
|
|
|
map->outisnull = (bool *) palloc(n * sizeof(bool));
|
|
|
|
|
n = indesc->natts + 1; /* +1 for NULL */
|
|
|
|
|
map->invalues = (Datum *) palloc(n * sizeof(Datum));
|
|
|
|
|
map->inisnull = (bool *) palloc(n * sizeof(bool));
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
9 years ago
|
|
|
map->invalues[0] = (Datum) 0; /* set up the NULL entry */
|
|
|
|
|
map->inisnull[0] = true;
|
|
|
|
|
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up for tuple conversion, matching input and output columns by name.
|
|
|
|
|
* (Dropped columns are ignored in both input and output.) This is intended
|
|
|
|
|
* for use when the rowtypes are related by inheritance, so we expect an exact
|
|
|
|
|
* match of both type and typmod. The error messages will be a bit unhelpful
|
|
|
|
|
* unless both rowtypes are named composite types.
|
|
|
|
|
*/
|
|
|
|
|
TupleConversionMap *
|
|
|
|
|
convert_tuples_by_name(TupleDesc indesc,
|
|
|
|
|
TupleDesc outdesc)
|
|
|
|
|
{
|
|
|
|
|
TupleConversionMap *map;
|
|
|
|
|
AttrNumber *attrMap;
|
|
|
|
|
int n = outdesc->natts;
|
|
|
|
|
|
|
|
|
|
/* Verify compatibility and prepare attribute-number map */
|
|
|
|
|
attrMap = convert_tuples_by_name_map_if_req(indesc, outdesc);
|
|
|
|
|
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
if (attrMap == NULL)
|
|
|
|
|
{
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
/* runtime conversion is not needed */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prepare the map structure */
|
|
|
|
|
map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
|
|
|
|
|
map->indesc = indesc;
|
|
|
|
|
map->outdesc = outdesc;
|
|
|
|
|
map->attrMap = attrMap;
|
|
|
|
|
/* preallocate workspace for Datum arrays */
|
|
|
|
|
map->outvalues = (Datum *) palloc(n * sizeof(Datum));
|
|
|
|
|
map->outisnull = (bool *) palloc(n * sizeof(bool));
|
|
|
|
|
n = indesc->natts + 1; /* +1 for NULL */
|
|
|
|
|
map->invalues = (Datum *) palloc(n * sizeof(Datum));
|
|
|
|
|
map->inisnull = (bool *) palloc(n * sizeof(bool));
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
9 years ago
|
|
|
map->invalues[0] = (Datum) 0; /* set up the NULL entry */
|
|
|
|
|
map->inisnull[0] = true;
|
|
|
|
|
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return a palloc'd bare attribute map for tuple conversion, matching input
|
|
|
|
|
* and output columns by name. (Dropped columns are ignored in both input and
|
|
|
|
|
* output.) This is normally a subroutine for convert_tuples_by_name, but can
|
|
|
|
|
* be used standalone.
|
|
|
|
|
*/
|
|
|
|
|
AttrNumber *
|
|
|
|
|
convert_tuples_by_name_map(TupleDesc indesc,
|
|
|
|
|
TupleDesc outdesc)
|
|
|
|
|
{
|
|
|
|
|
AttrNumber *attrMap;
|
|
|
|
|
int outnatts;
|
|
|
|
|
int innatts;
|
|
|
|
|
int i;
|
|
|
|
|
int nextindesc = -1;
|
|
|
|
|
|
|
|
|
|
outnatts = outdesc->natts;
|
|
|
|
|
innatts = indesc->natts;
|
|
|
|
|
|
|
|
|
|
attrMap = (AttrNumber *) palloc0(outnatts * sizeof(AttrNumber));
|
|
|
|
|
for (i = 0; i < outnatts; i++)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
|
|
|
|
|
char *attname;
|
|
|
|
|
Oid atttypid;
|
|
|
|
|
int32 atttypmod;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
if (outatt->attisdropped)
|
|
|
|
|
continue; /* attrMap[i] is already 0 */
|
|
|
|
|
attname = NameStr(outatt->attname);
|
|
|
|
|
atttypid = outatt->atttypid;
|
|
|
|
|
atttypmod = outatt->atttypmod;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now search for an attribute with the same name in the indesc. It
|
|
|
|
|
* seems likely that a partitioned table will have the attributes in
|
|
|
|
|
* the same order as the partition, so the search below is optimized
|
|
|
|
|
* for that case. It is possible that columns are dropped in one of
|
|
|
|
|
* the relations, but not the other, so we use the 'nextindesc'
|
|
|
|
|
* counter to track the starting point of the search. If the inner
|
|
|
|
|
* loop encounters dropped columns then it will have to skip over
|
|
|
|
|
* them, but it should leave 'nextindesc' at the correct position for
|
|
|
|
|
* the next outer loop.
|
|
|
|
|
*/
|
|
|
|
|
for (j = 0; j < innatts; j++)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_attribute inatt;
|
|
|
|
|
|
|
|
|
|
nextindesc++;
|
|
|
|
|
if (nextindesc >= innatts)
|
|
|
|
|
nextindesc = 0;
|
|
|
|
|
|
|
|
|
|
inatt = TupleDescAttr(indesc, nextindesc);
|
|
|
|
|
if (inatt->attisdropped)
|
|
|
|
|
continue;
|
|
|
|
|
if (strcmp(attname, NameStr(inatt->attname)) == 0)
|
|
|
|
|
{
|
|
|
|
|
/* Found it, check type */
|
|
|
|
|
if (atttypid != inatt->atttypid || atttypmod != inatt->atttypmod)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
|
errmsg("could not convert row type"),
|
|
|
|
|
errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
|
|
|
|
|
attname,
|
|
|
|
|
format_type_be(outdesc->tdtypeid),
|
|
|
|
|
format_type_be(indesc->tdtypeid))));
|
|
|
|
|
attrMap[i] = inatt->attnum;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (attrMap[i] == 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
|
errmsg("could not convert row type"),
|
|
|
|
|
errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
|
|
|
|
|
attname,
|
|
|
|
|
format_type_be(outdesc->tdtypeid),
|
|
|
|
|
format_type_be(indesc->tdtypeid))));
|
|
|
|
|
}
|
|
|
|
|
return attrMap;
|
|
|
|
|
}
|
|
|
|
|
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
/*
|
|
|
|
|
* Returns mapping created by convert_tuples_by_name_map, or NULL if no
|
|
|
|
|
* conversion not required. This is a convenience routine for
|
|
|
|
|
* convert_tuples_by_name() and other functions.
|
|
|
|
|
*/
|
|
|
|
|
AttrNumber *
|
|
|
|
|
convert_tuples_by_name_map_if_req(TupleDesc indesc,
|
|
|
|
|
TupleDesc outdesc)
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
{
|
|
|
|
|
AttrNumber *attrMap;
|
|
|
|
|
int n = outdesc->natts;
|
|
|
|
|
int i;
|
|
|
|
|
bool same;
|
|
|
|
|
|
|
|
|
|
/* Verify compatibility and prepare attribute-number map */
|
|
|
|
|
attrMap = convert_tuples_by_name_map(indesc, outdesc);
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check to see if the map is one-to-one, in which case we need not do a
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
7 years ago
|
|
|
* tuple conversion.
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
7 years ago
|
|
|
if (indesc->natts == outdesc->natts)
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
{
|
|
|
|
|
same = true;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_attribute inatt;
|
|
|
|
|
Form_pg_attribute outatt;
|
|
|
|
|
|
|
|
|
|
if (attrMap[i] == (i + 1))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If it's a dropped column and the corresponding input column is
|
|
|
|
|
* also dropped, we needn't convert. However, attlen and attalign
|
|
|
|
|
* must agree.
|
|
|
|
|
*/
|
|
|
|
|
inatt = TupleDescAttr(indesc, i);
|
|
|
|
|
outatt = TupleDescAttr(outdesc, i);
|
|
|
|
|
if (attrMap[i] == 0 &&
|
|
|
|
|
inatt->attisdropped &&
|
|
|
|
|
inatt->attlen == outatt->attlen &&
|
|
|
|
|
inatt->attalign == outatt->attalign)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
same = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
same = false;
|
|
|
|
|
|
|
|
|
|
if (same)
|
|
|
|
|
{
|
|
|
|
|
/* Runtime conversion is not needed */
|
|
|
|
|
pfree(attrMap);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return attrMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Perform conversion of a tuple according to the map.
|
|
|
|
|
*/
|
|
|
|
|
HeapTuple
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
|
|
|
|
|
{
|
|
|
|
|
AttrNumber *attrMap = map->attrMap;
|
|
|
|
|
Datum *invalues = map->invalues;
|
|
|
|
|
bool *inisnull = map->inisnull;
|
|
|
|
|
Datum *outvalues = map->outvalues;
|
|
|
|
|
bool *outisnull = map->outisnull;
|
|
|
|
|
int outnatts = map->outdesc->natts;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Extract all the values of the old tuple, offsetting the arrays so that
|
|
|
|
|
* invalues[0] is left NULL and invalues[1] is the first source attribute;
|
|
|
|
|
* this exactly matches the numbering convention in attrMap.
|
|
|
|
|
*/
|
|
|
|
|
heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Transpose into proper fields of the new tuple.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < outnatts; i++)
|
|
|
|
|
{
|
|
|
|
|
int j = attrMap[i];
|
|
|
|
|
|
|
|
|
|
outvalues[i] = invalues[j];
|
|
|
|
|
outisnull[i] = inisnull[j];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now form the new tuple.
|
|
|
|
|
*/
|
|
|
|
|
return heap_form_tuple(map->outdesc, outvalues, outisnull);
|
|
|
|
|
}
|
|
|
|
|
|
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple
descriptors for multiple tuples, as previously done when using
ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors
change for every tuple.
Previously we also, via ConvertPartitionTupleSlot(), built new tuples
after the mapping even in cases where we, immediately afterwards,
access individual columns again.
Refactor the code so one slot, on demand, is used for each
partition. That avoids having to change the descriptor (and allows to
use the more efficient "fixed" tuple slots). Then use slot->slot
mapping, to avoid unnecessarily forming a tuple.
As the naming between the tuple and slot mapping functions wasn't
consistent, rename them to execute_attr_map_{tuple,slot}. It's likely
that we'll also rename convert_tuples_by_* to denote that these
functions "only" build a map, but that's left for later.
Author: Amit Khandekar and Amit Langote, editorialized by me
Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund
Discussion:
https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com
https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp
Backpatch: -
7 years ago
|
|
|
/*
|
|
|
|
|
* Perform conversion of a tuple slot according to the map.
|
|
|
|
|
*/
|
|
|
|
|
TupleTableSlot *
|
|
|
|
|
execute_attr_map_slot(AttrNumber *attrMap,
|
|
|
|
|
TupleTableSlot *in_slot,
|
|
|
|
|
TupleTableSlot *out_slot)
|
|
|
|
|
{
|
|
|
|
|
Datum *invalues;
|
|
|
|
|
bool *inisnull;
|
|
|
|
|
Datum *outvalues;
|
|
|
|
|
bool *outisnull;
|
|
|
|
|
int outnatts;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
|
Assert(in_slot->tts_tupleDescriptor != NULL &&
|
|
|
|
|
out_slot->tts_tupleDescriptor != NULL);
|
|
|
|
|
Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
|
|
|
|
|
|
|
|
|
|
outnatts = out_slot->tts_tupleDescriptor->natts;
|
|
|
|
|
|
|
|
|
|
/* Extract all the values of the in slot. */
|
|
|
|
|
slot_getallattrs(in_slot);
|
|
|
|
|
|
|
|
|
|
/* Before doing the mapping, clear any old contents from the out slot */
|
|
|
|
|
ExecClearTuple(out_slot);
|
|
|
|
|
|
|
|
|
|
invalues = in_slot->tts_values;
|
|
|
|
|
inisnull = in_slot->tts_isnull;
|
|
|
|
|
outvalues = out_slot->tts_values;
|
|
|
|
|
outisnull = out_slot->tts_isnull;
|
|
|
|
|
|
|
|
|
|
/* Transpose into proper fields of the out slot. */
|
|
|
|
|
for (i = 0; i < outnatts; i++)
|
|
|
|
|
{
|
|
|
|
|
int j = attrMap[i] - 1;
|
|
|
|
|
|
|
|
|
|
/* attrMap[i] == 0 means it's a NULL datum. */
|
|
|
|
|
if (j == -1)
|
|
|
|
|
{
|
|
|
|
|
outvalues[i] = (Datum) 0;
|
|
|
|
|
outisnull[i] = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
outvalues[i] = invalues[j];
|
|
|
|
|
outisnull[i] = inisnull[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExecStoreVirtualTuple(out_slot);
|
|
|
|
|
|
|
|
|
|
return out_slot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Free a TupleConversionMap structure.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
free_conversion_map(TupleConversionMap *map)
|
|
|
|
|
{
|
|
|
|
|
/* indesc and outdesc are not ours to free */
|
|
|
|
|
pfree(map->attrMap);
|
|
|
|
|
pfree(map->invalues);
|
|
|
|
|
pfree(map->inisnull);
|
|
|
|
|
pfree(map->outvalues);
|
|
|
|
|
pfree(map->outisnull);
|
|
|
|
|
pfree(map);
|
|
|
|
|
}
|