attoptions-v1.patch
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/access/common/reloptions.c | 48 | 0 |
| src/backend/access/common/tupdesc.c | 2 | 2 |
| src/backend/catalog/genbki.pl | 3 | 1 |
| src/backend/catalog/heap.c | 8 | 7 |
| src/backend/commands/tablecmds.c | 103 | 0 |
| src/backend/parser/gram.y | 18 | 0 |
| src/include/access/reloptions.h | 3 | 1 |
| src/include/catalog/pg_attribute.h | 5 | 1 |
| src/include/catalog/pg_class.h | 1 | 1 |
| src/include/commands/tablecmds.h | 5 | 0 |
| src/include/nodes/parsenodes.h | 2 | 0 |
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 24480e3..596591c 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -21,6 +21,7 @@
#include "access/reloptions.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
+#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "nodes/makefuncs.h"
#include "utils/array.h"
@@ -196,6 +197,22 @@ static relopt_real realRelOpts[] =
},
-1, 0.0, DBL_MAX
},
+ {
+ {
+ "n_distinct",
+ "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
+ RELOPT_KIND_ATTRIBUTE
+ },
+ 0, -1.0, DBL_MAX
+ },
+ {
+ {
+ "n_distinct_inherited",
+ "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
+ RELOPT_KIND_ATTRIBUTE
+ },
+ 0, -1.0, DBL_MAX
+ },
/* list terminator */
{{NULL}}
};
@@ -1187,6 +1204,37 @@ index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
}
/*
+ * Option parser for attribute reloptions
+ */
+bytea *
+attribute_reloptions(Datum reloptions, bool validate)
+{
+ relopt_value *options;
+ AttributeOpts *aopts;
+ int numoptions;
+ static const relopt_parse_elt tab[] = {
+ {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
+ {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
+ };
+
+ options = parseRelOptions(reloptions, validate, RELOPT_KIND_ATTRIBUTE,
+ &numoptions);
+
+ /* if none set, we're done */
+ if (numoptions == 0)
+ return NULL;
+
+ aopts = allocateReloptStruct(sizeof(AttributeOpts), options, numoptions);
+
+ fillRelOptions((void *) aopts, sizeof(AttributeOpts), options, numoptions,
+ validate, tab, lengthof(tab));
+
+ pfree(options);
+
+ return (bytea *) aopts;
+}
+
+/*
* Option parser for tablespace reloptions
*/
bytea *
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index b54520f..8acdde8 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -362,7 +362,7 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
return false;
if (attr1->attinhcount != attr2->attinhcount)
return false;
- /* attacl is ignored, since it's not even present... */
+ /* attacl and attoptions are not even present... */
}
if (tupdesc1->constr != NULL)
@@ -479,7 +479,7 @@ TupleDescInitEntry(TupleDesc desc,
att->attisdropped = false;
att->attislocal = true;
att->attinhcount = 0;
- /* attacl is not set because it's not present in tupledescs */
+ /* attacl and attoptions are not present in tupledescs */
tuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(oidtypeid),
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 7a51b09..35a13e4 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -351,7 +351,8 @@ sub emit_pgattr_row
attisdropped => 'f',
attislocal => 't',
attinhcount => '0',
- attacl => '_null_'
+ attacl => '_null_',
+ attoptions => '_null_'
);
return {%PGATTR_DEFAULTS, %row};
}
@@ -378,6 +379,7 @@ sub emit_schemapg_row
$row->{attstorage} = q|'| . $row->{attstorage} . q|'|;
$row->{attalign} = q|'| . $row->{attalign} . q|'|;
$row->{attacl} = q|{ 0 }|;
+ $row->{attoptions} = q|{ 0 }|;
# Expand booleans from 'f'/'t' to 'false'/'true'.
# Some values might be other macros (eg FLOAT4PASSBYVAL), don't change.
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index ce890e1..085d945 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -116,37 +116,37 @@ static List *insert_ordered_unique_oid(List *list, Oid datum);
static FormData_pg_attribute a1 = {
0, {"ctid"}, TIDOID, 0, 0, sizeof(ItemPointerData),
SelfItemPointerAttributeNumber, 0, -1, -1,
- false, 'p', 's', true, false, false, true, 0, {0}
+ false, 'p', 's', true, false, false, true, 0, {0}, {0}
};
static FormData_pg_attribute a2 = {
0, {"oid"}, OIDOID, 0, 0, sizeof(Oid),
ObjectIdAttributeNumber, 0, -1, -1,
- true, 'p', 'i', true, false, false, true, 0, {0}
+ true, 'p', 'i', true, false, false, true, 0, {0}, {0}
};
static FormData_pg_attribute a3 = {
0, {"xmin"}, XIDOID, 0, 0, sizeof(TransactionId),
MinTransactionIdAttributeNumber, 0, -1, -1,
- true, 'p', 'i', true, false, false, true, 0, {0}
+ true, 'p', 'i', true, false, false, true, 0, {0}, {0}
};
static FormData_pg_attribute a4 = {
0, {"cmin"}, CIDOID, 0, 0, sizeof(CommandId),
MinCommandIdAttributeNumber, 0, -1, -1,
- true, 'p', 'i', true, false, false, true, 0, {0}
+ true, 'p', 'i', true, false, false, true, 0, {0}, {0}
};
static FormData_pg_attribute a5 = {
0, {"xmax"}, XIDOID, 0, 0, sizeof(TransactionId),
MaxTransactionIdAttributeNumber, 0, -1, -1,
- true, 'p', 'i', true, false, false, true, 0, {0}
+ true, 'p', 'i', true, false, false, true, 0, {0}, {0}
};
static FormData_pg_attribute a6 = {
0, {"cmax"}, CIDOID, 0, 0, sizeof(CommandId),
MaxCommandIdAttributeNumber, 0, -1, -1,
- true, 'p', 'i', true, false, false, true, 0, {0}
+ true, 'p', 'i', true, false, false, true, 0, {0}, {0}
};
/*
@@ -519,8 +519,9 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
- /* start out with empty permissions */
+ /* start out with empty permissions and empty options */
nulls[Anum_pg_attribute_attacl - 1] = true;
+ nulls[Anum_pg_attribute_attoptions - 1] = true;
tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 75f65ba..54f321f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -288,6 +288,10 @@ static void ATPrepSetDistinct(Relation rel, const char *colName,
Node *newValue);
static void ATExecSetDistinct(Relation rel, const char *colName,
Node *newValue);
+static void ATPrepSetOptions(Relation rel, const char *colName,
+ Node *options);
+static void ATExecSetOptions(Relation rel, const char *colName,
+ Node *options, bool isReset);
static void ATExecSetStorage(Relation rel, const char *colName,
Node *newValue);
static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
@@ -2431,6 +2435,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
ATPrepSetDistinct(rel, cmd->name, cmd->def);
pass = AT_PASS_COL_ATTRS;
break;
+ case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
+ case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
+ ATSimpleRecursion(wqueue, rel, cmd, recurse);
+ /* Performs own permission checks */
+ ATPrepSetOptions(rel, cmd->name, cmd->def);
+ pass = AT_PASS_COL_ATTRS;
+ break;
case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
ATSimplePermissions(rel, false);
ATSimpleRecursion(wqueue, rel, cmd, recurse);
@@ -2648,6 +2659,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
case AT_SetDistinct: /* ALTER COLUMN SET STATISTICS DISTINCT */
ATExecSetDistinct(rel, cmd->name, cmd->def);
break;
+ case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
+ ATExecSetOptions(rel, cmd->name, cmd->def, false);
+ break;
+ case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
+ ATExecSetOptions(rel, cmd->name, cmd->def, true);
+ break;
case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
ATExecSetStorage(rel, cmd->name, cmd->def);
break;
@@ -4177,6 +4194,31 @@ ATPrepSetDistinct(Relation rel, const char *colName, Node *newValue)
RelationGetRelationName(rel));
}
+/*
+ * ALTER TABLE ALTER COLUMN SET ( options )
+ * ALTER TABLE ALTER COLUMN RESET ( options )
+ */
+static void
+ATPrepSetOptions(Relation rel, const char *colName, Node *options)
+{
+ /*
+ * We do our own permission checking because (a) we want to allow options
+ * to be set on indexes, and (b) we want to allow options to be set on
+ * system catalogs without requiring allowSystemTableMods to be turned on.
+ */
+ if (rel->rd_rel->relkind != RELKIND_RELATION &&
+ rel->rd_rel->relkind != RELKIND_INDEX)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a table or index",
+ RelationGetRelationName(rel))));
+
+ /* Permissions checks */
+ if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ RelationGetRelationName(rel));
+}
+
static void
ATExecSetDistinct(Relation rel, const char *colName, Node *newValue)
{
@@ -4240,6 +4282,67 @@ ATExecSetDistinct(Relation rel, const char *colName, Node *newValue)
heap_close(attrelation, RowExclusiveLock);
}
+static void
+ATExecSetOptions(Relation rel, const char *colName, Node *options,
+ bool isReset)
+{
+ Relation attrelation;
+ HeapTuple tuple,
+ newtuple;
+ Form_pg_attribute attrtuple;
+ Datum datum,
+ newOptions;
+ bool isnull;
+ Datum repl_val[Natts_pg_attribute];
+ bool repl_null[Natts_pg_attribute];
+ bool repl_repl[Natts_pg_attribute];
+
+ attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
+
+ tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
+
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ colName, RelationGetRelationName(rel))));
+ attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
+
+ if (attrtuple->attnum <= 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot alter system column \"%s\"",
+ colName)));
+
+ /* Generate new proposed attoptions (text array) */
+ Assert(IsA(options, List));
+ datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
+ &isnull);
+ newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
+ (List *) options, NULL, NULL, false,
+ isReset);
+ (void) attribute_reloptions(newOptions, true);
+
+ /* Build new tuple. */
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+ if (newOptions != (Datum) 0)
+ repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
+ else
+ repl_null[Anum_pg_attribute_attoptions - 1] = true;
+ repl_repl[Anum_pg_attribute_attoptions - 1] = true;
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
+ repl_val, repl_null, repl_repl);
+ ReleaseSysCache(tuple);
+
+ /* Update system catalog. */
+ simple_heap_update(attrelation, &newtuple->t_self, newtuple);
+ CatalogUpdateIndexes(attrelation, newtuple);
+ heap_freetuple(newtuple);
+
+ heap_close(attrelation, RowExclusiveLock);
+}
+
/*
* ALTER TABLE ALTER COLUMN SET STORAGE
*/
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7aa387e..49fff9f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -1654,6 +1654,24 @@ alter_table_cmd:
n->def = (Node *) $7;
$$ = (Node *)n;
}
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */
+ | ALTER opt_column ColId SET reloptions
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetOptions;
+ n->name = $3;
+ n->def = (Node *) $5;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */
+ | ALTER opt_column ColId RESET reloptions
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ResetOptions;
+ n->name = $3;
+ n->def = (Node *) $5;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
| ALTER opt_column ColId SET STORAGE ColId
{
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index a0087bc..db21390 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -40,7 +40,8 @@ typedef enum relopt_kind
RELOPT_KIND_HASH = (1 << 3),
RELOPT_KIND_GIN = (1 << 4),
RELOPT_KIND_GIST = (1 << 5),
- RELOPT_KIND_TABLESPACE = (1 << 6),
+ RELOPT_KIND_ATTRIBUTE = (1 << 6),
+ RELOPT_KIND_TABLESPACE = (1 << 7),
/* if you add a new kind, make sure you update "last_default" too */
RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_TABLESPACE,
/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
@@ -266,6 +267,7 @@ extern bytea *default_reloptions(Datum reloptions, bool validate,
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions,
bool validate);
+extern bytea *attribute_reloptions(Datum reloptions, bool validate);
extern bytea *tablespace_reloptions(Datum reloptions, bool validate);
#endif /* RELOPTIONS_H */
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 6fdc6b8..998418b 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -157,6 +157,9 @@ CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK
/* Column-level access permissions */
aclitem attacl[1];
+
+ /* Column-level options */
+ aclitem attoptions[1];
} FormData_pg_attribute;
/*
@@ -180,7 +183,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
* ----------------
*/
-#define Natts_pg_attribute 19
+#define Natts_pg_attribute 20
#define Anum_pg_attribute_attrelid 1
#define Anum_pg_attribute_attname 2
#define Anum_pg_attribute_atttypid 3
@@ -200,6 +203,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
#define Anum_pg_attribute_attislocal 17
#define Anum_pg_attribute_attinhcount 18
#define Anum_pg_attribute_attacl 19
+#define Anum_pg_attribute_attoptions 20
/* ----------------
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index c5b15f5..2f40198 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -128,7 +128,7 @@ typedef FormData_pg_class *Form_pg_class;
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f f 3 _null_ _null_ ));
DESCR("");
-DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 20 0 f f f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f f 3 _null_ _null_ ));
DESCR("");
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 8bc716a..276d1eb 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -17,6 +17,11 @@
#include "nodes/parsenodes.h"
#include "utils/relcache.h"
+typedef struct AttributeOpts
+{
+ float8 n_distinct;
+ float8 n_distinct_inherited;
+} AttributeOpts;
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e05f93b..32ba917 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1102,6 +1102,8 @@ typedef enum AlterTableType
AT_SetNotNull, /* alter column set not null */
AT_SetStatistics, /* alter column set statistics */
AT_SetDistinct, /* alter column set statistics distinct */
+ AT_SetOptions, /* alter column set ( options ) */
+ AT_ResetOptions, /* alter column reset ( options ) */
AT_SetStorage, /* alter column set storage */
AT_DropColumn, /* drop column */
AT_DropColumnRecurse, /* internal to commands/tablecmds.c */