On 10.01.24 14:16, Alvaro Herrera wrote:
Here is an updated patch rebased over 3e2e0d5ad7.
The 0001 patch stands on its own, but I also tacked on two additional WIP
patches that simplify some pg_attribute handling and make these kinds of
refactorings simpler in the future. See description in the patches.
I didn't look at 0002 and 0003, since they're marked as WIP. (But I did
like the removal that happens in 0003, so I hope these two also make it
to 17).
Here is an updated patch set. I have addressed your comments on 0001.
I looked again at 0002 and 0003 and I was quite happy with them, so I
just removed the WIP label and also added a few more code comments, but
otherwise didn't change anything.
Seems reasonable. Do we really need a catversion bump for this?
Yes, this changes the order of the fields in pg_attribute.
I like that we now have SET STATISTICS DEFAULT rather than -1 to reset
to default. Do we want to document that setting explicitly to -1
continues to have that behavior? (I would add something like "Setting
to a value of -1 is an obsolete spelling to get the same behavior."
after the phrase that explains DEFAULT in the ALTER TABLE manpage.)
done
I noticed that equalTupleDescs no longer compares attstattarget, and
this is because the field is not in TupleDesc anymore. I looked at the
callers of equalTupleDescs and I think this is exactly what we want
(precisely because attstattarget is no longer in TupleDesc.)
Yes, I had investigated that in some detail, and I think it's ok. I
think equalTupleDescs() is actually mostly useless and I plan to start a
separate discussion on that.
This changes the pg_attribute field attstattarget into a nullable field
in the variable-length part of the row.
I don't think we use "the variable-length part of the row" as a term
anywhere. We only have the variable-length columns, and we made a bit
of a mistake in using CATALOG_VARLEN to differentiate the part of the
catalogs that are not mapped to the structs (because at the time those
were in effect only the variable length fields). I think this is
largely not a problem, but let's be careful with how we word the related
comments. So:
Yeah, there are multiple ways to interpret this. There are fields with
varlena headers, but there are also fields that are not-fixed-length as
far as struct access to catalog tuples is concerned, and the two not the
same.
I think the comment next to "#ifdef CATALOG_VARLEN" is now a bit
misleading, because the field immediately below is effectively not
varlena. Maybe make it
#ifdef CATALOG_VARLEN /* nullable/varlena fields start here */
done
In RemoveAttributeById, a comment says
"Clear the other variable-length fields."
but this is no longer fully correct. Again maybe make it "... the other
nullable or variable-length fields".
done
In get_attstattarget() I think we should return 0 for dropped columns
without reading attstattarget, which is useless anyway, and if it did
happen to return non-null, it might cause us to do stuff, which would be
a waste.
I ended up deciding to get rid of get_attstattarget() altogether and
just do the fetching inline in examine_attribute(). Because the
previous API and what you are discussing here is over-designed, since
the only caller doesn't call it with dropped columns or system columns
anyway. This way these issues are contained in the ANALYZE code, not in
a very general place like lsyscache.c.
It's annoying that the new code in index_concurrently_swap() is more
verbose than the code being replaced, but it seems OK to me, since it
allows us to distinguish a null value in attstattarget from actual 0
without complicating the get_attstattarget API (which I think we would
have to do if we wanted to use it here.)
Yeah, this was annoying. Originally, I had it even more complicated,
because I was trying to check if the actual (non-null) values are the
same. But then I realized the new value is never set at this point. I
think what the code is actually about is clearer now. And of course the
0003 patch gets rid of it anyway.
From d937c26d8c471c999aa53c96dce86c68fad71a7a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 11 Jan 2024 10:09:02 +0100
Subject: [PATCH v3 1/3] Make attstattarget nullable
This changes the pg_attribute field attstattarget into a nullable
field in the variable-length part of the row. If no value is set by
the user for attstattarget, it is now null instead of previously -1.
This saves space in pg_attribute and tuple descriptors for most
practical scenarios. (ATTRIBUTE_FIXED_PART_SIZE is reduced from 108
to 104.) Also, null is the semantically more correct value.
The ANALYZE code internally continues to represent the default
statistics target by -1, so that that code can avoid having to deal
with null values. But that is now contained to the ANALYZE code.
Only the DDL code deals with attstattarget possibly null.
For system columns, the field is now always null. The ANALYZE code
skips system columns anyway.
To set a column's statistics target to the default value, the new
command form ALTER TABLE ... SET STATISTICS DEFAULT can be used. (SET
STATISTICS -1 still works.)
Discussion:
https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184...@eisentraut.org
TODO: catversion
---
doc/src/sgml/ref/alter_table.sgml | 10 +++--
src/backend/access/common/tupdesc.c | 4 --
src/backend/bootstrap/bootstrap.c | 1 -
src/backend/catalog/genbki.pl | 1 -
src/backend/catalog/heap.c | 18 ++++-----
src/backend/catalog/index.c | 21 ++++++++---
src/backend/commands/analyze.c | 21 ++++++++++-
src/backend/commands/tablecmds.c | 44 +++++++++++++++++-----
src/backend/parser/gram.y | 18 ++++++---
src/backend/utils/cache/lsyscache.c | 27 -------------
src/bin/pg_dump/pg_dump.c | 7 +++-
src/include/catalog/pg_attribute.h | 16 ++++----
src/include/commands/vacuum.h | 2 +-
src/include/utils/lsyscache.h | 1 -
src/test/regress/expected/create_index.out | 4 +-
15 files changed, 110 insertions(+), 85 deletions(-)
diff --git a/doc/src/sgml/ref/alter_table.sgml
b/doc/src/sgml/ref/alter_table.sgml
index eaada230248..9670671107e 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -51,7 +51,7 @@
ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ (
<replaceable>sequence_options</replaceable> ) ]
ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
{ SET GENERATED { ALWAYS | BY DEFAULT } | SET
<replaceable>sequence_option</replaceable> | RESTART [ [ WITH ] <replaceable
class="parameter">restart</replaceable> ] } [...]
ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
DROP IDENTITY [ IF EXISTS ]
- ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
SET STATISTICS <replaceable class="parameter">integer</replaceable>
+ ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
SET STATISTICS { <replaceable class="parameter">integer</replaceable> | DEFAULT
}
ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
SET ( <replaceable class="parameter">attribute_option</replaceable> =
<replaceable class="parameter">value</replaceable> [, ... ] )
ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
RESET ( <replaceable class="parameter">attribute_option</replaceable> [, ... ] )
ALTER [ COLUMN ] <replaceable class="parameter">column_name</replaceable>
SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT }
@@ -328,9 +328,11 @@ <title>Description</title>
This form
sets the per-column statistics-gathering target for subsequent
<link linkend="sql-analyze"><command>ANALYZE</command></link> operations.
- The target can be set in the range 0 to 10000; alternatively, set it
- to -1 to revert to using the system default statistics
- target (<xref linkend="guc-default-statistics-target"/>).
+ The target can be set in the range 0 to 10000. Set it
+ to <literal>DEFAULT</literal> to revert to using the system default
+ statistics target (<xref linkend="guc-default-statistics-target"/>).
+ (Setting to a value of -1 is an obsolete way spelling to get the same
+ outcome.)
For more information on the use of statistics by the
<productname>PostgreSQL</productname> query planner, refer to
<xref linkend="planner-stats"/>.
diff --git a/src/backend/access/common/tupdesc.c
b/src/backend/access/common/tupdesc.c
index 6e7ad79834f..bc80caee117 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -453,8 +453,6 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
return false;
if (attr1->atttypid != attr2->atttypid)
return false;
- if (attr1->attstattarget != attr2->attstattarget)
- return false;
if (attr1->attlen != attr2->attlen)
return false;
if (attr1->attndims != attr2->attndims)
@@ -639,7 +637,6 @@ TupleDescInitEntry(TupleDesc desc,
else if (attributeName != NameStr(att->attname))
namestrcpy(&(att->attname), attributeName);
- att->attstattarget = -1;
att->attcacheoff = -1;
att->atttypmod = typmod;
@@ -702,7 +699,6 @@ TupleDescInitBuiltinEntry(TupleDesc desc,
Assert(attributeName != NULL);
namestrcpy(&(att->attname), attributeName);
- att->attstattarget = -1;
att->attcacheoff = -1;
att->atttypmod = typmod;
diff --git a/src/backend/bootstrap/bootstrap.c
b/src/backend/bootstrap/bootstrap.c
index 55c53d01f87..141b25ddd7a 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -552,7 +552,6 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
if (OidIsValid(attrtypes[attnum]->attcollation))
attrtypes[attnum]->attcollation = C_COLLATION_OID;
- attrtypes[attnum]->attstattarget = -1;
attrtypes[attnum]->attcacheoff = -1;
attrtypes[attnum]->atttypmod = -1;
attrtypes[attnum]->attislocal = true;
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 531d7cd0d52..93553e8c3c4 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -840,7 +840,6 @@ sub gen_pg_attribute
my %row;
$row{attnum} = $attnum;
$row{attrelid} = $table->{relation_oid};
- $row{attstattarget} = '0';
morph_row_for_pgattr(\%row, $schema, $attr, 1);
print_bki_insert(\%row, $schema);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e80a90ef4c0..45a71081d42 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -749,14 +749,16 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1]
= BoolGetDatum(attrs->attisdropped);
slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] =
BoolGetDatum(attrs->attislocal);
slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1]
= Int16GetDatum(attrs->attinhcount);
- slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget -
1] = Int16GetDatum(attrs->attstattarget);
slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1]
= ObjectIdGetDatum(attrs->attcollation);
if (attoptions && attoptions[natts] != (Datum) 0)
slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] =
attoptions[natts];
else
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
- /* start out with empty permissions and empty options */
+ /*
+ * The remaining fields are not set for new columns.
+ */
+ slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget -
1] = true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] =
true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions -
1] = true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval -
1] = true;
@@ -818,9 +820,6 @@ AddNewAttributeTuples(Oid new_rel_oid,
indstate = CatalogOpenIndexes(rel);
- /* set stats detail level to a sane default */
- for (int i = 0; i < natts; i++)
- tupdesc->attrs[i].attstattarget = -1;
InsertPgAttributeTuples(rel, tupdesc, new_rel_oid, NULL, indstate);
/* add dependencies on their datatypes and collations */
@@ -1685,9 +1684,6 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
/* Remove any not-null constraint the column may have */
attStruct->attnotnull = false;
- /* We don't want to keep stats for it anymore */
- attStruct->attstattarget = 0;
-
/* Unset this so no one tries to look up the generation expression */
attStruct->attgenerated = '\0';
@@ -1704,9 +1700,11 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
/*
- * Clear the other variable-length fields. This saves some space in
- * pg_attribute and removes no longer useful information.
+ * Clear the other nullable fields. This saves some space in
pg_attribute
+ * and removes no longer useful information.
*/
+ nullsAtt[Anum_pg_attribute_attstattarget - 1] = true;
+ replacesAtt[Anum_pg_attribute_attstattarget - 1] = true;
nullsAtt[Anum_pg_attribute_attacl - 1] = true;
replacesAtt[Anum_pg_attribute_attacl - 1] = true;
nullsAtt[Anum_pg_attribute_attoptions - 1] = true;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 88f7994b5a6..fbef3d5382d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -325,7 +325,6 @@ ConstructTupleDescriptor(Relation heapRelation,
MemSet(to, 0, ATTRIBUTE_FIXED_PART_SIZE);
to->attnum = i + 1;
- to->attstattarget = -1;
to->attcacheoff = -1;
to->attislocal = true;
to->attcollation = (i < numkeyatts) ? collationIds[i] :
InvalidOid;
@@ -1780,10 +1779,12 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId,
const char *oldName)
while (HeapTupleIsValid((attrTuple = systable_getnext(scan))))
{
Form_pg_attribute att = (Form_pg_attribute)
GETSTRUCT(attrTuple);
+ HeapTuple tp;
+ Datum dat;
+ bool isnull;
Datum repl_val[Natts_pg_attribute];
bool repl_null[Natts_pg_attribute];
bool repl_repl[Natts_pg_attribute];
- int attstattarget;
HeapTuple newTuple;
/* Ignore dropped columns */
@@ -1793,10 +1794,18 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId,
const char *oldName)
/*
* Get attstattarget from the old index and refresh the
new value.
*/
- attstattarget = get_attstattarget(oldIndexId,
att->attnum);
+ tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(oldIndexId), Int16GetDatum(att->attnum));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for attribute
%d of relation %u",
+ att->attnum, oldIndexId);
+ dat = SysCacheGetAttr(ATTNUM, tp,
Anum_pg_attribute_attstattarget, &isnull);
+ ReleaseSysCache(tp);
- /* no need for a refresh if both match */
- if (attstattarget == att->attstattarget)
+ /*
+ * No need for a refresh if old index value is null.
(All new
+ * index values are null at this point.)
+ */
+ if (isnull)
continue;
memset(repl_val, 0, sizeof(repl_val));
@@ -1804,7 +1813,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId,
const char *oldName)
memset(repl_repl, false, sizeof(repl_repl));
repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
- repl_val[Anum_pg_attribute_attstattarget - 1] =
Int16GetDatum(attstattarget);
+ repl_val[Anum_pg_attribute_attstattarget - 1] = dat;
newTuple = heap_modify_tuple(attrTuple,
RelationGetDescr(pg_attribute),
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index deef865ce6d..a03495d6c95 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -1004,6 +1004,10 @@ static VacAttrStats *
examine_attribute(Relation onerel, int attnum, Node *index_expr)
{
Form_pg_attribute attr = TupleDescAttr(onerel->rd_att, attnum - 1);
+ int attstattarget;
+ HeapTuple atttuple;
+ Datum dat;
+ bool isnull;
HeapTuple typtuple;
VacAttrStats *stats;
int i;
@@ -1013,15 +1017,28 @@ examine_attribute(Relation onerel, int attnum, Node
*index_expr)
if (attr->attisdropped)
return NULL;
+ /*
+ * Get attstattarget value. Set to -1 if null. (Analyze functions
expect
+ * -1 to mean use default_statistics_target; see for example
+ * std_typanalyze.)
+ */
+ atttuple = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(RelationGetRelid(onerel)), Int16GetDatum(attnum));
+ if (!HeapTupleIsValid(atttuple))
+ elog(ERROR, "cache lookup failed for attribute %d of relation
%u",
+ attnum, RelationGetRelid(onerel));
+ dat = SysCacheGetAttr(ATTNUM, atttuple,
Anum_pg_attribute_attstattarget, &isnull);
+ attstattarget = isnull ? -1 : DatumGetInt16(dat);
+ ReleaseSysCache(atttuple);
+
/* Don't analyze column if user has specified not to */
- if (attr->attstattarget == 0)
+ if (attstattarget == 0)
return NULL;
/*
* Create the VacAttrStats struct.
*/
stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats));
- stats->attstattarget = attr->attstattarget;
+ stats->attstattarget = attstattarget;
/*
* When analyzing an expression index, believe the expression tree's
type
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2822b2bb440..86a70599062 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7143,7 +7143,6 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
Relation rel,
attribute.attrelid = myrelid;
namestrcpy(&(attribute.attname), colDef->colname);
attribute.atttypid = typeOid;
- attribute.attstattarget = -1;
attribute.attlen = tform->typlen;
attribute.attnum = newattnum;
if (list_length(colDef->typeName->arrayBounds) > PG_INT16_MAX)
@@ -8588,10 +8587,14 @@ ATExecSetStatistics(Relation rel, const char *colName,
int16 colNum, Node *newVa
{
int newtarget;
Relation attrelation;
- HeapTuple tuple;
+ HeapTuple tuple,
+ newtuple;
Form_pg_attribute attrtuple;
AttrNumber attnum;
ObjectAddress address;
+ Datum repl_val[Natts_pg_attribute];
+ bool repl_null[Natts_pg_attribute];
+ bool repl_repl[Natts_pg_attribute];
/*
* We allow referencing columns by numbers only for indexes, since table
@@ -8604,8 +8607,18 @@ ATExecSetStatistics(Relation rel, const char *colName,
int16 colNum, Node *newVa
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot refer to non-index column by
number")));
- Assert(IsA(newValue, Integer));
- newtarget = intVal(newValue);
+ if (newValue)
+ {
+ Assert(IsA(newValue, Integer));
+ newtarget = intVal(newValue);
+ }
+ else
+ {
+ /*
+ * -1 was used in previous versions to represent the default
setting
+ */
+ newtarget = -1;
+ }
/*
* Limit target to a sane range
@@ -8630,7 +8643,7 @@ ATExecSetStatistics(Relation rel, const char *colName,
int16 colNum, Node *newVa
if (colName)
{
- tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel),
colName);
+ tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
@@ -8640,7 +8653,7 @@ ATExecSetStatistics(Relation rel, const char *colName,
int16 colNum, Node *newVa
}
else
{
- tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
+ tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
@@ -8674,16 +8687,27 @@ ATExecSetStatistics(Relation rel, const char *colName,
int16 colNum, Node *newVa
errhint("Alter statistics on table
column instead.")));
}
- attrtuple->attstattarget = newtarget;
-
- CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
+ /* Build new tuple. */
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+ if (newtarget != -1)
+ repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
+ else
+ repl_null[Anum_pg_attribute_attstattarget - 1] = true;
+ repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
+ repl_val,
repl_null, repl_repl);
+ CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple);
InvokeObjectPostAlterHook(RelationRelationId,
RelationGetRelid(rel),
attrtuple->attnum);
ObjectAddressSubSet(address, RelationRelationId,
RelationGetRelid(rel), attnum);
- heap_freetuple(tuple);
+
+ heap_freetuple(newtuple);
+
+ ReleaseSysCache(tuple);
table_close(attrelation, RowExclusiveLock);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6b88096e8e1..3460fea56ba 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -337,6 +337,7 @@ static Node *makeRecursiveViewSelect(char *relname, List
*aliases, Node *query);
%type <list> alter_table_cmds alter_type_cmds
%type <list> alter_identity_column_option_list
%type <defelt> alter_identity_column_option
+%type <node> set_statistics_value
%type <list> createdb_opt_list createdb_opt_items copy_opt_list
transaction_mode_list
@@ -2446,18 +2447,18 @@ alter_table_cmd:
n->missing_ok = true;
$$ = (Node *) n;
}
- /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET
STATISTICS <SignedIconst> */
- | ALTER opt_column ColId SET STATISTICS SignedIconst
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET
STATISTICS */
+ | ALTER opt_column ColId SET STATISTICS
set_statistics_value
{
AlterTableCmd *n =
makeNode(AlterTableCmd);
n->subtype = AT_SetStatistics;
n->name = $3;
- n->def = (Node *) makeInteger($6);
+ n->def = $6;
$$ = (Node *) n;
}
- /* ALTER TABLE <name> ALTER [COLUMN] <colnum> SET
STATISTICS <SignedIconst> */
- | ALTER opt_column Iconst SET STATISTICS SignedIconst
+ /* ALTER TABLE <name> ALTER [COLUMN] <colnum> SET
STATISTICS */
+ | ALTER opt_column Iconst SET STATISTICS
set_statistics_value
{
AlterTableCmd *n =
makeNode(AlterTableCmd);
@@ -2469,7 +2470,7 @@ alter_table_cmd:
n->subtype = AT_SetStatistics;
n->num = (int16) $3;
- n->def = (Node *) makeInteger($6);
+ n->def = $6;
$$ = (Node *) n;
}
/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET (
column_parameter = value [, ... ] ) */
@@ -3070,6 +3071,11 @@ alter_identity_column_option:
}
;
+set_statistics_value:
+ SignedIconst { $$ =
(Node *) makeInteger($1); }
+ | DEFAULT
{ $$ = NULL; }
+ ;
+
PartitionBoundSpec:
/* a HASH partition */
FOR VALUES WITH '(' hash_partbound ')'
diff --git a/src/backend/utils/cache/lsyscache.c
b/src/backend/utils/cache/lsyscache.c
index 8ec83561bfa..f730aa26c47 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -872,33 +872,6 @@ get_attnum(Oid relid, const char *attname)
return InvalidAttrNumber;
}
-/*
- * get_attstattarget
- *
- * Given the relation id and the attribute number,
- * return the "attstattarget" field from the attribute relation.
- *
- * Errors if not found.
- */
-int
-get_attstattarget(Oid relid, AttrNumber attnum)
-{
- HeapTuple tp;
- Form_pg_attribute att_tup;
- int result;
-
- tp = SearchSysCache2(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum));
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "cache lookup failed for attribute %d of relation
%u",
- attnum, relid);
- att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- result = att_tup->attstattarget;
- ReleaseSysCache(tp);
- return result;
-}
-
/*
* get_attgenerated
*
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 22d1e6cf922..d4a888f5f13 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -8925,7 +8925,10 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int
numTables)
tbinfo->dobj.name);
tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r,
i_attname));
tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r,
i_atttypname));
- tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r,
i_attstattarget));
+ if (PQgetisnull(res, r, i_attstattarget))
+ tbinfo->attstattarget[j] = -1;
+ else
+ tbinfo->attstattarget[j] = atoi(PQgetvalue(res,
r, i_attstattarget));
tbinfo->attstorage[j] = *(PQgetvalue(res, r,
i_attstorage));
tbinfo->typstorage[j] = *(PQgetvalue(res, r,
i_typstorage));
tbinfo->attidentity[j] = *(PQgetvalue(res, r,
i_attidentity));
@@ -16507,7 +16510,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
/*
* Dump per-column statistics information. We only
issue an ALTER
* TABLE statement if the attstattarget entry for this
column is
- * non-negative (i.e. it's not the default value)
+ * not the default value.
*/
if (tbinfo->attstattarget[j] >= 0)
appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s
ALTER COLUMN %s SET STATISTICS %d;\n",
diff --git a/src/include/catalog/pg_attribute.h
b/src/include/catalog/pg_attribute.h
index 7f4d308e8dd..1a487441e50 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -158,22 +158,22 @@ CATALOG(pg_attribute,1249,AttributeRelationId)
BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
/* Number of times inherited from direct parent relation(s) */
int16 attinhcount BKI_DEFAULT(0);
+ /* attribute's collation, if any */
+ Oid attcollation BKI_LOOKUP_OPT(pg_collation);
+
+#ifdef CATALOG_VARLEN /* variable-length/nullable fields
start here */
+ /* NOTE: The following fields are not present in tuple descriptors. */
+
/*
* attstattarget is the target number of statistics datapoints to
collect
* during VACUUM ANALYZE of this column. A zero here indicates that we
do
- * not wish to collect any stats about this column. A "-1" here
indicates
+ * not wish to collect any stats about this column. A NULL here
indicates
* that no value has been explicitly set for this column, so ANALYZE
* should use the default setting.
*
* int16 is sufficient for the current max value
(MAX_STATISTICS_TARGET).
*/
- int16 attstattarget BKI_DEFAULT(-1);
-
- /* attribute's collation, if any */
- Oid attcollation BKI_LOOKUP_OPT(pg_collation);
-
-#ifdef CATALOG_VARLEN /* variable-length fields start here */
- /* NOTE: The following fields are not present in tuple descriptors. */
+ int16 attstattarget BKI_DEFAULT(_null_) BKI_FORCE_NULL;
/* Column-level access permissions */
aclitem attacl[1] BKI_DEFAULT(_null_);
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 5cacefc7670..7f623b37fdc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -121,7 +121,7 @@ typedef struct VacAttrStats
* than the underlying column/expression. Therefore, use these fields
for
* information about the datatype being fed to the typanalyze function.
*/
- int attstattarget;
+ int attstattarget; /* -1 to use default */
Oid attrtypid; /* type of data being
analyzed */
int32 attrtypmod; /* typmod of data being
analyzed */
Form_pg_type attrtype; /* copy of pg_type row for attrtypid */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index be9ed70e841..e4a200b00ec 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -90,7 +90,6 @@ extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype,
Oid righttype,
int16 procnum);
extern char *get_attname(Oid relid, AttrNumber attnum, bool missing_ok);
extern AttrNumber get_attnum(Oid relid, const char *attname);
-extern int get_attstattarget(Oid relid, AttrNumber attnum);
extern char get_attgenerated(Oid relid, AttrNumber attnum);
extern Oid get_atttype(Oid relid, AttrNumber attnum);
extern void get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
diff --git a/src/test/regress/expected/create_index.out
b/src/test/regress/expected/create_index.out
index 446cfa678b7..79fa117cb54 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2707,8 +2707,8 @@ SELECT attrelid::regclass, attnum, attstattarget
attrelid | attnum | attstattarget
---------------------------+--------+---------------
concur_exprs_index_expr | 1 | 100
- concur_exprs_index_pred | 1 | -1
- concur_exprs_index_pred_2 | 1 | -1
+ concur_exprs_index_pred | 1 |
+ concur_exprs_index_pred_2 | 1 |
(3 rows)
DROP TABLE concur_exprs_tab;
base-commit: 6f97ef05d62a9c4ed5c53e98ac8a44cf3e0a2780
--
2.43.0
From 0cb841fd3d6ded93a54f499b328b49e63ad1541f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 11 Jan 2024 10:26:04 +0100
Subject: [PATCH v3 2/3] Generalize handling of nullable pg_attribute columns
in DDL
DDL code uses tuple descriptors to pass around pg_attribute values
during table and index creation. But tuple descriptors don't include
the variable-length/nullable columns of pg_attribute, so they have to
be handled separately. Right now, the attoptions field is handled in
a one-off way with a separate argument passed to
InsertPgAttributeTuples(). The other affected fields of pg_attribute
are right now not needed at relation creation time.
The goal of this patch is to generalize this to allow handling
additional variable-length/nullable columns of pg_attribute in a
similar manner. For that, create a new struct
Form_pg_attribute_extra, which is to be passed around in parallel to
the tuple descriptor and optionally supplies the additional columns.
Right now, this struct only contains one field for attoptions, so no
functionality is actually changed by this.
Discussion:
https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184...@eisentraut.org
---
src/backend/catalog/heap.c | 12 +++++++++---
src/backend/catalog/index.c | 16 +++++++++++++++-
src/include/catalog/heap.h | 2 +-
src/include/catalog/pg_attribute.h | 15 +++++++++++++++
src/tools/pgindent/typedefs.list | 2 ++
5 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 45a71081d42..e0fa12a0a96 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -697,7 +697,7 @@ void
InsertPgAttributeTuples(Relation pg_attribute_rel,
TupleDesc tupdesc,
Oid new_rel_oid,
- const Datum *attoptions,
+ const
FormData_pg_attribute_extra tupdesc_extra[],
CatalogIndexState indstate)
{
TupleTableSlot **slot;
@@ -719,6 +719,7 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
while (natts < tupdesc->natts)
{
Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts);
+ const FormData_pg_attribute_extra *attrs_extra = tupdesc_extra
? &tupdesc_extra[natts] : NULL;
ExecClearTuple(slot[slotCount]);
@@ -750,10 +751,15 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] =
BoolGetDatum(attrs->attislocal);
slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1]
= Int16GetDatum(attrs->attinhcount);
slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1]
= ObjectIdGetDatum(attrs->attcollation);
- if (attoptions && attoptions[natts] != (Datum) 0)
-
slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] =
attoptions[natts];
+ if (attrs_extra)
+ {
+
slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] =
attrs_extra->attoptions.value;
+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] =
attrs_extra->attoptions.isnull;
+ }
else
+ {
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
+ }
/*
* The remaining fields are not set for new columns.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index fbef3d5382d..d14e42ad8bb 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -517,6 +517,20 @@ AppendAttributeTuples(Relation indexRelation, const Datum
*attopts)
Relation pg_attribute;
CatalogIndexState indstate;
TupleDesc indexTupDesc;
+ FormData_pg_attribute_extra *attrs_extra = NULL;
+
+ if (attopts)
+ {
+ attrs_extra = palloc0_array(FormData_pg_attribute_extra,
indexRelation->rd_att->natts);
+
+ for (int i = 0; i < indexRelation->rd_att->natts; i++)
+ {
+ if (attopts[i])
+ attrs_extra[i].attoptions.value = attopts[i];
+ else
+ attrs_extra[i].attoptions.isnull = true;
+ }
+ }
/*
* open the attribute relation and its indexes
@@ -530,7 +544,7 @@ AppendAttributeTuples(Relation indexRelation, const Datum
*attopts)
*/
indexTupDesc = RelationGetDescr(indexRelation);
- InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid,
attopts, indstate);
+ InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid,
attrs_extra, indstate);
CatalogCloseIndexes(indstate);
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 1d7f8380d90..1e694a40919 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -98,7 +98,7 @@ extern List *heap_truncate_find_FKs(List *relationIds);
extern void InsertPgAttributeTuples(Relation pg_attribute_rel,
TupleDesc tupdesc,
Oid
new_rel_oid,
- const
Datum *attoptions,
+ const
FormData_pg_attribute_extra tupdesc_extra[],
CatalogIndexState indstate);
extern void InsertPgClassTuple(Relation pg_class_desc,
diff --git a/src/include/catalog/pg_attribute.h
b/src/include/catalog/pg_attribute.h
index 1a487441e50..6258da3f683 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -208,6 +208,21 @@ CATALOG(pg_attribute,1249,AttributeRelationId)
BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
*/
typedef FormData_pg_attribute *Form_pg_attribute;
+/*
+ * FormData_pg_attribute_extra contains (some of) the fields that are not in
+ * FormData_pg_attribute because they are excluded by CATALOG_VARLEN. It is
+ * meant to be used by DDL code so that the combination of
+ * FormData_pg_attribute (often via tuple descriptor) and
+ * FormData_pg_attribute_extra can be used to pass around all the information
+ * about an attribute. Fields can be included here as needed.
+ */
+typedef struct FormData_pg_attribute_extra
+{
+ NullableDatum attoptions;
+} FormData_pg_attribute_extra;
+
+typedef FormData_pg_attribute_extra *Form_pg_attribute_extra;
+
DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnam_index, 2658,
AttributeRelidNameIndexId, pg_attribute, btree(attrelid oid_ops, attname
name_ops));
DECLARE_UNIQUE_INDEX_PKEY(pg_attribute_relid_attnum_index, 2659,
AttributeRelidNumIndexId, pg_attribute, btree(attrelid oid_ops, attnum
int2_ops));
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 5fd46b7bd1f..e811341ce06 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -792,6 +792,7 @@ FormData_pg_amop
FormData_pg_amproc
FormData_pg_attrdef
FormData_pg_attribute
+FormData_pg_attribute_extra
FormData_pg_auth_members
FormData_pg_authid
FormData_pg_cast
@@ -850,6 +851,7 @@ Form_pg_amop
Form_pg_amproc
Form_pg_attrdef
Form_pg_attribute
+Form_pg_attribute_extra
Form_pg_auth_members
Form_pg_authid
Form_pg_cast
--
2.43.0
From 5874bc06ecf6d3cbf5aa13a2559d3a78e7d79bc0 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 11 Jan 2024 10:30:13 +0100
Subject: [PATCH v3 3/3] Add attstattarget to Form_pg_attribute_extra
This allows setting attstattarget when a relation is created.
We make use of this by having index_concurrently_create_copy() copy
over the attstattarget values when the new index is created, instead
of having index_concurrently_swap() fix it up later.
Discussion:
https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184...@eisentraut.org
---
src/backend/catalog/heap.c | 5 +-
src/backend/catalog/index.c | 97 +++++++++---------------------
src/backend/catalog/toasting.c | 2 +-
src/backend/commands/indexcmds.c | 2 +-
src/include/catalog/index.h | 1 +
src/include/catalog/pg_attribute.h | 1 +
6 files changed, 36 insertions(+), 72 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e0fa12a0a96..d632fc00faf 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -753,18 +753,21 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1]
= ObjectIdGetDatum(attrs->attcollation);
if (attrs_extra)
{
+
slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] =
attrs_extra->attstattarget.value;
+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] =
attrs_extra->attstattarget.isnull;
+
slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] =
attrs_extra->attoptions.value;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] =
attrs_extra->attoptions.isnull;
}
else
{
+
slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
}
/*
* The remaining fields are not set for new columns.
*/
- slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget -
1] = true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] =
true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions -
1] = true;
slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval -
1] = true;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d14e42ad8bb..c0bfd731379 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -112,7 +112,7 @@ static TupleDesc ConstructTupleDescriptor(Relation
heapRelation,
const Oid *opclassIds);
static void InitializeAttributeOids(Relation indexRelation,
int
numatts, Oid indexoid);
-static void AppendAttributeTuples(Relation indexRelation, const Datum
*attopts);
+static void AppendAttributeTuples(Relation indexRelation, const Datum
*attopts, const NullableDatum *stattargets);
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
Oid
parentIndexId,
const IndexInfo
*indexInfo,
@@ -512,7 +512,7 @@ InitializeAttributeOids(Relation indexRelation,
* ----------------------------------------------------------------
*/
static void
-AppendAttributeTuples(Relation indexRelation, const Datum *attopts)
+AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const
NullableDatum *stattargets)
{
Relation pg_attribute;
CatalogIndexState indstate;
@@ -529,6 +529,11 @@ AppendAttributeTuples(Relation indexRelation, const Datum
*attopts)
attrs_extra[i].attoptions.value = attopts[i];
else
attrs_extra[i].attoptions.isnull = true;
+
+ if (stattargets)
+ attrs_extra[i].attstattarget = stattargets[i];
+ else
+ attrs_extra[i].attstattarget.isnull = true;
}
}
@@ -735,6 +740,7 @@ index_create(Relation heapRelation,
const Oid *opclassIds,
const Datum *opclassOptions,
const int16 *coloptions,
+ const NullableDatum *stattargets,
Datum reloptions,
bits16 flags,
bits16 constr_flags,
@@ -1029,7 +1035,7 @@ index_create(Relation heapRelation,
/*
* append ATTRIBUTE tuples for the index
*/
- AppendAttributeTuples(indexRelation, opclassOptions);
+ AppendAttributeTuples(indexRelation, opclassOptions, stattargets);
/* ----------------
* update pg_index
@@ -1308,6 +1314,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid
oldIndexId,
Datum *opclassOptions;
oidvector *indclass;
int2vector *indcoloptions;
+ NullableDatum *stattargets;
bool isnull;
List *indexColNames = NIL;
List *indexExprs = NIL;
@@ -1412,6 +1419,23 @@ index_concurrently_create_copy(Relation heapRelation,
Oid oldIndexId,
for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
opclassOptions[i] = get_attoptions(oldIndexId, i + 1);
+ /* Extra statistic targets for each attribute */
+ stattargets = palloc0_array(NullableDatum, newInfo->ii_NumIndexAttrs);
+ for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
+ {
+ HeapTuple tp;
+ Datum dat;
+
+ tp = SearchSysCache2(ATTNUM, ObjectIdGetDatum(oldIndexId),
Int16GetDatum(i + 1));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for attribute %d of
relation %u",
+ i + 1, oldIndexId);
+ dat = SysCacheGetAttr(ATTNUM, tp,
Anum_pg_attribute_attstattarget, &isnull);
+ ReleaseSysCache(tp);
+ stattargets[i].value = dat;
+ stattargets[i].isnull = isnull;
+ }
+
/*
* Now create the new index.
*
@@ -1433,6 +1457,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid
oldIndexId,
indclass->values,
opclassOptions,
indcoloptions->values,
+ stattargets,
reloptionsDatum,
INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
0,
@@ -1775,72 +1800,6 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId,
const char *oldName)
/* Copy data of pg_statistic from the old index to the new one */
CopyStatistics(oldIndexId, newIndexId);
- /* Copy pg_attribute.attstattarget for each index attribute */
- {
- HeapTuple attrTuple;
- Relation pg_attribute;
- SysScanDesc scan;
- ScanKeyData key[1];
-
- pg_attribute = table_open(AttributeRelationId,
RowExclusiveLock);
- ScanKeyInit(&key[0],
- Anum_pg_attribute_attrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(newIndexId));
- scan = systable_beginscan(pg_attribute,
AttributeRelidNumIndexId,
- true, NULL,
1, key);
-
- while (HeapTupleIsValid((attrTuple = systable_getnext(scan))))
- {
- Form_pg_attribute att = (Form_pg_attribute)
GETSTRUCT(attrTuple);
- HeapTuple tp;
- Datum dat;
- bool isnull;
- Datum repl_val[Natts_pg_attribute];
- bool repl_null[Natts_pg_attribute];
- bool repl_repl[Natts_pg_attribute];
- HeapTuple newTuple;
-
- /* Ignore dropped columns */
- if (att->attisdropped)
- continue;
-
- /*
- * Get attstattarget from the old index and refresh the
new value.
- */
- tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(oldIndexId), Int16GetDatum(att->attnum));
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "cache lookup failed for attribute
%d of relation %u",
- att->attnum, oldIndexId);
- dat = SysCacheGetAttr(ATTNUM, tp,
Anum_pg_attribute_attstattarget, &isnull);
- ReleaseSysCache(tp);
-
- /*
- * No need for a refresh if old index value is null.
(All new
- * index values are null at this point.)
- */
- if (isnull)
- continue;
-
- memset(repl_val, 0, sizeof(repl_val));
- memset(repl_null, false, sizeof(repl_null));
- memset(repl_repl, false, sizeof(repl_repl));
-
- repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
- repl_val[Anum_pg_attribute_attstattarget - 1] = dat;
-
- newTuple = heap_modify_tuple(attrTuple,
-
RelationGetDescr(pg_attribute),
-
repl_val, repl_null, repl_repl);
- CatalogTupleUpdate(pg_attribute, &newTuple->t_self,
newTuple);
-
- heap_freetuple(newTuple);
- }
-
- systable_endscan(scan);
- table_close(pg_attribute, RowExclusiveLock);
- }
-
/* Close relations */
table_close(pg_class, RowExclusiveLock);
table_close(pg_index, RowExclusiveLock);
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 05d945b34b7..bbdf74ebed3 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -326,7 +326,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid
toastIndexOid,
list_make2("chunk_id", "chunk_seq"),
BTREE_AM_OID,
rel->rd_rel->reltablespace,
- collationIds, opclassIds, NULL, coloptions,
(Datum) 0,
+ collationIds, opclassIds, NULL, coloptions,
NULL, (Datum) 0,
INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL);
table_close(toast_rel, NoLock);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 340248a3f29..c2416c11d61 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1193,7 +1193,7 @@ DefineIndex(Oid tableId,
stmt->oldNumber, indexInfo,
indexColNames,
accessMethodId, tablespaceId,
collationIds, opclassIds,
opclassOptions,
- coloptions, reloptions,
+ coloptions, NULL, reloptions,
flags, constr_flags,
allowSystemTableMods, !check_rights,
&createdConstraintId);
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 99dab5940bc..7d434f8e653 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -80,6 +80,7 @@ extern Oid index_create(Relation heapRelation,
const Oid *opclassIds,
const Datum *opclassOptions,
const int16 *coloptions,
+ const NullableDatum
*stattargets,
Datum reloptions,
bits16 flags,
bits16 constr_flags,
diff --git a/src/include/catalog/pg_attribute.h
b/src/include/catalog/pg_attribute.h
index 6258da3f683..c26058f8ab7 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -218,6 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
*/
typedef struct FormData_pg_attribute_extra
{
+ NullableDatum attstattarget;
NullableDatum attoptions;
} FormData_pg_attribute_extra;
--
2.43.0