Skip to content

Commit 1ccaed7

Browse files
feodorNikita Malakhov
authored andcommitted
Implement CREATE TABLE .. ( STORAGE .. )
1 parent 641f3df commit 1ccaed7

File tree

6 files changed

+101
-28
lines changed

6 files changed

+101
-28
lines changed

doc/src/sgml/ref/create_table.sgml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ PostgreSQL documentation
2222
<refsynopsisdiv>
2323
<synopsis>
2424
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] <replaceable class="parameter">table_name</replaceable> ( [
25-
{ <replaceable class="parameter">column_name</replaceable> <replaceable class="parameter">data_type</replaceable> [ COMPRESSION <replaceable>compression_method</replaceable> ] [ COLLATE <replaceable>collation</replaceable> ] [ <replaceable class="parameter">column_constraint</replaceable> [ ... ] ]
25+
{ <replaceable class="parameter">column_name</replaceable> <replaceable class="parameter">data_type</replaceable> [ STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } ] [ COMPRESSION <replaceable>compression_method</replaceable> ] [ COLLATE <replaceable>collation</replaceable> ] [ <replaceable class="parameter">column_constraint</replaceable> [ ... ] ]
2626
| <replaceable>table_constraint</replaceable>
2727
| LIKE <replaceable>source_table</replaceable> [ <replaceable>like_option</replaceable> ... ] }
2828
[, ... ]
@@ -292,6 +292,28 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
292292
</listitem>
293293
</varlistentry>
294294

295+
<varlistentry>
296+
<term> <literal>SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }</literal></term>
297+
<listitem>
298+
<para>
299+
This form sets the storage mode for a column. This controls whether this
300+
column is held inline or in a secondary <acronym>TOAST</acronym> table, and
301+
whether the data
302+
should be compressed or not. <literal>PLAIN</literal> must be used
303+
for fixed-length values such as <type>integer</type> and is
304+
inline, uncompressed. <literal>MAIN</literal> is for inline,
305+
compressible data. <literal>EXTERNAL</literal> is for external,
306+
uncompressed data, and <literal>EXTENDED</literal> is for external,
307+
compressed data. <literal>EXTENDED</literal> is the default for most
308+
data types that support non-<literal>PLAIN</literal> storage.
309+
Use of <literal>EXTERNAL</literal> will make substring operations on
310+
very large <type>text</type> and <type>bytea</type> values run faster,
311+
at the penalty of increased storage space.
312+
See <xref linkend="storage-toast"/> for more information.
313+
</para>
314+
</listitem>
315+
</varlistentry>
316+
295317
<varlistentry>
296318
<term><literal>COMPRESSION <replaceable class="parameter">compression_method</replaceable></literal></term>
297319
<listitem>

src/backend/commands/tablecmds.c

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
625625
static List *GetParentedForeignKeyRefs(Relation partition);
626626
static void ATDetachCheckNoForeignKeyRefs(Relation partition);
627627
static char GetAttributeCompression(Oid atttypid, char *compression);
628+
static char GetAttributeStorage(const char *storagemode);
628629

629630

630631
/* ----------------------------------------------------------------
@@ -923,6 +924,22 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
923924
if (colDef->compression)
924925
attr->attcompression = GetAttributeCompression(attr->atttypid,
925926
colDef->compression);
927+
928+
if (colDef->storage_name)
929+
{
930+
attr->attstorage = GetAttributeStorage(colDef->storage_name);
931+
/*
932+
* safety check: do not allow toasted storage modes unless column datatype
933+
* is TOAST-aware.
934+
*/
935+
if (!(attr->attstorage == TYPSTORAGE_PLAIN ||
936+
TypeIsToastable(attr->atttypid)))
937+
ereport(ERROR,
938+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
939+
errmsg("column data type %s can only have storage PLAIN",
940+
format_type_be(attr->atttypid))));
941+
}
942+
926943
}
927944

928945
/*
@@ -6769,7 +6786,23 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
67696786
attribute.atttypmod = typmod;
67706787
attribute.attbyval = tform->typbyval;
67716788
attribute.attalign = tform->typalign;
6772-
attribute.attstorage = tform->typstorage;
6789+
if (colDef->storage_name)
6790+
{
6791+
attribute.attstorage = GetAttributeStorage(colDef->storage_name);
6792+
/*
6793+
* safety check: do not allow toasted storage modes unless column datatype
6794+
* is TOAST-aware.
6795+
*/
6796+
if (!(attribute.attstorage == TYPSTORAGE_PLAIN ||
6797+
TypeIsToastable(attribute.atttypid)))
6798+
ereport(ERROR,
6799+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6800+
errmsg("column data type %s can only have storage PLAIN",
6801+
format_type_be(attribute.atttypid))));
6802+
}
6803+
else
6804+
attribute.attstorage = tform->typstorage;
6805+
67736806
attribute.attcompression = GetAttributeCompression(typeOid,
67746807
colDef->compression);
67756808
attribute.attnotnull = colDef->is_not_null;
@@ -8238,7 +8271,6 @@ SetIndexStorageProperties(Relation rel, Relation attrelation,
82388271
static ObjectAddress
82398272
ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
82408273
{
8241-
char *storagemode;
82428274
char newstorage;
82438275
Relation attrelation;
82448276
HeapTuple tuple;
@@ -8247,24 +8279,8 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
82478279
ObjectAddress address;
82488280

82498281
Assert(IsA(newValue, String));
8250-
storagemode = strVal(newValue);
82518282

8252-
if (pg_strcasecmp(storagemode, "plain") == 0)
8253-
newstorage = TYPSTORAGE_PLAIN;
8254-
else if (pg_strcasecmp(storagemode, "external") == 0)
8255-
newstorage = TYPSTORAGE_EXTERNAL;
8256-
else if (pg_strcasecmp(storagemode, "extended") == 0)
8257-
newstorage = TYPSTORAGE_EXTENDED;
8258-
else if (pg_strcasecmp(storagemode, "main") == 0)
8259-
newstorage = TYPSTORAGE_MAIN;
8260-
else
8261-
{
8262-
ereport(ERROR,
8263-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8264-
errmsg("invalid storage type \"%s\"",
8265-
storagemode)));
8266-
newstorage = 0; /* keep compiler quiet */
8267-
}
8283+
newstorage = GetAttributeStorage(strVal(newValue));
82688284

82698285
attrelation = table_open(AttributeRelationId, RowExclusiveLock);
82708286

@@ -19239,3 +19255,24 @@ GetAttributeCompression(Oid atttypid, char *compression)
1923919255

1924019256
return cmethod;
1924119257
}
19258+
19259+
static char
19260+
GetAttributeStorage(const char *storagemode)
19261+
{
19262+
if (pg_strcasecmp(storagemode, "plain") == 0)
19263+
return TYPSTORAGE_PLAIN;
19264+
else if (pg_strcasecmp(storagemode, "external") == 0)
19265+
return TYPSTORAGE_EXTERNAL;
19266+
else if (pg_strcasecmp(storagemode, "extended") == 0)
19267+
return TYPSTORAGE_EXTENDED;
19268+
else if (pg_strcasecmp(storagemode, "main") == 0)
19269+
return TYPSTORAGE_MAIN;
19270+
else
19271+
{
19272+
ereport(ERROR,
19273+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
19274+
errmsg("invalid storage type \"%s\"",
19275+
storagemode)));
19276+
return 0; /* keep compiler quiet */
19277+
}
19278+
}

src/backend/parser/gram.y

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
582582

583583
%type <node> TableConstraint TableLikeClause
584584
%type <ival> TableLikeOptionList TableLikeOption
585-
%type <str> column_compression opt_column_compression
585+
%type <str> column_compression opt_column_compression opt_column_storage
586586
%type <list> ColQualList
587587
%type <node> ColConstraint ColConstraintElem ConstraintAttr
588588
%type <ival> key_match
@@ -2318,7 +2318,7 @@ alter_table_cmd:
23182318
$$ = (Node *)n;
23192319
}
23202320
/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
2321-
| ALTER opt_column ColId SET STORAGE ColId
2321+
| ALTER opt_column ColId SET STORAGE name
23222322
{
23232323
AlterTableCmd *n = makeNode(AlterTableCmd);
23242324
n->subtype = AT_SetStorage;
@@ -3494,12 +3494,13 @@ TypedTableElement:
34943494
| TableConstraint { $$ = $1; }
34953495
;
34963496

3497-
columnDef: ColId Typename opt_column_compression create_generic_options ColQualList
3497+
columnDef: ColId Typename opt_column_storage opt_column_compression create_generic_options ColQualList
34983498
{
34993499
ColumnDef *n = makeNode(ColumnDef);
35003500
n->colname = $1;
35013501
n->typeName = $2;
3502-
n->compression = $3;
3502+
n->storage_name = $3;
3503+
n->compression = $4;
35033504
n->inhcount = 0;
35043505
n->is_local = true;
35053506
n->is_not_null = false;
@@ -3508,8 +3509,8 @@ columnDef: ColId Typename opt_column_compression create_generic_options ColQualL
35083509
n->raw_default = NULL;
35093510
n->cooked_default = NULL;
35103511
n->collOid = InvalidOid;
3511-
n->fdwoptions = $4;
3512-
SplitColQualList($5, &n->constraints, &n->collClause,
3512+
n->fdwoptions = $5;
3513+
SplitColQualList($6, &n->constraints, &n->collClause,
35133514
yyscanner);
35143515
n->location = @1;
35153516
$$ = (Node *)n;
@@ -3564,6 +3565,11 @@ opt_column_compression:
35643565
| /*EMPTY*/ { $$ = NULL; }
35653566
;
35663567

3568+
opt_column_storage:
3569+
STORAGE ColId { $$ = $2; }
3570+
| /*EMPTY*/ { $$ = NULL; }
3571+
;
3572+
35673573
ColQualList:
35683574
ColQualList ColConstraint { $$ = lappend($1, $2); }
35693575
| /*EMPTY*/ { $$ = NIL; }

src/include/nodes/parsenodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ typedef struct ColumnDef
676676
bool is_not_null; /* NOT NULL constraint specified? */
677677
bool is_from_type; /* column definition came from table type */
678678
char storage; /* attstorage setting, or 0 for default */
679+
char *storage_name; /* attstorage setting name or NULL for default*/
679680
Node *raw_default; /* default value (untransformed parse tree) */
680681
Node *cooked_default; /* default value (transformed expr tree) */
681682
char identity; /* attidentity setting */

src/test/regress/expected/alter_table.out

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2244,7 +2244,7 @@ alter table recur1 add column f2 int;
22442244
alter table recur1 alter column f2 type recur2; -- fails
22452245
ERROR: composite type recur1 cannot be made a member of itself
22462246
-- SET STORAGE may need to add a TOAST table
2247-
create table test_storage (a text);
2247+
create table test_storage (a text, c text storage plain);
22482248
alter table test_storage alter a set storage plain;
22492249
alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table
22502250
alter table test_storage alter a set storage extended; -- re-add TOAST table
@@ -2256,6 +2256,9 @@ where oid = 'test_storage'::regclass;
22562256
t
22572257
(1 row)
22582258

2259+
--check STORAGE correctness
2260+
create table test_storage_failed (a text, b int storage extended);
2261+
ERROR: column data type integer can only have storage PLAIN
22592262
-- test that SET STORAGE propagates to index correctly
22602263
create index test_storage_idx on test_storage (b, a);
22612264
alter table test_storage alter column a set storage external;
@@ -2264,6 +2267,7 @@ alter table test_storage alter column a set storage external;
22642267
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
22652268
--------+---------+-----------+----------+---------+----------+--------------+-------------
22662269
a | text | | | | external | |
2270+
c | text | | | | plain | |
22672271
b | integer | | | 0 | plain | |
22682272
Indexes:
22692273
"test_storage_idx" btree (b, a)

src/test/regress/sql/alter_table.sql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1527,7 +1527,7 @@ alter table recur1 add column f2 int;
15271527
alter table recur1 alter column f2 type recur2; -- fails
15281528

15291529
-- SET STORAGE may need to add a TOAST table
1530-
create table test_storage (a text);
1530+
create table test_storage (a text, c text storage plain);
15311531
alter table test_storage alter a set storage plain;
15321532
alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table
15331533
alter table test_storage alter a set storage extended; -- re-add TOAST table
@@ -1536,6 +1536,9 @@ select reltoastrelid <> 0 as has_toast_table
15361536
from pg_class
15371537
where oid = 'test_storage'::regclass;
15381538

1539+
--check STORAGE correctness
1540+
create table test_storage_failed (a text, b int storage extended);
1541+
15391542
-- test that SET STORAGE propagates to index correctly
15401543
create index test_storage_idx on test_storage (b, a);
15411544
alter table test_storage alter column a set storage external;

0 commit comments

Comments
 (0)