Skip to content

Commit ae93e5f

Browse files
committed
Make the world very nearly safe for composite-type columns in tables.
1. Solve the problem of not having TOAST references hiding inside composite values by establishing the rule that toasting only goes one level deep: a tuple can contain toasted fields, but a composite-type datum that is to be inserted into a tuple cannot. Enforcing this in heap_formtuple is relatively cheap and it avoids a large increase in the cost of running the tuptoaster during final storage of a row. 2. Fix some interesting problems in expansion of inherited queries that reference whole-row variables. We never really did this correctly before, but it's now relatively painless to solve by expanding the parent's whole-row Var into a RowExpr() selecting the proper columns from the child. If you dike out the preventive check in CheckAttributeType(), composite-type columns now seem to actually work. However, we surely cannot ship them like this --- without I/O for composite types, you can't get pg_dump to dump tables containing them. So a little more work still to do.
1 parent 8f2ea8b commit ae93e5f

File tree

12 files changed

+376
-67
lines changed

12 files changed

+376
-67
lines changed

src/backend/access/common/heaptuple.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.91 2004/06/04 20:35:21 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.92 2004/06/05 01:55:04 tgl Exp $
1313
*
1414
* NOTES
1515
* The old interface functions have been converted to macros
@@ -21,6 +21,7 @@
2121
#include "postgres.h"
2222

2323
#include "access/heapam.h"
24+
#include "access/tuptoaster.h"
2425
#include "catalog/pg_type.h"
2526

2627

@@ -567,8 +568,9 @@ heap_formtuple(TupleDesc tupleDescriptor,
567568
unsigned long len;
568569
int hoff;
569570
bool hasnull = false;
570-
int i;
571+
Form_pg_attribute *att = tupleDescriptor->attrs;
571572
int numberOfAttributes = tupleDescriptor->natts;
573+
int i;
572574

573575
if (numberOfAttributes > MaxTupleAttributeNumber)
574576
ereport(ERROR,
@@ -577,17 +579,34 @@ heap_formtuple(TupleDesc tupleDescriptor,
577579
numberOfAttributes, MaxTupleAttributeNumber)));
578580

579581
/*
580-
* Determine total space needed
582+
* Check for nulls and embedded tuples; expand any toasted attributes
583+
* in embedded tuples. This preserves the invariant that toasting can
584+
* only go one level deep.
585+
*
586+
* We can skip calling toast_flatten_tuple_attribute() if the attribute
587+
* couldn't possibly be of composite type. All composite datums are
588+
* varlena and have alignment 'd'; furthermore they aren't arrays.
589+
* Also, if an attribute is already toasted, it must have been sent to
590+
* disk already and so cannot contain toasted attributes.
581591
*/
582592
for (i = 0; i < numberOfAttributes; i++)
583593
{
584594
if (nulls[i] != ' ')
585-
{
586595
hasnull = true;
587-
break;
596+
else if (att[i]->attlen == -1 &&
597+
att[i]->attalign == 'd' &&
598+
att[i]->attndims == 0 &&
599+
!VARATT_IS_EXTENDED(values[i]))
600+
{
601+
values[i] = toast_flatten_tuple_attribute(values[i],
602+
att[i]->atttypid,
603+
att[i]->atttypmod);
588604
}
589605
}
590606

607+
/*
608+
* Determine total space needed
609+
*/
591610
len = offsetof(HeapTupleHeaderData, t_bits);
592611

593612
if (hasnull)
@@ -744,7 +763,11 @@ heap_deformtuple(HeapTuple tuple,
744763
bool slow = false; /* can we use/set attcacheoff? */
745764

746765
natts = tup->t_natts;
747-
/* This min() operation is pure paranoia */
766+
/*
767+
* In inheritance situations, it is possible that the given tuple actually
768+
* has more fields than the caller is expecting. Don't run off the end
769+
* of the caller's arrays.
770+
*/
748771
natts = Min(natts, tdesc_natts);
749772

750773
tp = (char *) tup + tup->t_hoff;

src/backend/access/heap/tuptoaster.c

Lines changed: 128 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.42 2004/06/04 20:35:21 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.43 2004/06/05 01:55:04 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -35,6 +35,7 @@
3535
#include "utils/builtins.h"
3636
#include "utils/fmgroids.h"
3737
#include "utils/pg_lzcompress.h"
38+
#include "utils/typcache.h"
3839

3940

4041
#undef TOAST_DEBUG
@@ -458,10 +459,10 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
458459
* still in the tuple must be someone else's we cannot reuse.
459460
* Expand it to plain (and, probably, toast it again below).
460461
*/
461-
if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
462+
if (VARATT_IS_EXTERNAL(new_value))
462463
{
463-
toast_values[i] = PointerGetDatum(heap_tuple_untoast_attr(
464-
(varattrib *) DatumGetPointer(toast_values[i])));
464+
new_value = heap_tuple_untoast_attr(new_value);
465+
toast_values[i] = PointerGetDatum(new_value);
465466
toast_free[i] = true;
466467
need_change = true;
467468
need_free = true;
@@ -470,7 +471,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
470471
/*
471472
* Remember the size of this attribute
472473
*/
473-
toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));
474+
toast_sizes[i] = VARATT_SIZE(new_value);
474475
}
475476
else
476477
{
@@ -785,6 +786,128 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
785786
}
786787

787788

789+
/* ----------
790+
* toast_flatten_tuple_attribute -
791+
*
792+
* If a Datum is of composite type, "flatten" it to contain no toasted fields.
793+
* This must be invoked on any potentially-composite field that is to be
794+
* inserted into a tuple. Doing this preserves the invariant that toasting
795+
* goes only one level deep in a tuple.
796+
* ----------
797+
*/
798+
Datum
799+
toast_flatten_tuple_attribute(Datum value,
800+
Oid typeId, int32 typeMod)
801+
{
802+
TupleDesc tupleDesc;
803+
HeapTupleHeader olddata;
804+
HeapTupleHeader new_data;
805+
int32 new_len;
806+
HeapTupleData tmptup;
807+
Form_pg_attribute *att;
808+
int numAttrs;
809+
int i;
810+
bool need_change = false;
811+
bool has_nulls = false;
812+
Datum toast_values[MaxTupleAttributeNumber];
813+
char toast_nulls[MaxTupleAttributeNumber];
814+
bool toast_free[MaxTupleAttributeNumber];
815+
816+
/*
817+
* See if it's a composite type, and get the tupdesc if so.
818+
*/
819+
tupleDesc = lookup_rowtype_tupdesc_noerror(typeId, typeMod, true);
820+
if (tupleDesc == NULL)
821+
return value; /* not a composite type */
822+
823+
att = tupleDesc->attrs;
824+
numAttrs = tupleDesc->natts;
825+
826+
/*
827+
* Break down the tuple into fields.
828+
*/
829+
olddata = DatumGetHeapTupleHeader(value);
830+
Assert(typeId == HeapTupleHeaderGetTypeId(olddata));
831+
Assert(typeMod == HeapTupleHeaderGetTypMod(olddata));
832+
/* Build a temporary HeapTuple control structure */
833+
tmptup.t_len = HeapTupleHeaderGetDatumLength(olddata);
834+
ItemPointerSetInvalid(&(tmptup.t_self));
835+
tmptup.t_tableOid = InvalidOid;
836+
tmptup.t_data = olddata;
837+
838+
Assert(numAttrs <= MaxTupleAttributeNumber);
839+
heap_deformtuple(&tmptup, tupleDesc, toast_values, toast_nulls);
840+
841+
memset(toast_free, 0, numAttrs * sizeof(bool));
842+
843+
for (i = 0; i < numAttrs; i++)
844+
{
845+
/*
846+
* Look at non-null varlena attributes
847+
*/
848+
if (toast_nulls[i] == 'n')
849+
has_nulls = true;
850+
else if (att[i]->attlen == -1)
851+
{
852+
varattrib *new_value;
853+
854+
new_value = (varattrib *) DatumGetPointer(toast_values[i]);
855+
if (VARATT_IS_EXTENDED(new_value))
856+
{
857+
new_value = heap_tuple_untoast_attr(new_value);
858+
toast_values[i] = PointerGetDatum(new_value);
859+
toast_free[i] = true;
860+
need_change = true;
861+
}
862+
}
863+
}
864+
865+
/*
866+
* If nothing to untoast, just return the original tuple.
867+
*/
868+
if (!need_change)
869+
return value;
870+
871+
/*
872+
* Calculate the new size of the tuple. Header size should not
873+
* change, but data size might.
874+
*/
875+
new_len = offsetof(HeapTupleHeaderData, t_bits);
876+
if (has_nulls)
877+
new_len += BITMAPLEN(numAttrs);
878+
if (olddata->t_infomask & HEAP_HASOID)
879+
new_len += sizeof(Oid);
880+
new_len = MAXALIGN(new_len);
881+
Assert(new_len == olddata->t_hoff);
882+
new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
883+
884+
new_data = (HeapTupleHeader) palloc0(new_len);
885+
886+
/*
887+
* Put the tuple header and the changed values into place
888+
*/
889+
memcpy(new_data, olddata, olddata->t_hoff);
890+
891+
HeapTupleHeaderSetDatumLength(new_data, new_len);
892+
893+
DataFill((char *) new_data + olddata->t_hoff,
894+
tupleDesc,
895+
toast_values,
896+
toast_nulls,
897+
&(new_data->t_infomask),
898+
has_nulls ? new_data->t_bits : NULL);
899+
900+
/*
901+
* Free allocated temp values
902+
*/
903+
for (i = 0; i < numAttrs; i++)
904+
if (toast_free[i])
905+
pfree(DatumGetPointer(toast_values[i]));
906+
907+
return PointerGetDatum(new_data);
908+
}
909+
910+
788911
/* ----------
789912
* toast_compress_datum -
790913
*

src/backend/optimizer/path/allpaths.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.117 2004/06/01 03:02:51 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.118 2004/06/05 01:55:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -302,11 +302,15 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
302302
{
303303
Var *parentvar = (Var *) lfirst(parentvars);
304304
Var *childvar = (Var *) lfirst(childvars);
305-
int parentndx = parentvar->varattno - rel->min_attr;
306-
int childndx = childvar->varattno - childrel->min_attr;
307305

308-
if (childrel->attr_widths[childndx] > rel->attr_widths[parentndx])
309-
rel->attr_widths[parentndx] = childrel->attr_widths[childndx];
306+
if (IsA(parentvar, Var) && IsA(childvar, Var))
307+
{
308+
int pndx = parentvar->varattno - rel->min_attr;
309+
int cndx = childvar->varattno - childrel->min_attr;
310+
311+
if (childrel->attr_widths[cndx] > rel->attr_widths[pndx])
312+
rel->attr_widths[pndx] = childrel->attr_widths[cndx];
313+
}
310314
}
311315
}
312316

src/backend/optimizer/path/costsize.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* Portions Copyright (c) 1994, Regents of the University of California
5050
*
5151
* IDENTIFICATION
52-
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.129 2004/06/01 03:02:52 tgl Exp $
52+
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.130 2004/06/05 01:55:04 tgl Exp $
5353
*
5454
*-------------------------------------------------------------------------
5555
*/
@@ -1704,11 +1704,18 @@ set_rel_width(Query *root, RelOptInfo *rel)
17041704
foreach(tllist, rel->reltargetlist)
17051705
{
17061706
Var *var = (Var *) lfirst(tllist);
1707-
int ndx = var->varattno - rel->min_attr;
1707+
int ndx;
17081708
Oid relid;
17091709
int32 item_width;
17101710

1711-
Assert(IsA(var, Var));
1711+
/* For now, punt on whole-row child Vars */
1712+
if (!IsA(var, Var))
1713+
{
1714+
tuple_width += 32; /* arbitrary */
1715+
continue;
1716+
}
1717+
1718+
ndx = var->varattno - rel->min_attr;
17121719

17131720
/*
17141721
* The width probably hasn't been cached yet, but may as well

src/backend/optimizer/path/pathkeys.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.59 2004/06/01 03:02:52 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.60 2004/06/05 01:55:04 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -725,7 +725,8 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
725725
{
726726
Var *var = (Var *) lfirst(temp);
727727

728-
if (var->varattno == varattno)
728+
if (IsA(var, Var) &&
729+
var->varattno == varattno)
729730
return var;
730731
}
731732

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy