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 }
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"/>.
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)
else if (attributeName != NameStr(att->attname))
namestrcpy(&(att->attname), attributeName);
- att->attstattarget = -1;
att->attcacheoff = -1;
att->atttypmod = typmod;
Assert(attributeName != NULL);
namestrcpy(&(att->attname), attributeName);
- att->attstattarget = -1;
att->attcacheoff = -1;
att->atttypmod = typmod;
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;
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);
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;
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 */
/* 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';
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;
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;
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 */
/*
* 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));
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),
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;
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
{
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
(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
if (colName)
{
- tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
+ tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
}
else
{
- tuple = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colNum);
+ tuple = SearchSysCacheAttNum(RelationGetRelid(rel), colNum);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
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);
%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
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);
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 [, ... ] ) */
}
;
+set_statistics_value:
+ SignedIconst { $$ = (Node *) makeInteger($1); }
+ | DEFAULT { $$ = NULL; }
+ ;
+
PartitionBoundSpec:
/* a HASH partition */
FOR VALUES WITH '(' hash_partbound ')'
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
*
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));
/*
* 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",
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202401111
+#define CATALOG_VERSION_NO 202401131
#endif
/* 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
- * that no value has been explicitly set for this column, so ANALYZE
- * should use the default setting.
+ * not wish to collect any stats about this column. A null value 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_);
* 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 */
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,
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;