Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0413a55

Browse files
committed
Improve compression and storage support with inheritance
A child table can specify a compression or storage method different from its parents. This was previously an error. (But this was inconsistently enforced because for example the settings could be changed later using ALTER TABLE.) This now also allows an explicit override if multiple parents have different compression or storage settings, which was previously an error that could not be overridden. The compression and storage properties remains unchanged in a child inheriting from parent(s) after its creation, i.e., when using ALTER TABLE ... INHERIT. (This is not changed.) Before this change, the error detail would mention the first pair of conflicting parent compression or storage methods. But with this change it waits till the child specification is considered by which time we may have encountered many such conflicting pairs. Hence the error detail after this change does not include the conflicting compression/storage methods. Those can be obtained from parent definitions if necessary. The code to maintain list of all conflicting methods or even the first conflicting pair does not seem worth the convenience it offers. This change is inline with what we do with conflicting default values. Before this commit, the specified storage method could be stored in ColumnDef::storage (CREATE TABLE ... LIKE) or ColumnDef::storage_name (CREATE TABLE ...). This caused the MergeChildAttribute() and MergeInheritedAttribute() to ignore a storage method specified in the child definition since it looked only at ColumnDef::storage. This commit removes ColumnDef::storage and instead uses ColumnDef::storage_name to save any storage method specification. This is similar to how compression method specification is handled. Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/24656cec-d6ef-4d15-8b5b-e8dfc9c833a7@eisentraut.org
1 parent e85732d commit 0413a55

File tree

15 files changed

+408
-111
lines changed

15 files changed

+408
-111
lines changed

doc/src/sgml/ref/create_table.sgml

+7-1
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,13 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
398398
</para>
399399

400400
<para>
401-
Column <literal>STORAGE</literal> settings are also copied from parent tables.
401+
Column storage and compression settings are inherited from parent
402+
tables. If a column is inherited from multiple tables, the storage
403+
settings or any explicit compression settings for the column must be the
404+
same in all parent tables, else an error is reported. Storage or
405+
compression settings explicitly specified for the new table override any
406+
inherited settings and can also be used to override conflicting
407+
inherited settings.
402408
</para>
403409

404410
<para>

src/backend/catalog/pg_type.c

+23
Original file line numberDiff line numberDiff line change
@@ -974,3 +974,26 @@ makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
974974

975975
return pstrdup(buf);
976976
}
977+
978+
/*
979+
* GetAttributeStorageName
980+
* returns the name corresponding to a typstorage/attstorage enum value.
981+
*/
982+
const char *
983+
GetAttributeStorageName(char c)
984+
{
985+
switch (c)
986+
{
987+
case TYPSTORAGE_PLAIN:
988+
return "PLAIN";
989+
case TYPSTORAGE_EXTERNAL:
990+
return "EXTERNAL";
991+
case TYPSTORAGE_EXTENDED:
992+
return "EXTENDED";
993+
case TYPSTORAGE_MAIN:
994+
return "MAIN";
995+
default:
996+
elog(ERROR, "invalid storage type %c", c);
997+
return NULL;
998+
}
999+
}

src/backend/commands/tablecmds.c

+63-75
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,16 @@ typedef struct ForeignTruncateInfo
350350
#define child_dependency_type(child_is_partition) \
351351
((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
352352

353+
/*
354+
* Bogus property string to track conflict in inherited properties of a column.
355+
* It is currently used for storage and compression specifications, but may be
356+
* used for other string specifications in future. It can be any string which
357+
* does not look like a valid compression or storage method. It is meant to be
358+
* used by MergeAttributes() and its minions. It is not expected to be stored
359+
* on disk.
360+
*/
361+
static const char *conflicting_column_property = "*** conflicting column property ***";
362+
353363
static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
354364
static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
355365
static void truncate_check_activity(Relation rel);
@@ -360,7 +370,8 @@ static List *MergeAttributes(List *columns, const List *supers, char relpersiste
360370
List **supnotnulls);
361371
static List *MergeCheckConstraint(List *constraints, const char *name, Node *expr);
362372
static void MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef);
363-
static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef);
373+
static ColumnDef *MergeInheritedAttribute(List *inh_columns, int exist_attno, const ColumnDef *newdef,
374+
bool *have_deferred_conflicts);
364375
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispartition);
365376
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
366377
static void StoreCatalogInheritance(Oid relationId, List *supers,
@@ -620,7 +631,6 @@ static ObjectAddress ATExecSetCompression(Relation rel,
620631
const char *column, Node *newValue, LOCKMODE lockmode);
621632

622633
static void index_copy_data(Relation rel, RelFileLocator newrlocator);
623-
static const char *storage_name(char c);
624634

625635
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid,
626636
Oid oldRelOid, void *arg);
@@ -1363,9 +1373,7 @@ BuildDescForRelation(const List *columns)
13631373
att->attidentity = entry->identity;
13641374
att->attgenerated = entry->generated;
13651375
att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1366-
if (entry->storage)
1367-
att->attstorage = entry->storage;
1368-
else if (entry->storage_name)
1376+
if (entry->storage_name)
13691377
att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
13701378
}
13711379

@@ -2388,28 +2396,6 @@ truncate_check_activity(Relation rel)
23882396
CheckTableNotInUse(rel, "TRUNCATE");
23892397
}
23902398

2391-
/*
2392-
* storage_name
2393-
* returns the name corresponding to a typstorage/attstorage enum value
2394-
*/
2395-
static const char *
2396-
storage_name(char c)
2397-
{
2398-
switch (c)
2399-
{
2400-
case TYPSTORAGE_PLAIN:
2401-
return "PLAIN";
2402-
case TYPSTORAGE_EXTERNAL:
2403-
return "EXTERNAL";
2404-
case TYPSTORAGE_EXTENDED:
2405-
return "EXTENDED";
2406-
case TYPSTORAGE_MAIN:
2407-
return "MAIN";
2408-
default:
2409-
return "???";
2410-
}
2411-
}
2412-
24132399
/*----------
24142400
* MergeAttributes
24152401
* Returns new schema given initial schema and superclasses.
@@ -2483,7 +2469,7 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
24832469
List *inh_columns = NIL;
24842470
List *constraints = NIL;
24852471
List *nnconstraints = NIL;
2486-
bool have_bogus_defaults = false;
2472+
bool have_deferred_conflicts = false;
24872473
int child_attno;
24882474
static Node bogus_marker = {0}; /* marks conflicting defaults */
24892475
List *saved_columns = NIL;
@@ -2720,11 +2706,10 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
27202706
*/
27212707
newdef = makeColumnDef(attributeName, attribute->atttypid,
27222708
attribute->atttypmod, attribute->attcollation);
2723-
newdef->storage = attribute->attstorage;
2709+
newdef->storage_name = GetAttributeStorageName(attribute->attstorage);
27242710
newdef->generated = attribute->attgenerated;
27252711
if (CompressionMethodIsValid(attribute->attcompression))
2726-
newdef->compression =
2727-
pstrdup(GetCompressionMethodName(attribute->attcompression));
2712+
newdef->compression = GetCompressionMethodName(attribute->attcompression);
27282713

27292714
/*
27302715
* Regular inheritance children are independent enough not to
@@ -2744,7 +2729,8 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
27442729
/*
27452730
* Yes, try to merge the two column definitions.
27462731
*/
2747-
mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef);
2732+
mergeddef = MergeInheritedAttribute(inh_columns, exist_attno, newdef,
2733+
&have_deferred_conflicts);
27482734

27492735
newattmap->attnums[parent_attno - 1] = exist_attno;
27502736

@@ -2867,7 +2853,7 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
28672853
else if (!equal(def->cooked_default, this_default))
28682854
{
28692855
def->cooked_default = &bogus_marker;
2870-
have_bogus_defaults = true;
2856+
have_deferred_conflicts = true;
28712857
}
28722858
}
28732859

@@ -3077,10 +3063,10 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
30773063
}
30783064

30793065
/*
3080-
* If we found any conflicting parent default values, check to make sure
3081-
* they were overridden by the child.
3066+
* If we found any conflicting parent default values or conflicting parent
3067+
* properties, check to make sure they were overridden by the child.
30823068
*/
3083-
if (have_bogus_defaults)
3069+
if (have_deferred_conflicts)
30843070
{
30853071
foreach(lc, columns)
30863072
{
@@ -3101,6 +3087,20 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
31013087
def->colname),
31023088
errhint("To resolve the conflict, specify a default explicitly.")));
31033089
}
3090+
3091+
if (def->compression == conflicting_column_property)
3092+
ereport(ERROR,
3093+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3094+
errmsg("column \"%s\" inherits conflicting compression methods",
3095+
def->colname),
3096+
errhint("To resolve the conflict, specify a compression method explicitly.")));
3097+
3098+
if (def->storage_name == conflicting_column_property)
3099+
ereport(ERROR,
3100+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3101+
errmsg("column \"%s\" inherits conflicting storage methods",
3102+
def->colname),
3103+
errhint("To resolve the conflict, specify a storage method explicitly.")));
31043104
}
31053105
}
31063106

@@ -3250,33 +3250,18 @@ MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const
32503250
inhdef->identity = newdef->identity;
32513251

32523252
/*
3253-
* Copy storage parameter
3253+
* Child storage specification, if any, overrides inherited storage
3254+
* property.
32543255
*/
3255-
if (inhdef->storage == 0)
3256-
inhdef->storage = newdef->storage;
3257-
else if (newdef->storage != 0 && inhdef->storage != newdef->storage)
3258-
ereport(ERROR,
3259-
(errcode(ERRCODE_DATATYPE_MISMATCH),
3260-
errmsg("column \"%s\" has a storage parameter conflict",
3261-
attributeName),
3262-
errdetail("%s versus %s",
3263-
storage_name(inhdef->storage),
3264-
storage_name(newdef->storage))));
3256+
if (newdef->storage_name != NULL)
3257+
inhdef->storage_name = newdef->storage_name;
32653258

32663259
/*
3267-
* Copy compression parameter
3260+
* Child compression specification, if any, overrides inherited
3261+
* compression property.
32683262
*/
3269-
if (inhdef->compression == NULL)
3263+
if (newdef->compression != NULL)
32703264
inhdef->compression = newdef->compression;
3271-
else if (newdef->compression != NULL)
3272-
{
3273-
if (strcmp(inhdef->compression, newdef->compression) != 0)
3274-
ereport(ERROR,
3275-
(errcode(ERRCODE_DATATYPE_MISMATCH),
3276-
errmsg("column \"%s\" has a compression method conflict",
3277-
attributeName),
3278-
errdetail("%s versus %s", inhdef->compression, newdef->compression)));
3279-
}
32803265

32813266
/*
32823267
* Merge of not-null constraints = OR 'em together
@@ -3343,6 +3328,10 @@ MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const
33433328
* 'exist_attno' is the number the existing matching attribute in inh_columns.
33443329
* 'newdef' is the new parent column/attribute definition to be merged.
33453330
*
3331+
* Output arguments:
3332+
* 'have_deferred_conflicts' is set to true if there is a conflict in inherited
3333+
* compression properties; remains unchanged otherwise.
3334+
*
33463335
* The matching ColumnDef in 'inh_columns' list is modified and returned.
33473336
*
33483337
* Notes:
@@ -3356,7 +3345,8 @@ MergeChildAttribute(List *inh_columns, int exist_attno, int newcol_attno, const
33563345
static ColumnDef *
33573346
MergeInheritedAttribute(List *inh_columns,
33583347
int exist_attno,
3359-
const ColumnDef *newdef)
3348+
const ColumnDef *newdef,
3349+
bool *have_deferred_conflicts)
33603350
{
33613351
char *attributeName = newdef->colname;
33623352
ColumnDef *prevdef;
@@ -3403,28 +3393,26 @@ MergeInheritedAttribute(List *inh_columns,
34033393
/*
34043394
* Copy/check storage parameter
34053395
*/
3406-
if (prevdef->storage == 0)
3407-
prevdef->storage = newdef->storage;
3408-
else if (prevdef->storage != newdef->storage)
3409-
ereport(ERROR,
3410-
(errcode(ERRCODE_DATATYPE_MISMATCH),
3411-
errmsg("inherited column \"%s\" has a storage parameter conflict",
3412-
attributeName),
3413-
errdetail("%s versus %s",
3414-
storage_name(prevdef->storage),
3415-
storage_name(newdef->storage))));
3396+
if (prevdef->storage_name == NULL)
3397+
prevdef->storage_name = newdef->storage_name;
3398+
else if (newdef->storage_name != NULL &&
3399+
strcmp(prevdef->storage_name, newdef->storage_name) != 0)
3400+
{
3401+
prevdef->storage_name = conflicting_column_property;
3402+
*have_deferred_conflicts = true;
3403+
}
34163404

34173405
/*
34183406
* Copy/check compression parameter
34193407
*/
34203408
if (prevdef->compression == NULL)
34213409
prevdef->compression = newdef->compression;
3422-
else if (strcmp(prevdef->compression, newdef->compression) != 0)
3423-
ereport(ERROR,
3424-
(errcode(ERRCODE_DATATYPE_MISMATCH),
3425-
errmsg("column \"%s\" has a compression method conflict",
3426-
attributeName),
3427-
errdetail("%s versus %s", prevdef->compression, newdef->compression)));
3410+
else if (newdef->compression != NULL &&
3411+
strcmp(prevdef->compression, newdef->compression) != 0)
3412+
{
3413+
prevdef->compression = conflicting_column_property;
3414+
*have_deferred_conflicts = true;
3415+
}
34283416

34293417
/*
34303418
* Check for GENERATED conflicts

src/backend/nodes/makefuncs.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
500500
n->is_local = true;
501501
n->is_not_null = false;
502502
n->is_from_type = false;
503-
n->storage = 0;
503+
n->storage_name = NULL;
504504
n->raw_default = NULL;
505505
n->cooked_default = NULL;
506506
n->collClause = NULL;

src/backend/parser/gram.y

+3-4
Original file line numberDiff line numberDiff line change
@@ -3754,7 +3754,6 @@ columnDef: ColId Typename opt_column_storage opt_column_compression create_gener
37543754
n->is_local = true;
37553755
n->is_not_null = false;
37563756
n->is_from_type = false;
3757-
n->storage = 0;
37583757
n->raw_default = NULL;
37593758
n->cooked_default = NULL;
37603759
n->collOid = InvalidOid;
@@ -3776,7 +3775,7 @@ columnOptions: ColId ColQualList
37763775
n->is_local = true;
37773776
n->is_not_null = false;
37783777
n->is_from_type = false;
3779-
n->storage = 0;
3778+
n->storage_name = NULL;
37803779
n->raw_default = NULL;
37813780
n->cooked_default = NULL;
37823781
n->collOid = InvalidOid;
@@ -3795,7 +3794,7 @@ columnOptions: ColId ColQualList
37953794
n->is_local = true;
37963795
n->is_not_null = false;
37973796
n->is_from_type = false;
3798-
n->storage = 0;
3797+
n->storage_name = NULL;
37993798
n->raw_default = NULL;
38003799
n->cooked_default = NULL;
38013800
n->collOid = InvalidOid;
@@ -13858,7 +13857,7 @@ TableFuncElement: ColId Typename opt_collate_clause
1385813857
n->is_local = true;
1385913858
n->is_not_null = false;
1386013859
n->is_from_type = false;
13861-
n->storage = 0;
13860+
n->storage_name = NULL;
1386213861
n->raw_default = NULL;
1386313862
n->cooked_default = NULL;
1386413863
n->collClause = (CollateClause *) $3;

src/backend/parser/parse_utilcmd.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -1134,15 +1134,14 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
11341134

11351135
/* Likewise, copy storage if requested */
11361136
if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE)
1137-
def->storage = attribute->attstorage;
1137+
def->storage_name = GetAttributeStorageName(attribute->attstorage);
11381138
else
1139-
def->storage = 0;
1139+
def->storage_name = NULL;
11401140

11411141
/* Likewise, copy compression if requested */
11421142
if ((table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) != 0
11431143
&& CompressionMethodIsValid(attribute->attcompression))
1144-
def->compression =
1145-
pstrdup(GetCompressionMethodName(attribute->attcompression));
1144+
def->compression = GetCompressionMethodName(attribute->attcompression);
11461145
else
11471146
def->compression = NULL;
11481147

src/include/catalog/pg_type.h

+2
Original file line numberDiff line numberDiff line change
@@ -404,4 +404,6 @@ extern bool moveArrayTypeName(Oid typeOid, const char *typeName,
404404
extern char *makeMultirangeTypeName(const char *rangeTypeName,
405405
Oid typeNamespace);
406406

407+
extern const char *GetAttributeStorageName(char storage);
408+
407409
#endif /* PG_TYPE_H */

src/include/nodes/parsenodes.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -712,13 +712,12 @@ typedef struct ColumnDef
712712
NodeTag type;
713713
char *colname; /* name of column */
714714
TypeName *typeName; /* type of column */
715-
char *compression; /* compression method for column */
715+
const char *compression; /* compression method for column */
716716
int inhcount; /* number of times column is inherited */
717717
bool is_local; /* column has local (non-inherited) def'n */
718718
bool is_not_null; /* NOT NULL constraint specified? */
719719
bool is_from_type; /* column definition came from table type */
720-
char storage; /* attstorage setting, or 0 for default */
721-
char *storage_name; /* attstorage setting name or NULL for default */
720+
const char *storage_name; /* attstorage setting name or NULL for default */
722721
Node *raw_default; /* default value (untransformed parse tree) */
723722
Node *cooked_default; /* default value (transformed expr tree) */
724723
char identity; /* attidentity setting */

0 commit comments

Comments
 (0)