mirror of
https://github.com/postgres/postgres.git
synced 2025-08-22 21:53:06 +03:00
Replace ALTER TABLE ... SET STATISTICS DISTINCT with a more general mechanism.
Attributes can now have options, just as relations and tablespaces do, and the reloptions code is used to parse, validate, and store them. For simplicity and because these options are not performance critical, we store them in a separate cache rather than the main relcache. Thanks to Alex Hunsaker for the review.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.31 2010/01/05 21:53:58 rhaas Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.32 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "commands/tablespace.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/attoptcache.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/memutils.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}}
|
||||
};
|
||||
@@ -1186,6 +1203,37 @@ index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
|
||||
return DatumGetByteaP(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.131 2010/01/02 16:57:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.132 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
* NOTES
|
||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||
@@ -338,8 +338,6 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||
return false;
|
||||
if (attr1->attstattarget != attr2->attstattarget)
|
||||
return false;
|
||||
if (attr1->attdistinct != attr2->attdistinct)
|
||||
return false;
|
||||
if (attr1->attlen != attr2->attlen)
|
||||
return false;
|
||||
if (attr1->attndims != attr2->attndims)
|
||||
@@ -362,7 +360,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)
|
||||
@@ -467,7 +465,6 @@ TupleDescInitEntry(TupleDesc desc,
|
||||
MemSet(NameStr(att->attname), 0, NAMEDATALEN);
|
||||
|
||||
att->attstattarget = -1;
|
||||
att->attdistinct = 0;
|
||||
att->attcacheoff = -1;
|
||||
att->atttypmod = typmod;
|
||||
|
||||
@@ -479,7 +476,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),
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.257 2010/01/20 09:16:23 heikki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.258 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -737,7 +737,6 @@ DefineAttr(char *name, char *type, int attnum)
|
||||
}
|
||||
|
||||
attrtypes[attnum]->attstattarget = -1;
|
||||
attrtypes[attnum]->attdistinct = 0;
|
||||
attrtypes[attnum]->attcacheoff = -1;
|
||||
attrtypes[attnum]->atttypmod = -1;
|
||||
attrtypes[attnum]->attislocal = true;
|
||||
|
@@ -10,7 +10,7 @@
|
||||
# Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
# Portions Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/genbki.pl,v 1.6 2010/01/06 22:02:45 tgl Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/genbki.pl,v 1.7 2010/01/22 16:40:18 rhaas Exp $
|
||||
#
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
@@ -200,7 +200,8 @@ foreach my $catname ( @{ $catalogs->{names} } )
|
||||
# Store schemapg entries for later.
|
||||
$row = emit_schemapg_row($row, grep { $bki_attr{$_} eq 'bool' } @attnames);
|
||||
push @{ $schemapg_entries{$table_name} },
|
||||
'{ ' . join(', ', map $row->{$_}, @attnames) . ' }';
|
||||
'{ ' . join(', ', grep { defined $_ }
|
||||
map $row->{$_}, @attnames) . ' }';
|
||||
}
|
||||
|
||||
# Generate entries for system attributes.
|
||||
@@ -351,14 +352,14 @@ sub emit_pgattr_row
|
||||
|
||||
# Add in default values for pg_attribute
|
||||
my %PGATTR_DEFAULTS = (
|
||||
attdistinct => '0',
|
||||
attcacheoff => '-1',
|
||||
atttypmod => '-1',
|
||||
atthasdef => 'f',
|
||||
attisdropped => 'f',
|
||||
attislocal => 't',
|
||||
attinhcount => '0',
|
||||
attacl => '_null_'
|
||||
attacl => '_null_',
|
||||
attoptions => '_null_'
|
||||
);
|
||||
return {%PGATTR_DEFAULTS, %row};
|
||||
}
|
||||
@@ -384,7 +385,11 @@ sub emit_schemapg_row
|
||||
$row->{attname} = q|{"| . $row->{attname} . q|"}|;
|
||||
$row->{attstorage} = q|'| . $row->{attstorage} . q|'|;
|
||||
$row->{attalign} = q|'| . $row->{attalign} . q|'|;
|
||||
$row->{attacl} = q|{ 0 }|;
|
||||
|
||||
# We don't emit initializers for the variable length fields at all.
|
||||
# Only the fixed-size portions of the descriptors are ever used.
|
||||
delete $row->{attacl};
|
||||
delete $row->{attoptions};
|
||||
|
||||
# Expand booleans from 'f'/'t' to 'false'/'true'.
|
||||
# Some values might be other macros (eg FLOAT4PASSBYVAL), don't change.
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.366 2010/01/06 05:18:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.367 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -116,40 +116,46 @@ Oid binary_upgrade_next_toast_relfilenode = InvalidOid;
|
||||
* Disadvantage: special cases will be all over the place.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The initializers below do not include the attoptions or attacl fields,
|
||||
* but that's OK - we're never going to reference anything beyond the
|
||||
* fixed-size portion of the structure anyway.
|
||||
*/
|
||||
|
||||
static FormData_pg_attribute a1 = {
|
||||
0, {"ctid"}, TIDOID, 0, 0, sizeof(ItemPointerData),
|
||||
0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
|
||||
SelfItemPointerAttributeNumber, 0, -1, -1,
|
||||
false, 'p', 's', true, false, false, true, 0, {0}
|
||||
false, 'p', 's', true, false, false, true, 0
|
||||
};
|
||||
|
||||
static FormData_pg_attribute a2 = {
|
||||
0, {"oid"}, OIDOID, 0, 0, sizeof(Oid),
|
||||
0, {"oid"}, OIDOID, 0, sizeof(Oid),
|
||||
ObjectIdAttributeNumber, 0, -1, -1,
|
||||
true, 'p', 'i', true, false, false, true, 0, {0}
|
||||
true, 'p', 'i', true, false, false, true, 0
|
||||
};
|
||||
|
||||
static FormData_pg_attribute a3 = {
|
||||
0, {"xmin"}, XIDOID, 0, 0, sizeof(TransactionId),
|
||||
0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
|
||||
MinTransactionIdAttributeNumber, 0, -1, -1,
|
||||
true, 'p', 'i', true, false, false, true, 0, {0}
|
||||
true, 'p', 'i', true, false, false, true, 0
|
||||
};
|
||||
|
||||
static FormData_pg_attribute a4 = {
|
||||
0, {"cmin"}, CIDOID, 0, 0, sizeof(CommandId),
|
||||
0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
|
||||
MinCommandIdAttributeNumber, 0, -1, -1,
|
||||
true, 'p', 'i', true, false, false, true, 0, {0}
|
||||
true, 'p', 'i', true, false, false, true, 0
|
||||
};
|
||||
|
||||
static FormData_pg_attribute a5 = {
|
||||
0, {"xmax"}, XIDOID, 0, 0, sizeof(TransactionId),
|
||||
0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
|
||||
MaxTransactionIdAttributeNumber, 0, -1, -1,
|
||||
true, 'p', 'i', true, false, false, true, 0, {0}
|
||||
true, 'p', 'i', true, false, false, true, 0
|
||||
};
|
||||
|
||||
static FormData_pg_attribute a6 = {
|
||||
0, {"cmax"}, CIDOID, 0, 0, sizeof(CommandId),
|
||||
0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
|
||||
MaxCommandIdAttributeNumber, 0, -1, -1,
|
||||
true, 'p', 'i', true, false, false, true, 0, {0}
|
||||
true, 'p', 'i', true, false, false, true, 0
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -159,9 +165,9 @@ static FormData_pg_attribute a6 = {
|
||||
* used in SQL.
|
||||
*/
|
||||
static FormData_pg_attribute a7 = {
|
||||
0, {"tableoid"}, OIDOID, 0, 0, sizeof(Oid),
|
||||
0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
|
||||
TableOidAttributeNumber, 0, -1, -1,
|
||||
true, 'p', 'i', true, false, false, true, 0, {0}
|
||||
true, 'p', 'i', true, false, false, true, 0
|
||||
};
|
||||
|
||||
static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
|
||||
@@ -482,13 +488,12 @@ CheckAttributeType(const char *attname, Oid atttypid)
|
||||
* Construct and insert a new tuple in pg_attribute.
|
||||
*
|
||||
* Caller has already opened and locked pg_attribute. new_attribute is the
|
||||
* attribute to insert (but we ignore its attacl, if indeed it has one).
|
||||
* attribute to insert (but we ignore attacl and attoptions, which are always
|
||||
* initialized to NULL).
|
||||
*
|
||||
* indstate is the index state for CatalogIndexInsert. It can be passed as
|
||||
* NULL, in which case we'll fetch the necessary info. (Don't do this when
|
||||
* inserting multiple attributes, because it's a tad more expensive.)
|
||||
*
|
||||
* We always initialize attacl to NULL (i.e., default permissions).
|
||||
*/
|
||||
void
|
||||
InsertPgAttributeTuple(Relation pg_attribute_rel,
|
||||
@@ -507,7 +512,6 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
|
||||
values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname);
|
||||
values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid);
|
||||
values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget);
|
||||
values[Anum_pg_attribute_attdistinct - 1] = Float4GetDatum(new_attribute->attdistinct);
|
||||
values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen);
|
||||
values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum);
|
||||
values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims);
|
||||
@@ -522,8 +526,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);
|
||||
|
||||
@@ -578,7 +583,6 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
||||
attr->attrelid = new_rel_oid;
|
||||
/* Make sure these are OK, too */
|
||||
attr->attstattarget = -1;
|
||||
attr->attdistinct = 0;
|
||||
attr->attcacheoff = -1;
|
||||
|
||||
InsertPgAttributeTuple(rel, attr, indstate);
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.330 2010/01/17 22:56:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.331 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -203,7 +203,6 @@ ConstructTupleDescriptor(Relation heapRelation,
|
||||
to->attnum = i + 1;
|
||||
|
||||
to->attstattarget = -1;
|
||||
to->attdistinct = 0;
|
||||
to->attcacheoff = -1;
|
||||
to->attnotnull = false;
|
||||
to->atthasdef = false;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.147 2010/01/02 16:57:36 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.148 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "storage/proc.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/attoptcache.h"
|
||||
#include "utils/datum.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/lsyscache.h"
|
||||
@@ -493,6 +494,8 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
|
||||
for (i = 0; i < attr_cnt; i++)
|
||||
{
|
||||
VacAttrStats *stats = vacattrstats[i];
|
||||
AttributeOpts *aopt =
|
||||
get_attribute_options(onerel->rd_id, stats->attr->attnum);
|
||||
|
||||
stats->rows = rows;
|
||||
stats->tupDesc = onerel->rd_att;
|
||||
@@ -501,9 +504,17 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt,
|
||||
numrows,
|
||||
totalrows);
|
||||
|
||||
/* If attdistinct is set, override with that value */
|
||||
if (stats->attr->attdistinct != 0)
|
||||
stats->stadistinct = stats->attr->attdistinct;
|
||||
/*
|
||||
* If the appropriate flavor of the n_distinct option is
|
||||
* specified, override with the corresponding value.
|
||||
*/
|
||||
if (aopt != NULL)
|
||||
{
|
||||
float8 n_distinct =
|
||||
inh ? aopt->n_distinct_inherited : aopt->n_distinct;
|
||||
if (n_distinct != 0.0)
|
||||
stats->stadistinct = n_distinct;
|
||||
}
|
||||
|
||||
MemoryContextResetAndDeleteChildren(col_context);
|
||||
}
|
||||
@@ -751,6 +762,9 @@ compute_index_stats(Relation onerel, double totalrows,
|
||||
for (i = 0; i < attr_cnt; i++)
|
||||
{
|
||||
VacAttrStats *stats = thisdata->vacattrstats[i];
|
||||
AttributeOpts *aopt =
|
||||
get_attribute_options(stats->attr->attrelid,
|
||||
stats->attr->attnum);
|
||||
|
||||
stats->exprvals = exprvals + i;
|
||||
stats->exprnulls = exprnulls + i;
|
||||
@@ -759,9 +773,15 @@ compute_index_stats(Relation onerel, double totalrows,
|
||||
ind_fetch_func,
|
||||
numindexrows,
|
||||
totalindexrows);
|
||||
/* If attdistinct is set, override with that value */
|
||||
if (stats->attr->attdistinct != 0)
|
||||
stats->stadistinct = stats->attr->attdistinct;
|
||||
|
||||
/*
|
||||
* If the n_distinct option is specified, it overrides the
|
||||
* above computation. For indices, we always use just
|
||||
* n_distinct, not n_distinct_inherited.
|
||||
*/
|
||||
if (aopt != NULL && aopt->n_distinct != 0.0)
|
||||
stats->stadistinct = aopt->n_distinct;
|
||||
|
||||
MemoryContextResetAndDeleteChildren(col_context);
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.317 2010/01/20 19:43:40 heikki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.318 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -284,10 +284,8 @@ static void ATPrepSetStatistics(Relation rel, const char *colName,
|
||||
Node *newValue);
|
||||
static void ATExecSetStatistics(Relation rel, const char *colName,
|
||||
Node *newValue);
|
||||
static void ATPrepSetDistinct(Relation rel, const char *colName,
|
||||
Node *newValue);
|
||||
static void ATExecSetDistinct(Relation rel, const char *colName,
|
||||
Node *newValue);
|
||||
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,
|
||||
@@ -2425,10 +2423,10 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
||||
ATPrepSetStatistics(rel, cmd->name, cmd->def);
|
||||
pass = AT_PASS_COL_ATTRS;
|
||||
break;
|
||||
case AT_SetDistinct: /* ALTER COLUMN SET STATISTICS DISTINCT */
|
||||
ATSimpleRecursion(wqueue, rel, cmd, recurse);
|
||||
/* Performs own permission checks */
|
||||
ATPrepSetDistinct(rel, cmd->name, cmd->def);
|
||||
case AT_SetOptions: /* ALTER COLUMN SET ( options ) */
|
||||
case AT_ResetOptions: /* ALTER COLUMN RESET ( options ) */
|
||||
ATSimplePermissionsRelationOrIndex(rel);
|
||||
/* This command never recurses */
|
||||
pass = AT_PASS_COL_ATTRS;
|
||||
break;
|
||||
case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
|
||||
@@ -2644,8 +2642,11 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
|
||||
ATExecSetStatistics(rel, cmd->name, cmd->def);
|
||||
break;
|
||||
case AT_SetDistinct: /* ALTER COLUMN SET STATISTICS DISTINCT */
|
||||
ATExecSetDistinct(rel, cmd->name, cmd->def);
|
||||
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);
|
||||
@@ -3682,7 +3683,6 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
||||
namestrcpy(&(attribute.attname), colDef->colname);
|
||||
attribute.atttypid = typeOid;
|
||||
attribute.attstattarget = (newattnum > 0) ? -1 : 0;
|
||||
attribute.attdistinct = 0;
|
||||
attribute.attlen = tform->typlen;
|
||||
attribute.attcacheoff = -1;
|
||||
attribute.atttypmod = typmod;
|
||||
@@ -4151,68 +4151,24 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue)
|
||||
heap_close(attrelation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TABLE ALTER COLUMN SET STATISTICS DISTINCT
|
||||
*/
|
||||
static void
|
||||
ATPrepSetDistinct(Relation rel, const char *colName, Node *newValue)
|
||||
ATExecSetOptions(Relation rel, const char *colName, Node *options,
|
||||
bool isReset)
|
||||
{
|
||||
/*
|
||||
* We do our own permission checking because (a) we want to allow SET
|
||||
* DISTINCT on indexes (for expressional index columns), and (b) we want
|
||||
* to allow SET DISTINCT 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)
|
||||
{
|
||||
float4 newdistinct;
|
||||
Relation attrelation;
|
||||
HeapTuple tuple;
|
||||
HeapTuple tuple,
|
||||
newtuple;
|
||||
Form_pg_attribute attrtuple;
|
||||
|
||||
switch (nodeTag(newValue))
|
||||
{
|
||||
case T_Integer:
|
||||
newdistinct = intVal(newValue);
|
||||
break;
|
||||
case T_Float:
|
||||
newdistinct = floatVal(newValue);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(newValue));
|
||||
newdistinct = 0; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Limit ndistinct to sane values
|
||||
*/
|
||||
if (newdistinct < -1.0)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("number of distinct values %g is too low",
|
||||
newdistinct)));
|
||||
}
|
||||
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 = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
|
||||
tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
@@ -4227,14 +4183,32 @@ ATExecSetDistinct(Relation rel, const char *colName, Node *newValue)
|
||||
errmsg("cannot alter system column \"%s\"",
|
||||
colName)));
|
||||
|
||||
attrtuple->attdistinct = newdistinct;
|
||||
/* 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);
|
||||
/* Validate new options */
|
||||
(void) attribute_reloptions(newOptions, true);
|
||||
|
||||
simple_heap_update(attrelation, &tuple->t_self, tuple);
|
||||
/* 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);
|
||||
|
||||
/* keep system catalog indexes current */
|
||||
CatalogUpdateIndexes(attrelation, tuple);
|
||||
|
||||
heap_freetuple(tuple);
|
||||
/* Update system catalog. */
|
||||
simple_heap_update(attrelation, &newtuple->t_self, newtuple);
|
||||
CatalogUpdateIndexes(attrelation, newtuple);
|
||||
heap_freetuple(newtuple);
|
||||
|
||||
heap_close(attrelation, RowExclusiveLock);
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.703 2010/01/06 05:31:13 itagaki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.704 2010/01/22 16:40:18 rhaas Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -1645,13 +1645,22 @@ alter_table_cmd:
|
||||
n->def = (Node *) makeInteger($6);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STATISTICS DISTINCT <NumericOnly> */
|
||||
| ALTER opt_column ColId SET STATISTICS DISTINCT NumericOnly
|
||||
/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */
|
||||
| ALTER opt_column ColId SET reloptions
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_SetDistinct;
|
||||
n->subtype = AT_SetOptions;
|
||||
n->name = $3;
|
||||
n->def = (Node *) $7;
|
||||
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> */
|
||||
|
4
src/backend/utils/cache/Makefile
vendored
4
src/backend/utils/cache/Makefile
vendored
@@ -4,7 +4,7 @@
|
||||
# Makefile for utils/cache
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.24 2010/01/05 21:53:59 rhaas Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.25 2010/01/22 16:40:19 rhaas Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -12,7 +12,7 @@ subdir = src/backend/utils/cache
|
||||
top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = catcache.o inval.o plancache.o relcache.o \
|
||||
OBJS = attoptcache.o catcache.o inval.o plancache.o relcache.o \
|
||||
spccache.o syscache.o lsyscache.o typcache.o ts_cache.o
|
||||
|
||||
include $(top_srcdir)/src/backend/common.mk
|
||||
|
Reference in New Issue
Block a user