Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/dependency.c230
-rw-r--r--src/backend/catalog/heap.c7
-rw-r--r--src/backend/catalog/index.c198
-rw-r--r--src/backend/catalog/pg_collation.c5
-rw-r--r--src/backend/catalog/pg_constraint.c2
-rw-r--r--src/backend/catalog/pg_depend.c47
-rw-r--r--src/backend/catalog/pg_type.c69
-rw-r--r--src/backend/commands/collationcmds.c104
-rw-r--r--src/backend/commands/statscmds.c2
-rw-r--r--src/backend/commands/tablecmds.c31
-rw-r--r--src/backend/nodes/copyfuncs.c14
-rw-r--r--src/backend/nodes/equalfuncs.c11
-rw-r--r--src/backend/optimizer/util/plancat.c9
-rw-r--r--src/backend/parser/gram.y26
-rw-r--r--src/backend/tcop/utility.c12
-rw-r--r--src/backend/utils/adt/pg_locale.c89
-rw-r--r--src/backend/utils/adt/pg_upgrade_support.c1
-rw-r--r--src/backend/utils/cache/relcache.c2
18 files changed, 277 insertions, 582 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 41093ea6aee..259cde33976 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -76,7 +76,6 @@
#include "rewrite/rewriteRemove.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
-#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
@@ -436,84 +435,6 @@ performMultipleDeletions(const ObjectAddresses *objects,
}
/*
- * Call a function for all objects that 'object' depend on. If the function
- * returns true, refobjversion will be updated in the catalog.
- */
-void
-visitDependenciesOf(const ObjectAddress *object,
- VisitDependenciesOfCB callback,
- void *userdata)
-{
- Relation depRel;
- ScanKeyData key[3];
- SysScanDesc scan;
- HeapTuple tup;
- ObjectAddress otherObject;
-
- ScanKeyInit(&key[0],
- Anum_pg_depend_classid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->classId));
- ScanKeyInit(&key[1],
- Anum_pg_depend_objid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(object->objectId));
- ScanKeyInit(&key[2],
- Anum_pg_depend_objsubid,
- BTEqualStrategyNumber, F_INT4EQ,
- Int32GetDatum(object->objectSubId));
-
- depRel = table_open(DependRelationId, RowExclusiveLock);
- scan = systable_beginscan(depRel, DependDependerIndexId, true,
- NULL, 3, key);
-
- while (HeapTupleIsValid(tup = systable_getnext(scan)))
- {
- Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
- char *new_version;
- Datum depversion;
- bool isnull;
-
- otherObject.classId = foundDep->refclassid;
- otherObject.objectId = foundDep->refobjid;
- otherObject.objectSubId = foundDep->refobjsubid;
-
- depversion = heap_getattr(tup, Anum_pg_depend_refobjversion,
- RelationGetDescr(depRel), &isnull);
-
- /* Does the callback want to update the version? */
- if (callback(&otherObject,
- isnull ? NULL : TextDatumGetCString(depversion),
- &new_version,
- userdata))
- {
- Datum values[Natts_pg_depend];
- bool nulls[Natts_pg_depend];
- bool replaces[Natts_pg_depend];
-
- memset(values, 0, sizeof(values));
- memset(nulls, false, sizeof(nulls));
- memset(replaces, false, sizeof(replaces));
-
- if (new_version)
- values[Anum_pg_depend_refobjversion - 1] =
- CStringGetTextDatum(new_version);
- else
- nulls[Anum_pg_depend_refobjversion - 1] = true;
- replaces[Anum_pg_depend_refobjversion - 1] = true;
-
- tup = heap_modify_tuple(tup, RelationGetDescr(depRel), values,
- nulls, replaces);
- CatalogTupleUpdate(depRel, &tup->t_self, tup);
-
- heap_freetuple(tup);
- }
- }
- systable_endscan(scan);
- table_close(depRel, RowExclusiveLock);
-}
-
-/*
* findDependentObjects - find all objects that depend on 'object'
*
* For every object that depends on the starting object, acquire a deletion
@@ -1640,38 +1561,6 @@ ReleaseDeletionLock(const ObjectAddress *object)
}
/*
- * Record dependencies on a list of collations, optionally with their current
- * version.
- */
-void
-recordDependencyOnCollations(ObjectAddress *myself,
- List *collations,
- bool record_version)
-{
- ObjectAddresses *addrs;
- ListCell *lc;
-
- if (list_length(collations) == 0)
- return;
-
- addrs = new_object_addresses();
- foreach(lc, collations)
- {
- ObjectAddress referenced;
-
- ObjectAddressSet(referenced, CollationRelationId, lfirst_oid(lc));
-
- add_exact_object_address(&referenced, addrs);
- }
-
- eliminate_duplicate_dependencies(addrs);
- recordMultipleDependencies(myself, addrs->refs, addrs->numrefs,
- DEPENDENCY_NORMAL, record_version);
-
- free_object_addresses(addrs);
-}
-
-/*
* recordDependencyOnExpr - find expression dependencies
*
* This is used to find the dependencies of rules, constraint expressions,
@@ -1705,10 +1594,8 @@ recordDependencyOnExpr(const ObjectAddress *depender,
/* And record 'em */
recordMultipleDependencies(depender,
- context.addrs->refs,
- context.addrs->numrefs,
- behavior,
- false);
+ context.addrs->refs, context.addrs->numrefs,
+ behavior);
free_object_addresses(context.addrs);
}
@@ -1735,8 +1622,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
Node *expr, Oid relId,
DependencyType behavior,
DependencyType self_behavior,
- bool reverse_self,
- bool record_version)
+ bool reverse_self)
{
find_expr_references_context context;
RangeTblEntry rte;
@@ -1795,10 +1681,8 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
/* Record the self-dependencies with the appropriate direction */
if (!reverse_self)
recordMultipleDependencies(depender,
- self_addrs->refs,
- self_addrs->numrefs,
- self_behavior,
- record_version);
+ self_addrs->refs, self_addrs->numrefs,
+ self_behavior);
else
{
/* Can't use recordMultipleDependencies, so do it the hard way */
@@ -1817,10 +1701,8 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
/* Record the external dependencies */
recordMultipleDependencies(depender,
- context.addrs->refs,
- context.addrs->numrefs,
- behavior,
- record_version);
+ context.addrs->refs, context.addrs->numrefs,
+ behavior);
free_object_addresses(context.addrs);
}
@@ -1835,17 +1717,8 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
* the datatype. However we do need a type dependency if there is no such
* indirect dependency, as for example in Const and CoerceToDomain nodes.
*
- * Collations are handled primarily by recording the inputcollid's of node
- * types that have them, as those are the ones that are semantically
- * significant during expression evaluation. We also record the collation of
- * CollateExpr nodes, since those will be needed to print such nodes even if
- * they don't really affect semantics. Collations of leaf nodes such as Vars
- * can be ignored on the grounds that if they're not default, they came from
- * the referenced object (e.g., a table column), so the dependency on that
- * object is enough. (Note: in a post-const-folding expression tree, a
- * CollateExpr's collation could have been absorbed into a Const or
- * RelabelType node. While ruleutils.c prints such collations for clarity,
- * we may ignore them here as they have no semantic effect.)
+ * Similarly, we don't need to create dependencies on collations except where
+ * the collation is being freshly introduced to the expression.
*/
static bool
find_expr_references_walker(Node *node,
@@ -1907,6 +1780,17 @@ find_expr_references_walker(Node *node,
context->addrs);
/*
+ * We must also depend on the constant's collation: it could be
+ * different from the datatype's, if a CollateExpr was const-folded to
+ * a simple constant. However we can save work in the most common
+ * case where the collation is "default", since we know that's pinned.
+ */
+ if (OidIsValid(con->constcollid) &&
+ con->constcollid != DEFAULT_COLLATION_OID)
+ add_object_address(OCLASS_COLLATION, con->constcollid, 0,
+ context->addrs);
+
+ /*
* If it's a regclass or similar literal referring to an existing
* object, add a reference to that object. (Currently, only the
* regclass and regconfig cases have any likely use, but we may as
@@ -1990,6 +1874,11 @@ find_expr_references_walker(Node *node,
/* A parameter must depend on the parameter's datatype */
add_object_address(OCLASS_TYPE, param->paramtype, 0,
context->addrs);
+ /* and its collation, just as for Consts */
+ if (OidIsValid(param->paramcollid) &&
+ param->paramcollid != DEFAULT_COLLATION_OID)
+ add_object_address(OCLASS_COLLATION, param->paramcollid, 0,
+ context->addrs);
}
else if (IsA(node, FuncExpr))
{
@@ -1997,9 +1886,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
context->addrs);
- if (OidIsValid(funcexpr->inputcollid))
- add_object_address(OCLASS_COLLATION, funcexpr->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, OpExpr))
@@ -2008,9 +1894,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
context->addrs);
- if (OidIsValid(opexpr->inputcollid))
- add_object_address(OCLASS_COLLATION, opexpr->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, DistinctExpr))
@@ -2019,9 +1902,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
context->addrs);
- if (OidIsValid(distinctexpr->inputcollid))
- add_object_address(OCLASS_COLLATION, distinctexpr->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, NullIfExpr))
@@ -2030,9 +1910,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
context->addrs);
- if (OidIsValid(nullifexpr->inputcollid))
- add_object_address(OCLASS_COLLATION, nullifexpr->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, ScalarArrayOpExpr))
@@ -2041,9 +1918,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
context->addrs);
- if (OidIsValid(opexpr->inputcollid))
- add_object_address(OCLASS_COLLATION, opexpr->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, Aggref))
@@ -2052,9 +1926,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
context->addrs);
- if (OidIsValid(aggref->inputcollid))
- add_object_address(OCLASS_COLLATION, aggref->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, WindowFunc))
@@ -2063,9 +1934,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_PROC, wfunc->winfnoid, 0,
context->addrs);
- if (OidIsValid(wfunc->inputcollid))
- add_object_address(OCLASS_COLLATION, wfunc->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, SubscriptingRef))
@@ -2110,6 +1978,11 @@ find_expr_references_walker(Node *node,
else
add_object_address(OCLASS_TYPE, fselect->resulttype, 0,
context->addrs);
+ /* the collation might not be referenced anywhere else, either */
+ if (OidIsValid(fselect->resultcollid) &&
+ fselect->resultcollid != DEFAULT_COLLATION_OID)
+ add_object_address(OCLASS_COLLATION, fselect->resultcollid, 0,
+ context->addrs);
}
else if (IsA(node, FieldStore))
{
@@ -2136,6 +2009,11 @@ find_expr_references_walker(Node *node,
/* since there is no function dependency, need to depend on type */
add_object_address(OCLASS_TYPE, relab->resulttype, 0,
context->addrs);
+ /* the collation might not be referenced anywhere else, either */
+ if (OidIsValid(relab->resultcollid) &&
+ relab->resultcollid != DEFAULT_COLLATION_OID)
+ add_object_address(OCLASS_COLLATION, relab->resultcollid, 0,
+ context->addrs);
}
else if (IsA(node, CoerceViaIO))
{
@@ -2144,6 +2022,11 @@ find_expr_references_walker(Node *node,
/* since there is no exposed function, need to depend on type */
add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
context->addrs);
+ /* the collation might not be referenced anywhere else, either */
+ if (OidIsValid(iocoerce->resultcollid) &&
+ iocoerce->resultcollid != DEFAULT_COLLATION_OID)
+ add_object_address(OCLASS_COLLATION, iocoerce->resultcollid, 0,
+ context->addrs);
}
else if (IsA(node, ArrayCoerceExpr))
{
@@ -2152,6 +2035,11 @@ find_expr_references_walker(Node *node,
/* as above, depend on type */
add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
context->addrs);
+ /* the collation might not be referenced anywhere else, either */
+ if (OidIsValid(acoerce->resultcollid) &&
+ acoerce->resultcollid != DEFAULT_COLLATION_OID)
+ add_object_address(OCLASS_COLLATION, acoerce->resultcollid, 0,
+ context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, ConvertRowtypeExpr))
@@ -2191,24 +2079,6 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
context->addrs);
}
- foreach(l, rcexpr->inputcollids)
- {
- Oid inputcollid = lfirst_oid(l);
-
- if (OidIsValid(inputcollid))
- add_object_address(OCLASS_COLLATION, inputcollid, 0,
- context->addrs);
- }
- /* fall through to examine arguments */
- }
- else if (IsA(node, MinMaxExpr))
- {
- MinMaxExpr *mmexpr = (MinMaxExpr *) node;
-
- /* minmaxtype will match one of the inputs, so no need to record it */
- if (OidIsValid(mmexpr->inputcollid))
- add_object_address(OCLASS_COLLATION, mmexpr->inputcollid, 0,
- context->addrs);
/* fall through to examine arguments */
}
else if (IsA(node, CoerceToDomain))
@@ -2255,7 +2125,8 @@ find_expr_references_walker(Node *node,
if (OidIsValid(wc->endInRangeFunc))
add_object_address(OCLASS_PROC, wc->endInRangeFunc, 0,
context->addrs);
- if (OidIsValid(wc->inRangeColl))
+ if (OidIsValid(wc->inRangeColl) &&
+ wc->inRangeColl != DEFAULT_COLLATION_OID)
add_object_address(OCLASS_COLLATION, wc->inRangeColl, 0,
context->addrs);
/* fall through to examine substructure */
@@ -2415,7 +2286,7 @@ find_expr_references_walker(Node *node,
{
Oid collid = lfirst_oid(ct);
- if (OidIsValid(collid))
+ if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
add_object_address(OCLASS_COLLATION, collid, 0,
context->addrs);
}
@@ -2437,7 +2308,7 @@ find_expr_references_walker(Node *node,
{
Oid collid = lfirst_oid(ct);
- if (OidIsValid(collid))
+ if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
add_object_address(OCLASS_COLLATION, collid, 0,
context->addrs);
}
@@ -2834,8 +2705,7 @@ record_object_address_dependencies(const ObjectAddress *depender,
eliminate_duplicate_dependencies(referenced);
recordMultipleDependencies(depender,
referenced->refs, referenced->numrefs,
- behavior,
- false);
+ behavior);
}
/*
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 42ff175bc80..431e62e3897 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2357,7 +2357,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
*/
recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
DEPENDENCY_AUTO,
- DEPENDENCY_AUTO, false, false);
+ DEPENDENCY_AUTO, false);
}
else
{
@@ -2367,7 +2367,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
*/
recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
DEPENDENCY_NORMAL,
- DEPENDENCY_NORMAL, false, false);
+ DEPENDENCY_NORMAL, false);
}
/*
@@ -3729,8 +3729,7 @@ StorePartitionKey(Relation rel,
RelationGetRelid(rel),
DEPENDENCY_NORMAL,
DEPENDENCY_INTERNAL,
- true /* reverse the self-deps */ ,
- false /* don't track versions */ );
+ true /* reverse the self-deps */ );
/*
* We must invalidate the relcache so that the next
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index a628b3281ce..8ded2b53d4c 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -54,7 +54,6 @@
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
-#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
@@ -78,7 +77,6 @@
#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
-#include "utils/pg_locale.h"
#include "utils/memutils.h"
#include "utils/pg_rusage.h"
#include "utils/rel.h"
@@ -1034,8 +1032,6 @@ index_create(Relation heapRelation,
ObjectAddress myself,
referenced;
ObjectAddresses *addrs;
- List *colls = NIL,
- *colls_no_version = NIL;
ObjectAddressSet(myself, RelationRelationId, indexRelationId);
@@ -1119,65 +1115,30 @@ index_create(Relation heapRelation,
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
}
- /* Get dependencies on collations for all index keys. */
- for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
- {
- Oid colloid = collationObjectId[i];
+ /* placeholder for normal dependencies */
+ addrs = new_object_addresses();
- if (OidIsValid(colloid))
- {
- Oid opclass = classObjectId[i];
+ /* Store dependency on collations */
- /*
- * The *_pattern_ops opclasses are special: they explicitly do
- * not depend on collation order so we can save some effort.
- *
- * XXX With more analysis, we could also skip version tracking
- * for some cases like hash indexes with deterministic
- * collations, because they will never need to order strings.
- */
- if (opclass == TEXT_BTREE_PATTERN_OPS_OID ||
- opclass == VARCHAR_BTREE_PATTERN_OPS_OID ||
- opclass == BPCHAR_BTREE_PATTERN_OPS_OID)
- colls_no_version = lappend_oid(colls_no_version, colloid);
- else
- colls = lappend_oid(colls, colloid);
- }
- else
+ /* The default collation is pinned, so don't bother recording it */
+ for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
+ {
+ if (OidIsValid(collationObjectId[i]) &&
+ collationObjectId[i] != DEFAULT_COLLATION_OID)
{
- Form_pg_attribute att = TupleDescAttr(indexTupDesc, i);
-
- Assert(i < indexTupDesc->natts);
-
- /*
- * Even though there is no top-level collation, there may be
- * collations affecting ordering inside types, so look there
- * too.
- */
- colls = list_concat(colls, GetTypeCollations(att->atttypid));
+ ObjectAddressSet(referenced, CollationRelationId,
+ collationObjectId[i]);
+ add_exact_object_address(&referenced, addrs);
}
}
- /*
- * If we have anything in both lists, keep just the versioned one to
- * avoid some duplication.
- */
- if (colls_no_version != NIL && colls != NIL)
- colls_no_version = list_difference_oid(colls_no_version, colls);
-
- /* Store the versioned and unversioned collation dependencies. */
- if (colls_no_version != NIL)
- recordDependencyOnCollations(&myself, colls_no_version, false);
- if (colls != NIL)
- recordDependencyOnCollations(&myself, colls, true);
-
/* Store dependency on operator classes */
- addrs = new_object_addresses();
for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
{
ObjectAddressSet(referenced, OperatorClassRelationId, classObjectId[i]);
add_exact_object_address(&referenced, addrs);
}
+
record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
@@ -1188,7 +1149,7 @@ index_create(Relation heapRelation,
(Node *) indexInfo->ii_Expressions,
heapRelationId,
DEPENDENCY_NORMAL,
- DEPENDENCY_AUTO, false, true);
+ DEPENDENCY_AUTO, false);
}
/* Store dependencies on anything mentioned in predicate */
@@ -1198,7 +1159,7 @@ index_create(Relation heapRelation,
(Node *) indexInfo->ii_Predicate,
heapRelationId,
DEPENDENCY_NORMAL,
- DEPENDENCY_AUTO, false, true);
+ DEPENDENCY_AUTO, false);
}
}
else
@@ -1277,130 +1238,6 @@ index_create(Relation heapRelation,
return indexRelationId;
}
-typedef struct do_collation_version_check_context
-{
- Oid relid;
- List *warned_colls;
-} do_collation_version_check_context;
-
-/*
- * Raise a warning if the recorded and current collation version don't match.
- * This is a callback for visitDependenciesOf().
- */
-static bool
-do_collation_version_check(const ObjectAddress *otherObject,
- const char *version,
- char **new_version,
- void *data)
-{
- do_collation_version_check_context *context = data;
- char *current_version;
-
- /* We only care about dependencies on collations with a version. */
- if (!version || otherObject->classId != CollationRelationId)
- return false;
-
- /* Ask the provider for the current version. Give up if unsupported. */
- current_version = get_collation_version_for_oid(otherObject->objectId,
- false);
- if (!current_version)
- return false;
-
- /*
- * We don't expect too many duplicates, but it's possible, and we don't
- * want to generate duplicate warnings.
- */
- if (list_member_oid(context->warned_colls, otherObject->objectId))
- return false;
-
- /* Do they match? */
- if (strcmp(current_version, version) != 0)
- {
- /*
- * The version has changed, probably due to an OS/library upgrade or
- * streaming replication between different OS/library versions.
- */
- ereport(WARNING,
- (errmsg("index \"%s\" depends on collation \"%s\" version \"%s\", but the current version is \"%s\"",
- get_rel_name(context->relid),
- get_collation_name(otherObject->objectId),
- version,
- current_version),
- errdetail("The index may be corrupted due to changes in sort order."),
- errhint("REINDEX to avoid the risk of corruption.")));
-
- /* Remember not to complain about this collation again. */
- context->warned_colls = lappend_oid(context->warned_colls,
- otherObject->objectId);
- }
-
- return false;
-}
-
-/* index_check_collation_versions
- * Check the collation version for all dependencies on the given index.
- */
-void
-index_check_collation_versions(Oid relid)
-{
- do_collation_version_check_context context;
- ObjectAddress object;
-
- /*
- * The callback needs the relid for error messages, and some scratch space
- * to avoid duplicate warnings.
- */
- context.relid = relid;
- context.warned_colls = NIL;
-
- object.classId = RelationRelationId;
- object.objectId = relid;
- object.objectSubId = 0;
-
- visitDependenciesOf(&object, &do_collation_version_check, &context);
-
- list_free(context.warned_colls);
-}
-
-/*
- * Update the version for collations. A callback for visitDependenciesOf().
- */
-static bool
-do_collation_version_update(const ObjectAddress *otherObject,
- const char *version,
- char **new_version,
- void *data)
-{
- Oid *coll = data;
-
- /* We only care about dependencies on collations with versions. */
- if (!version || otherObject->classId != CollationRelationId)
- return false;
-
- /* If we're only trying to update one collation, skip others. */
- if (OidIsValid(*coll) && otherObject->objectId != *coll)
- return false;
-
- *new_version = get_collation_version_for_oid(otherObject->objectId, false);
-
- return true;
-}
-
-/*
- * Record the current versions of one or all collations that an index depends
- * on. InvalidOid means all.
- */
-void
-index_update_collation_versions(Oid relid, Oid coll)
-{
- ObjectAddress object;
-
- object.classId = RelationRelationId;
- object.objectId = relid;
- object.objectSubId = 0;
- visitDependenciesOf(&object, &do_collation_version_update, &coll);
-}
-
/*
* index_concurrently_create_copy
*
@@ -1864,10 +1701,6 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId);
changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId);
- /* Now we have the old index's collation versions, so fix that. */
- CommandCounterIncrement();
- index_update_collation_versions(newIndexId, InvalidOid);
-
/*
* Copy over statistics from old to new index
*/
@@ -3921,9 +3754,6 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
/* Close rels, but keep locks */
index_close(iRel, NoLock);
table_close(heapRelation, NoLock);
-
- /* Record the current versions of all depended-on collations. */
- index_update_collation_versions(indexId, InvalidOid);
}
/*
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 40d98a334a6..19068b652a0 100644
--- a/src/backend/catalog/pg_collation.c
+++ b/src/backend/catalog/pg_collation.c
@@ -49,6 +49,7 @@ CollationCreate(const char *collname, Oid collnamespace,
bool collisdeterministic,
int32 collencoding,
const char *collcollate, const char *collctype,
+ const char *collversion,
bool if_not_exists,
bool quiet)
{
@@ -166,6 +167,10 @@ CollationCreate(const char *collname, Oid collnamespace,
values[Anum_pg_collation_collcollate - 1] = NameGetDatum(&name_collate);
namestrcpy(&name_ctype, collctype);
values[Anum_pg_collation_collctype - 1] = NameGetDatum(&name_ctype);
+ if (collversion)
+ values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion);
+ else
+ nulls[Anum_pg_collation_collversion - 1] = true;
tup = heap_form_tuple(tupDesc, values, nulls);
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 0081558c48a..a4e890020ff 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -362,7 +362,7 @@ CreateConstraintEntry(const char *constraintName,
*/
recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
DEPENDENCY_NORMAL,
- DEPENDENCY_NORMAL, false, true);
+ DEPENDENCY_NORMAL, false);
}
/* Post creation hook for new constraint */
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 1217c01b8ae..54688094f58 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -19,16 +19,13 @@
#include "access/table.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
-#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_extension.h"
#include "commands/extension.h"
#include "miscadmin.h"
-#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
-#include "utils/pg_locale.h"
#include "utils/rel.h"
@@ -47,24 +44,18 @@ recordDependencyOn(const ObjectAddress *depender,
const ObjectAddress *referenced,
DependencyType behavior)
{
- recordMultipleDependencies(depender, referenced, 1, behavior, false);
+ recordMultipleDependencies(depender, referenced, 1, behavior);
}
/*
* Record multiple dependencies (of the same kind) for a single dependent
* object. This has a little less overhead than recording each separately.
- *
- * If record_version is true, then a record is added even if the referenced
- * object is pinned, and the dependency version will be retrieved according to
- * the referenced object kind. For now, only collation version is
- * supported.
*/
void
recordMultipleDependencies(const ObjectAddress *depender,
const ObjectAddress *referenced,
int nreferenced,
- DependencyType behavior,
- bool record_version)
+ DependencyType behavior)
{
Relation dependDesc;
CatalogIndexState indstate;
@@ -103,30 +94,12 @@ recordMultipleDependencies(const ObjectAddress *depender,
slot_init_count = 0;
for (i = 0; i < nreferenced; i++, referenced++)
{
- char *version = NULL;
-
- if (record_version)
- {
- /* For now we only know how to deal with collations. */
- if (referenced->classId == CollationRelationId)
- {
- /* These are unversioned, so don't waste cycles on them. */
- if (referenced->objectId == C_COLLATION_OID ||
- referenced->objectId == POSIX_COLLATION_OID)
- continue;
-
- version = get_collation_version_for_oid(referenced->objectId,
- false);
- }
- }
-
/*
* If the referenced object is pinned by the system, there's no real
- * need to record dependencies on it, unless we need to record a
- * version. This saves lots of space in pg_depend, so it's worth the
- * time taken to check.
+ * need to record dependencies on it. This saves lots of space in
+ * pg_depend, so it's worth the time taken to check.
*/
- if (version == NULL && isObjectPinned(referenced, dependDesc))
+ if (isObjectPinned(referenced, dependDesc))
continue;
if (slot_init_count < max_slots)
@@ -142,9 +115,6 @@ recordMultipleDependencies(const ObjectAddress *depender,
* Record the dependency. Note we don't bother to check for duplicate
* dependencies; there's no harm in them.
*/
- memset(slot[slot_stored_count]->tts_isnull, false,
- slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
-
slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
@@ -152,10 +122,9 @@ recordMultipleDependencies(const ObjectAddress *depender,
slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
- if (version)
- slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjversion - 1] = CStringGetTextDatum(version);
- else
- slot[slot_stored_count]->tts_isnull[Anum_pg_depend_refobjversion - 1] = true;
+
+ memset(slot[slot_stored_count]->tts_isnull, false,
+ slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
ExecStoreVirtualTuple(slot[slot_stored_count]);
slot_stored_count++;
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index dc9d28a32c5..da65584476b 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -15,7 +15,6 @@
#include "postgres.h"
#include "access/htup_details.h"
-#include "access/relation.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
@@ -521,74 +520,6 @@ TypeCreate(Oid newTypeOid,
}
/*
- * Get a list of all distinct collations that the given type depends on.
- */
-List *
-GetTypeCollations(Oid typeoid)
-{
- List *result = NIL;
- HeapTuple tuple;
- Form_pg_type typeTup;
-
- tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeoid));
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for type %u", typeoid);
- typeTup = (Form_pg_type) GETSTRUCT(tuple);
-
- /*
- * If the type has a typcollation attribute, report that and we're done.
- * Otherwise, it could be a container type that we should recurse into.
- */
- if (OidIsValid(typeTup->typcollation))
- result = list_make1_oid(typeTup->typcollation);
- else if (typeTup->typtype == TYPTYPE_COMPOSITE)
- {
- Relation rel = relation_open(typeTup->typrelid, AccessShareLock);
- TupleDesc desc = RelationGetDescr(rel);
-
- for (int i = 0; i < RelationGetNumberOfAttributes(rel); i++)
- {
- Form_pg_attribute att = TupleDescAttr(desc, i);
-
- if (att->attisdropped)
- continue;
- if (OidIsValid(att->attcollation))
- result = list_append_unique_oid(result, att->attcollation);
- else
- result = list_concat_unique_oid(result,
- GetTypeCollations(att->atttypid));
- }
-
- relation_close(rel, NoLock);
- }
- else if (typeTup->typtype == TYPTYPE_DOMAIN)
- {
- Assert(OidIsValid(typeTup->typbasetype));
- result = GetTypeCollations(typeTup->typbasetype);
- }
- else if (typeTup->typtype == TYPTYPE_RANGE)
- {
- Oid rangecoll = get_range_collation(typeTup->oid);
-
- if (OidIsValid(rangecoll))
- result = list_make1_oid(rangecoll);
- else
- {
- Oid rangeid = get_range_subtype(typeTup->oid);
-
- Assert(OidIsValid(rangeid));
- result = GetTypeCollations(rangeid);
- }
- }
- else if (IsTrueArrayType(typeTup))
- result = GetTypeCollations(typeTup->typelem);
-
- ReleaseSysCache(tuple);
-
- return result;
-}
-
-/*
* GenerateTypeDependencies: build the dependencies needed for a type
*
* Most of what this function needs to know about the type is passed as the
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index b8ec6f57564..ebb0994db32 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -62,12 +62,14 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *lcctypeEl = NULL;
DefElem *providerEl = NULL;
DefElem *deterministicEl = NULL;
+ DefElem *versionEl = NULL;
char *collcollate = NULL;
char *collctype = NULL;
char *collproviderstr = NULL;
bool collisdeterministic = true;
int collencoding = 0;
char collprovider = 0;
+ char *collversion = NULL;
Oid newoid;
ObjectAddress address;
@@ -95,6 +97,8 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
defelp = &providerEl;
else if (strcmp(defel->defname, "deterministic") == 0)
defelp = &deterministicEl;
+ else if (strcmp(defel->defname, "version") == 0)
+ defelp = &versionEl;
else
{
ereport(ERROR,
@@ -163,6 +167,9 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
if (deterministicEl)
collisdeterministic = defGetBoolean(deterministicEl);
+ if (versionEl)
+ collversion = defGetString(versionEl);
+
if (collproviderstr)
{
if (pg_strcasecmp(collproviderstr, "icu") == 0)
@@ -209,6 +216,9 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
}
}
+ if (!collversion)
+ collversion = get_collation_actual_version(collprovider, collcollate);
+
newoid = CollationCreate(collName,
collNamespace,
GetUserId(),
@@ -217,6 +227,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
collencoding,
collcollate,
collctype,
+ collversion,
if_not_exists,
false); /* not quiet */
@@ -267,13 +278,101 @@ IsThereCollationInNamespace(const char *collname, Oid nspOid)
collname, get_namespace_name(nspOid))));
}
+/*
+ * ALTER COLLATION
+ */
+ObjectAddress
+AlterCollation(AlterCollationStmt *stmt)
+{
+ Relation rel;
+ Oid collOid;
+ HeapTuple tup;
+ Form_pg_collation collForm;
+ Datum collversion;
+ bool isnull;
+ char *oldversion;
+ char *newversion;
+ ObjectAddress address;
+
+ rel = table_open(CollationRelationId, RowExclusiveLock);
+ collOid = get_collation_oid(stmt->collname, false);
+
+ if (!pg_collation_ownercheck(collOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_COLLATION,
+ NameListToString(stmt->collname));
+
+ tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collOid));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for collation %u", collOid);
+
+ collForm = (Form_pg_collation) GETSTRUCT(tup);
+ collversion = SysCacheGetAttr(COLLOID, tup, Anum_pg_collation_collversion,
+ &isnull);
+ oldversion = isnull ? NULL : TextDatumGetCString(collversion);
+
+ newversion = get_collation_actual_version(collForm->collprovider, NameStr(collForm->collcollate));
+
+ /* cannot change from NULL to non-NULL or vice versa */
+ if ((!oldversion && newversion) || (oldversion && !newversion))
+ elog(ERROR, "invalid collation version change");
+ else if (oldversion && newversion && strcmp(newversion, oldversion) != 0)
+ {
+ bool nulls[Natts_pg_collation];
+ bool replaces[Natts_pg_collation];
+ Datum values[Natts_pg_collation];
+
+ ereport(NOTICE,
+ (errmsg("changing version from %s to %s",
+ oldversion, newversion)));
+
+ memset(values, 0, sizeof(values));
+ memset(nulls, false, sizeof(nulls));
+ memset(replaces, false, sizeof(replaces));
+
+ values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion);
+ replaces[Anum_pg_collation_collversion - 1] = true;
+
+ tup = heap_modify_tuple(tup, RelationGetDescr(rel),
+ values, nulls, replaces);
+ }
+ else
+ ereport(NOTICE,
+ (errmsg("version has not changed")));
+
+ CatalogTupleUpdate(rel, &tup->t_self, tup);
+
+ InvokeObjectPostAlterHook(CollationRelationId, collOid, 0);
+
+ ObjectAddressSet(address, CollationRelationId, collOid);
+
+ heap_freetuple(tup);
+ table_close(rel, NoLock);
+
+ return address;
+}
+
+
Datum
pg_collation_actual_version(PG_FUNCTION_ARGS)
{
Oid collid = PG_GETARG_OID(0);
+ HeapTuple tp;
+ char *collcollate;
+ char collprovider;
char *version;
- version = get_collation_version_for_oid(collid, true);
+ tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
+ if (!HeapTupleIsValid(tp))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("collation with OID %u does not exist", collid)));
+
+ collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate));
+ collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider;
+
+ ReleaseSysCache(tp);
+
+ version = get_collation_actual_version(collprovider, collcollate);
if (version)
PG_RETURN_TEXT_P(cstring_to_text(version));
@@ -495,6 +594,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
collid = CollationCreate(localebuf, nspid, GetUserId(),
COLLPROVIDER_LIBC, true, enc,
localebuf, localebuf,
+ get_collation_actual_version(COLLPROVIDER_LIBC, localebuf),
true, true);
if (OidIsValid(collid))
{
@@ -555,6 +655,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
collid = CollationCreate(alias, nspid, GetUserId(),
COLLPROVIDER_LIBC, true, enc,
locale, locale,
+ get_collation_actual_version(COLLPROVIDER_LIBC, locale),
true, true);
if (OidIsValid(collid))
{
@@ -616,6 +717,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
nspid, GetUserId(),
COLLPROVIDER_ICU, true, -1,
collcollate, collcollate,
+ get_collation_actual_version(COLLPROVIDER_ICU, collcollate),
true, true);
if (OidIsValid(collid))
{
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index df4768952d5..acae19176c0 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -555,7 +555,7 @@ CreateStatistics(CreateStatsStmt *stmt)
(Node *) stxexprs,
relid,
DEPENDENCY_NORMAL,
- DEPENDENCY_AUTO, false, true);
+ DEPENDENCY_AUTO, false);
/*
* Also add dependencies on namespace and owner. These are required
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 0da61784d7a..3b5d4116839 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -94,7 +94,6 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
-#include "utils/pg_locale.h"
#include "utils/relcache.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
@@ -602,7 +601,6 @@ static void refuseDupeIndexAttach(Relation parentIdx, Relation partIdx,
Relation partitionTbl);
static List *GetParentedForeignKeyRefs(Relation partition);
static void ATDetachCheckNoForeignKeyRefs(Relation partition);
-static void ATExecAlterCollationRefreshVersion(Relation rel, List *coll);
static char GetAttributeCompression(Form_pg_attribute att, char *compression);
@@ -4333,10 +4331,6 @@ AlterTableGetLockLevel(List *cmds)
cmd_lockmode = AccessShareLock;
break;
- case AT_AlterCollationRefreshVersion:
- cmd_lockmode = AccessExclusiveLock;
- break;
-
default: /* oops */
elog(ERROR, "unrecognized alter table type: %d",
(int) cmd->subtype);
@@ -4524,12 +4518,6 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
/* This command never recurses */
pass = AT_PASS_MISC;
break;
- case AT_AlterCollationRefreshVersion: /* ALTER COLLATION ... REFRESH
- * VERSION */
- ATSimplePermissions(rel, ATT_INDEX);
- /* This command never recurses */
- pass = AT_PASS_MISC;
- break;
case AT_SetStorage: /* ALTER COLUMN SET STORAGE */
ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
@@ -5139,11 +5127,6 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
case AT_DetachPartitionFinalize:
ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name);
break;
- case AT_AlterCollationRefreshVersion:
- /* ATPrepCmd ensured it must be an index */
- Assert(rel->rd_rel->relkind == RELKIND_INDEX);
- ATExecAlterCollationRefreshVersion(rel, cmd->object);
- break;
default: /* oops */
elog(ERROR, "unrecognized alter table type: %d",
(int) cmd->subtype);
@@ -18627,20 +18610,6 @@ ATDetachCheckNoForeignKeyRefs(Relation partition)
}
/*
- * ALTER INDEX ... ALTER COLLATION ... REFRESH VERSION
- *
- * Update refobjversion to the current collation version by force. This clears
- * warnings about version mismatches without the need to run REINDEX,
- * potentially hiding corruption due to ordering changes.
- */
-static void
-ATExecAlterCollationRefreshVersion(Relation rel, List *coll)
-{
- index_update_collation_versions(rel->rd_id, get_collation_oid(coll, false));
- CacheInvalidateRelcache(rel);
-}
-
-/*
* resolve column compression specification to compression method.
*/
static char
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 632cc31a045..f5a7760740f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3347,7 +3347,6 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
- COPY_NODE_FIELD(object);
COPY_SCALAR_FIELD(num);
COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
@@ -3357,6 +3356,16 @@ _copyAlterTableCmd(const AlterTableCmd *from)
return newnode;
}
+static AlterCollationStmt *
+_copyAlterCollationStmt(const AlterCollationStmt *from)
+{
+ AlterCollationStmt *newnode = makeNode(AlterCollationStmt);
+
+ COPY_NODE_FIELD(collname);
+
+ return newnode;
+}
+
static AlterDomainStmt *
_copyAlterDomainStmt(const AlterDomainStmt *from)
{
@@ -5369,6 +5378,9 @@ copyObjectImpl(const void *from)
case T_AlterTableCmd:
retval = _copyAlterTableCmd(from);
break;
+ case T_AlterCollationStmt:
+ retval = _copyAlterCollationStmt(from);
+ break;
case T_AlterDomainStmt:
retval = _copyAlterDomainStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index a410a29a178..ce76d093dda 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1141,6 +1141,14 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
}
static bool
+_equalAlterCollationStmt(const AlterCollationStmt *a, const AlterCollationStmt *b)
+{
+ COMPARE_NODE_FIELD(collname);
+
+ return true;
+}
+
+static bool
_equalAlterDomainStmt(const AlterDomainStmt *a, const AlterDomainStmt *b)
{
COMPARE_SCALAR_FIELD(subtype);
@@ -3362,6 +3370,9 @@ equal(const void *a, const void *b)
case T_AlterTableCmd:
retval = _equalAlterTableCmd(a, b);
break;
+ case T_AlterCollationStmt:
+ retval = _equalAlterCollationStmt(a, b);
+ break;
case T_AlterDomainStmt:
retval = _equalAlterDomainStmt(a, b);
break;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 295ce114506..c5194fdbbf2 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -27,7 +27,6 @@
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
-#include "catalog/index.h"
#include "catalog/pg_am.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic_ext.h"
@@ -199,14 +198,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
indexRelation = index_open(indexoid, lmode);
index = indexRelation->rd_index;
- /* Warn if any dependent collations' versions have moved. */
- if (!IsSystemRelation(relation) &&
- !indexRelation->rd_version_checked)
- {
- index_check_collation_versions(indexoid);
- indexRelation->rd_version_checked = true;
- }
-
/*
* Ignore invalid indexes, since they can't safely be used for
* queries. Note that this is OK because the data structure we
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b4ab4014c87..aaf1a51f685 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -263,7 +263,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
}
%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
- AlterEventTrigStmt
+ AlterEventTrigStmt AlterCollationStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt
@@ -902,6 +902,7 @@ toplevel_stmt:
stmt:
AlterEventTrigStmt
+ | AlterCollationStmt
| AlterDatabaseStmt
| AlterDatabaseSetStmt
| AlterDefaultPrivilegesStmt
@@ -2682,14 +2683,6 @@ alter_table_cmd:
n->subtype = AT_NoForceRowSecurity;
$$ = (Node *)n;
}
- /* ALTER INDEX <name> ALTER COLLATION ... REFRESH VERSION */
- | ALTER COLLATION any_name REFRESH VERSION_P
- {
- AlterTableCmd *n = makeNode(AlterTableCmd);
- n->subtype = AT_AlterCollationRefreshVersion;
- n->object = $3;
- $$ = (Node *)n;
- }
| alter_generic_options
{
AlterTableCmd *n = makeNode(AlterTableCmd);
@@ -10379,6 +10372,21 @@ drop_option:
/*****************************************************************************
*
+ * ALTER COLLATION
+ *
+ *****************************************************************************/
+
+AlterCollationStmt: ALTER COLLATION any_name REFRESH VERSION_P
+ {
+ AlterCollationStmt *n = makeNode(AlterCollationStmt);
+ n->collname = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
* ALTER SYSTEM
*
* This is used to change configuration parameters persistently.
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 16c6f17e235..1a8fc167733 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1850,6 +1850,10 @@ ProcessUtilitySlow(ParseState *pstate,
address = AlterStatistics((AlterStatsStmt *) parsetree);
break;
+ case T_AlterCollationStmt:
+ address = AlterCollation((AlterCollationStmt *) parsetree);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
@@ -3001,6 +3005,10 @@ CreateCommandTag(Node *parsetree)
tag = CMDTAG_DROP_SUBSCRIPTION;
break;
+ case T_AlterCollationStmt:
+ tag = CMDTAG_ALTER_COLLATION;
+ break;
+
case T_PrepareStmt:
tag = CMDTAG_PREPARE;
break;
@@ -3617,6 +3625,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
+ case T_AlterCollationStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
/* already-planned queries */
case T_PlannedStmt:
{
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index aa4874163f8..eab089f252f 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -57,9 +57,7 @@
#include "access/htup_details.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_control.h"
-#include "catalog/pg_database.h"
#include "mb/pg_wchar.h"
-#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/formatting.h"
#include "utils/hsearch.h"
@@ -127,9 +125,6 @@ static char *IsoLocaleName(const char *); /* MSVC specific */
static void icu_set_collation_attributes(UCollator *collator, const char *loc);
#endif
-static char *get_collation_actual_version(char collprovider,
- const char *collcollate);
-
/*
* pg_perm_setlocale
*
@@ -1488,10 +1483,12 @@ pg_newlocale_from_collation(Oid collid)
/* We haven't computed this yet in this session, so do it */
HeapTuple tp;
Form_pg_collation collform;
- const char *collcollate pg_attribute_unused();
+ const char *collcollate;
const char *collctype pg_attribute_unused();
struct pg_locale_struct result;
pg_locale_t resultp;
+ Datum collversion;
+ bool isnull;
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
if (!HeapTupleIsValid(tp))
@@ -1593,6 +1590,41 @@ pg_newlocale_from_collation(Oid collid)
#endif /* not USE_ICU */
}
+ collversion = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
+ &isnull);
+ if (!isnull)
+ {
+ char *actual_versionstr;
+ char *collversionstr;
+
+ actual_versionstr = get_collation_actual_version(collform->collprovider, collcollate);
+ if (!actual_versionstr)
+ {
+ /*
+ * This could happen when specifying a version in CREATE
+ * COLLATION for a libc locale, or manually creating a mess in
+ * the catalogs.
+ */
+ ereport(ERROR,
+ (errmsg("collation \"%s\" has no actual version, but a version was specified",
+ NameStr(collform->collname))));
+ }
+ collversionstr = TextDatumGetCString(collversion);
+
+ if (strcmp(actual_versionstr, collversionstr) != 0)
+ ereport(WARNING,
+ (errmsg("collation \"%s\" has version mismatch",
+ NameStr(collform->collname)),
+ errdetail("The collation in the database was created using version %s, "
+ "but the operating system provides version %s.",
+ collversionstr, actual_versionstr),
+ errhint("Rebuild all objects affected by this collation and run "
+ "ALTER COLLATION %s REFRESH VERSION, "
+ "or build PostgreSQL with the right library version.",
+ quote_qualified_identifier(get_namespace_name(collform->collnamespace),
+ NameStr(collform->collname)))));
+ }
+
ReleaseSysCache(tp);
/* We'll keep the pg_locale_t structures in TopMemoryContext */
@@ -1609,7 +1641,7 @@ pg_newlocale_from_collation(Oid collid)
* Get provider-specific collation version string for the given collation from
* the operating system/library.
*/
-static char *
+char *
get_collation_actual_version(char collprovider, const char *collcollate)
{
char *collversion = NULL;
@@ -1697,49 +1729,6 @@ get_collation_actual_version(char collprovider, const char *collcollate)
return collversion;
}
-/*
- * Get provider-specific collation version string for a given collation OID.
- * Return NULL if the provider doesn't support versions, or the collation is
- * unversioned (for example "C"). Unknown OIDs result in NULL if missing_ok is
- * true.
- */
-char *
-get_collation_version_for_oid(Oid oid, bool missing_ok)
-{
- HeapTuple tp;
- char *version;
-
- if (oid == DEFAULT_COLLATION_OID)
- {
- Form_pg_database dbform;
-
- tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
- dbform = (Form_pg_database) GETSTRUCT(tp);
- version = get_collation_actual_version(COLLPROVIDER_LIBC,
- NameStr(dbform->datcollate));
- }
- else
- {
- Form_pg_collation collform;
-
- tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(oid));
- if (!HeapTupleIsValid(tp))
- {
- if (missing_ok)
- return NULL;
- elog(ERROR, "cache lookup failed for collation %u", oid);
- }
- collform = (Form_pg_collation) GETSTRUCT(tp);
- version = get_collation_actual_version(collform->collprovider,
- NameStr(collform->collcollate));
- }
-
- ReleaseSysCache(tp);
-
- return version;
-}
#ifdef USE_ICU
/*
diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c
index a575c950790..b5b46d72312 100644
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -13,7 +13,6 @@
#include "catalog/binary_upgrade.h"
#include "catalog/heap.h"
-#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/extension.h"
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 31c8e07f2a7..bd88f6105ba 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -42,7 +42,6 @@
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
-#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
@@ -6069,7 +6068,6 @@ load_relcache_init_file(bool shared)
rel->rd_idattr = NULL;
rel->rd_pubactions = NULL;
rel->rd_statvalid = false;
- rel->rd_version_checked = false;
rel->rd_statlist = NIL;
rel->rd_fkeyvalid = false;
rel->rd_fkeylist = NIL;